18c2ecf20Sopenharmony_ci/********************************************************************** 28c2ecf20Sopenharmony_ci * Author: Cavium, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Contact: support@cavium.com 58c2ecf20Sopenharmony_ci * Please include "LiquidIO" in the subject. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2003-2016 Cavium, Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License, Version 2, as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 158c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 168c2ecf20Sopenharmony_ci * NONINFRINGEMENT. See the GNU General Public License for more details. 178c2ecf20Sopenharmony_ci ***********************************************************************/ 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/pci.h> 218c2ecf20Sopenharmony_ci#include <linux/firmware.h> 228c2ecf20Sopenharmony_ci#include <net/vxlan.h> 238c2ecf20Sopenharmony_ci#include <linux/kthread.h> 248c2ecf20Sopenharmony_ci#include "liquidio_common.h" 258c2ecf20Sopenharmony_ci#include "octeon_droq.h" 268c2ecf20Sopenharmony_ci#include "octeon_iq.h" 278c2ecf20Sopenharmony_ci#include "response_manager.h" 288c2ecf20Sopenharmony_ci#include "octeon_device.h" 298c2ecf20Sopenharmony_ci#include "octeon_nic.h" 308c2ecf20Sopenharmony_ci#include "octeon_main.h" 318c2ecf20Sopenharmony_ci#include "octeon_network.h" 328c2ecf20Sopenharmony_ci#include "cn66xx_regs.h" 338c2ecf20Sopenharmony_ci#include "cn66xx_device.h" 348c2ecf20Sopenharmony_ci#include "cn68xx_device.h" 358c2ecf20Sopenharmony_ci#include "cn23xx_pf_device.h" 368c2ecf20Sopenharmony_ci#include "liquidio_image.h" 378c2ecf20Sopenharmony_ci#include "lio_vf_rep.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ciMODULE_AUTHOR("Cavium Networks, <support@cavium.com>"); 408c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cavium LiquidIO Intelligent Server Adapter Driver"); 418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 428c2ecf20Sopenharmony_ciMODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_210SV_NAME 438c2ecf20Sopenharmony_ci "_" LIO_FW_NAME_TYPE_NIC LIO_FW_NAME_SUFFIX); 448c2ecf20Sopenharmony_ciMODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_210NV_NAME 458c2ecf20Sopenharmony_ci "_" LIO_FW_NAME_TYPE_NIC LIO_FW_NAME_SUFFIX); 468c2ecf20Sopenharmony_ciMODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_410NV_NAME 478c2ecf20Sopenharmony_ci "_" LIO_FW_NAME_TYPE_NIC LIO_FW_NAME_SUFFIX); 488c2ecf20Sopenharmony_ciMODULE_FIRMWARE(LIO_FW_DIR LIO_FW_BASE_NAME LIO_23XX_NAME 498c2ecf20Sopenharmony_ci "_" LIO_FW_NAME_TYPE_NIC LIO_FW_NAME_SUFFIX); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int ddr_timeout = 10000; 528c2ecf20Sopenharmony_cimodule_param(ddr_timeout, int, 0644); 538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ddr_timeout, 548c2ecf20Sopenharmony_ci "Number of milliseconds to wait for DDR initialization. 0 waits for ddr_timeout to be set to non-zero value before starting to check"); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int debug = -1; 598c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "NETIF_MSG debug bits"); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic char fw_type[LIO_MAX_FW_TYPE_LEN] = LIO_FW_NAME_TYPE_AUTO; 638c2ecf20Sopenharmony_cimodule_param_string(fw_type, fw_type, sizeof(fw_type), 0444); 648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fw_type, "Type of firmware to be loaded (default is \"auto\"), which uses firmware in flash, if present, else loads \"nic\"."); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic u32 console_bitmask; 678c2ecf20Sopenharmony_cimodule_param(console_bitmask, int, 0644); 688c2ecf20Sopenharmony_ciMODULE_PARM_DESC(console_bitmask, 698c2ecf20Sopenharmony_ci "Bitmask indicating which consoles have debug output redirected to syslog."); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/** 728c2ecf20Sopenharmony_ci * octeon_console_debug_enabled - determines if a given console has debug enabled. 738c2ecf20Sopenharmony_ci * @console: console to check 748c2ecf20Sopenharmony_ci * Return: 1 = enabled. 0 otherwise 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic int octeon_console_debug_enabled(u32 console) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci return (console_bitmask >> (console)) & 0x1; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Polling interval for determining when NIC application is alive */ 828c2ecf20Sopenharmony_ci#define LIQUIDIO_STARTER_POLL_INTERVAL_MS 100 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* runtime link query interval */ 858c2ecf20Sopenharmony_ci#define LIQUIDIO_LINK_QUERY_INTERVAL_MS 1000 868c2ecf20Sopenharmony_ci/* update localtime to octeon firmware every 60 seconds. 878c2ecf20Sopenharmony_ci * make firmware to use same time reference, so that it will be easy to 888c2ecf20Sopenharmony_ci * correlate firmware logged events/errors with host events, for debugging. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci#define LIO_SYNC_OCTEON_TIME_INTERVAL_MS 60000 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* time to wait for possible in-flight requests in milliseconds */ 938c2ecf20Sopenharmony_ci#define WAIT_INFLIGHT_REQUEST msecs_to_jiffies(1000) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct lio_trusted_vf_ctx { 968c2ecf20Sopenharmony_ci struct completion complete; 978c2ecf20Sopenharmony_ci int status; 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistruct oct_link_status_resp { 1018c2ecf20Sopenharmony_ci u64 rh; 1028c2ecf20Sopenharmony_ci struct oct_link_info link_info; 1038c2ecf20Sopenharmony_ci u64 status; 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct oct_timestamp_resp { 1078c2ecf20Sopenharmony_ci u64 rh; 1088c2ecf20Sopenharmony_ci u64 timestamp; 1098c2ecf20Sopenharmony_ci u64 status; 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define OCT_TIMESTAMP_RESP_SIZE (sizeof(struct oct_timestamp_resp)) 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciunion tx_info { 1158c2ecf20Sopenharmony_ci u64 u64; 1168c2ecf20Sopenharmony_ci struct { 1178c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN_BITFIELD 1188c2ecf20Sopenharmony_ci u16 gso_size; 1198c2ecf20Sopenharmony_ci u16 gso_segs; 1208c2ecf20Sopenharmony_ci u32 reserved; 1218c2ecf20Sopenharmony_ci#else 1228c2ecf20Sopenharmony_ci u32 reserved; 1238c2ecf20Sopenharmony_ci u16 gso_segs; 1248c2ecf20Sopenharmony_ci u16 gso_size; 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci } s; 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Octeon device properties to be used by the NIC module. 1308c2ecf20Sopenharmony_ci * Each octeon device in the system will be represented 1318c2ecf20Sopenharmony_ci * by this structure in the NIC module. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define OCTNIC_GSO_MAX_HEADER_SIZE 128 1358c2ecf20Sopenharmony_ci#define OCTNIC_GSO_MAX_SIZE \ 1368c2ecf20Sopenharmony_ci (CN23XX_DEFAULT_INPUT_JABBER - OCTNIC_GSO_MAX_HEADER_SIZE) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistruct handshake { 1398c2ecf20Sopenharmony_ci struct completion init; 1408c2ecf20Sopenharmony_ci struct completion started; 1418c2ecf20Sopenharmony_ci struct pci_dev *pci_dev; 1428c2ecf20Sopenharmony_ci int init_ok; 1438c2ecf20Sopenharmony_ci int started_ok; 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 1478c2ecf20Sopenharmony_cistatic int liquidio_enable_sriov(struct pci_dev *dev, int num_vfs); 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int octeon_dbg_console_print(struct octeon_device *oct, u32 console_num, 1518c2ecf20Sopenharmony_ci char *prefix, char *suffix); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int octeon_device_init(struct octeon_device *); 1548c2ecf20Sopenharmony_cistatic int liquidio_stop(struct net_device *netdev); 1558c2ecf20Sopenharmony_cistatic void liquidio_remove(struct pci_dev *pdev); 1568c2ecf20Sopenharmony_cistatic int liquidio_probe(struct pci_dev *pdev, 1578c2ecf20Sopenharmony_ci const struct pci_device_id *ent); 1588c2ecf20Sopenharmony_cistatic int liquidio_set_vf_link_state(struct net_device *netdev, int vfidx, 1598c2ecf20Sopenharmony_ci int linkstate); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic struct handshake handshake[MAX_OCTEON_DEVICES]; 1628c2ecf20Sopenharmony_cistatic struct completion first_stage; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void octeon_droq_bh(struct tasklet_struct *t) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int q_no; 1678c2ecf20Sopenharmony_ci int reschedule = 0; 1688c2ecf20Sopenharmony_ci struct octeon_device_priv *oct_priv = from_tasklet(oct_priv, t, 1698c2ecf20Sopenharmony_ci droq_tasklet); 1708c2ecf20Sopenharmony_ci struct octeon_device *oct = oct_priv->dev; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (q_no = 0; q_no < MAX_OCTEON_OUTPUT_QUEUES(oct); q_no++) { 1738c2ecf20Sopenharmony_ci if (!(oct->io_qmask.oq & BIT_ULL(q_no))) 1748c2ecf20Sopenharmony_ci continue; 1758c2ecf20Sopenharmony_ci reschedule |= octeon_droq_process_packets(oct, oct->droq[q_no], 1768c2ecf20Sopenharmony_ci MAX_PACKET_BUDGET); 1778c2ecf20Sopenharmony_ci lio_enable_irq(oct->droq[q_no], NULL); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct) && oct->msix_on) { 1808c2ecf20Sopenharmony_ci /* set time and cnt interrupt thresholds for this DROQ 1818c2ecf20Sopenharmony_ci * for NAPI 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci int adjusted_q_no = q_no + oct->sriov_info.pf_srn; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci octeon_write_csr64( 1868c2ecf20Sopenharmony_ci oct, CN23XX_SLI_OQ_PKT_INT_LEVELS(adjusted_q_no), 1878c2ecf20Sopenharmony_ci 0x5700000040ULL); 1888c2ecf20Sopenharmony_ci octeon_write_csr64( 1898c2ecf20Sopenharmony_ci oct, CN23XX_SLI_OQ_PKTS_SENT(adjusted_q_no), 0); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (reschedule) 1948c2ecf20Sopenharmony_ci tasklet_schedule(&oct_priv->droq_tasklet); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int lio_wait_for_oq_pkts(struct octeon_device *oct) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct octeon_device_priv *oct_priv = 2008c2ecf20Sopenharmony_ci (struct octeon_device_priv *)oct->priv; 2018c2ecf20Sopenharmony_ci int retry = 100, pkt_cnt = 0, pending_pkts = 0; 2028c2ecf20Sopenharmony_ci int i; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci do { 2058c2ecf20Sopenharmony_ci pending_pkts = 0; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) { 2088c2ecf20Sopenharmony_ci if (!(oct->io_qmask.oq & BIT_ULL(i))) 2098c2ecf20Sopenharmony_ci continue; 2108c2ecf20Sopenharmony_ci pkt_cnt += octeon_droq_check_hw_for_pkts(oct->droq[i]); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci if (pkt_cnt > 0) { 2138c2ecf20Sopenharmony_ci pending_pkts += pkt_cnt; 2148c2ecf20Sopenharmony_ci tasklet_schedule(&oct_priv->droq_tasklet); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci pkt_cnt = 0; 2178c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci } while (retry-- && pending_pkts); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return pkt_cnt; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/** 2258c2ecf20Sopenharmony_ci * force_io_queues_off - Forces all IO queues off on a given device 2268c2ecf20Sopenharmony_ci * @oct: Pointer to Octeon device 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic void force_io_queues_off(struct octeon_device *oct) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci if ((oct->chip_id == OCTEON_CN66XX) || 2318c2ecf20Sopenharmony_ci (oct->chip_id == OCTEON_CN68XX)) { 2328c2ecf20Sopenharmony_ci /* Reset the Enable bits for Input Queues. */ 2338c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, 0); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* Reset the Enable bits for Output Queues. */ 2368c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, 0); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/** 2418c2ecf20Sopenharmony_ci * pcierror_quiesce_device - Cause device to go quiet so it can be safely removed/reset/etc 2428c2ecf20Sopenharmony_ci * @oct: Pointer to Octeon device 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic inline void pcierror_quiesce_device(struct octeon_device *oct) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci int i; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Disable the input and output queues now. No more packets will 2498c2ecf20Sopenharmony_ci * arrive from Octeon, but we should wait for all packet processing 2508c2ecf20Sopenharmony_ci * to finish. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci force_io_queues_off(oct); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* To allow for in-flight requests */ 2558c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(WAIT_INFLIGHT_REQUEST); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (wait_for_pending_requests(oct)) 2588c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "There were pending requests\n"); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Force all requests waiting to be fetched by OCTEON to complete. */ 2618c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { 2628c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!(oct->io_qmask.iq & BIT_ULL(i))) 2658c2ecf20Sopenharmony_ci continue; 2668c2ecf20Sopenharmony_ci iq = oct->instr_queue[i]; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (atomic_read(&iq->instr_pending)) { 2698c2ecf20Sopenharmony_ci spin_lock_bh(&iq->lock); 2708c2ecf20Sopenharmony_ci iq->fill_cnt = 0; 2718c2ecf20Sopenharmony_ci iq->octeon_read_index = iq->host_write_index; 2728c2ecf20Sopenharmony_ci iq->stats.instr_processed += 2738c2ecf20Sopenharmony_ci atomic_read(&iq->instr_pending); 2748c2ecf20Sopenharmony_ci lio_process_iq_request_list(oct, iq, 0); 2758c2ecf20Sopenharmony_ci spin_unlock_bh(&iq->lock); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Force all pending ordered list requests to time out. */ 2808c2ecf20Sopenharmony_ci lio_process_ordered_list(oct, 1); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* We do not need to wait for output queue packets to be processed. */ 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/** 2868c2ecf20Sopenharmony_ci * cleanup_aer_uncorrect_error_status - Cleanup PCI AER uncorrectable error status 2878c2ecf20Sopenharmony_ci * @dev: Pointer to PCI device 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_cistatic void cleanup_aer_uncorrect_error_status(struct pci_dev *dev) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci int pos = 0x100; 2928c2ecf20Sopenharmony_ci u32 status, mask; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci pr_info("%s :\n", __func__); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); 2978c2ecf20Sopenharmony_ci pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); 2988c2ecf20Sopenharmony_ci if (dev->error_state == pci_channel_io_normal) 2998c2ecf20Sopenharmony_ci status &= ~mask; /* Clear corresponding nonfatal bits */ 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci status &= mask; /* Clear corresponding fatal bits */ 3028c2ecf20Sopenharmony_ci pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * stop_pci_io - Stop all PCI IO to a given device 3078c2ecf20Sopenharmony_ci * @oct: Pointer to Octeon device 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic void stop_pci_io(struct octeon_device *oct) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci /* No more instructions will be forwarded. */ 3128c2ecf20Sopenharmony_ci atomic_set(&oct->status, OCT_DEV_IN_RESET); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci pci_disable_device(oct->pci_dev); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Disable interrupts */ 3178c2ecf20Sopenharmony_ci oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci pcierror_quiesce_device(oct); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Release the interrupt line */ 3228c2ecf20Sopenharmony_ci free_irq(oct->pci_dev->irq, oct); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (oct->flags & LIO_FLAG_MSI_ENABLED) 3258c2ecf20Sopenharmony_ci pci_disable_msi(oct->pci_dev); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Device state is now %s\n", 3288c2ecf20Sopenharmony_ci lio_get_state_string(&oct->status)); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* making it a common function for all OCTEON models */ 3318c2ecf20Sopenharmony_ci cleanup_aer_uncorrect_error_status(oct->pci_dev); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/** 3358c2ecf20Sopenharmony_ci * liquidio_pcie_error_detected - called when PCI error is detected 3368c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 3378c2ecf20Sopenharmony_ci * @state: The current pci connection state 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting 3408c2ecf20Sopenharmony_ci * this device has been detected. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_cistatic pci_ers_result_t liquidio_pcie_error_detected(struct pci_dev *pdev, 3438c2ecf20Sopenharmony_ci pci_channel_state_t state) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct octeon_device *oct = pci_get_drvdata(pdev); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Non-correctable Non-fatal errors */ 3488c2ecf20Sopenharmony_ci if (state == pci_channel_io_normal) { 3498c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Non-correctable non-fatal error reported:\n"); 3508c2ecf20Sopenharmony_ci cleanup_aer_uncorrect_error_status(oct->pci_dev); 3518c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_CAN_RECOVER; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Non-correctable Fatal errors */ 3558c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Non-correctable FATAL reported by PCI AER driver\n"); 3568c2ecf20Sopenharmony_ci stop_pci_io(oct); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Always return a DISCONNECT. There is no support for recovery but only 3598c2ecf20Sopenharmony_ci * for a clean shutdown. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci/** 3658c2ecf20Sopenharmony_ci * liquidio_pcie_mmio_enabled - mmio handler 3668c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_cistatic pci_ers_result_t liquidio_pcie_mmio_enabled(struct pci_dev __maybe_unused *pdev) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci /* We should never hit this since we never ask for a reset for a Fatal 3718c2ecf20Sopenharmony_ci * Error. We always return DISCONNECT in io_error above. 3728c2ecf20Sopenharmony_ci * But play safe and return RECOVERED for now. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci/** 3788c2ecf20Sopenharmony_ci * liquidio_pcie_slot_reset - called after the pci bus has been reset. 3798c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 3808c2ecf20Sopenharmony_ci * 3818c2ecf20Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot. Implementation 3828c2ecf20Sopenharmony_ci * resembles the first-half of the octeon_resume routine. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_cistatic pci_ers_result_t liquidio_pcie_slot_reset(struct pci_dev __maybe_unused *pdev) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci /* We should never hit this since we never ask for a reset for a Fatal 3878c2ecf20Sopenharmony_ci * Error. We always return DISCONNECT in io_error above. 3888c2ecf20Sopenharmony_ci * But play safe and return RECOVERED for now. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci/** 3948c2ecf20Sopenharmony_ci * liquidio_pcie_resume - called when traffic can start flowing again. 3958c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci * This callback is called when the error recovery driver tells us that 3988c2ecf20Sopenharmony_ci * its OK to resume normal operation. Implementation resembles the 3998c2ecf20Sopenharmony_ci * second-half of the octeon_resume routine. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_cistatic void liquidio_pcie_resume(struct pci_dev __maybe_unused *pdev) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci /* Nothing to be done here. */ 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci#define liquidio_suspend NULL 4078c2ecf20Sopenharmony_ci#define liquidio_resume NULL 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* For PCI-E Advanced Error Recovery (AER) Interface */ 4108c2ecf20Sopenharmony_cistatic const struct pci_error_handlers liquidio_err_handler = { 4118c2ecf20Sopenharmony_ci .error_detected = liquidio_pcie_error_detected, 4128c2ecf20Sopenharmony_ci .mmio_enabled = liquidio_pcie_mmio_enabled, 4138c2ecf20Sopenharmony_ci .slot_reset = liquidio_pcie_slot_reset, 4148c2ecf20Sopenharmony_ci .resume = liquidio_pcie_resume, 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic const struct pci_device_id liquidio_pci_tbl[] = { 4188c2ecf20Sopenharmony_ci { /* 68xx */ 4198c2ecf20Sopenharmony_ci PCI_VENDOR_ID_CAVIUM, 0x91, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 4208c2ecf20Sopenharmony_ci }, 4218c2ecf20Sopenharmony_ci { /* 66xx */ 4228c2ecf20Sopenharmony_ci PCI_VENDOR_ID_CAVIUM, 0x92, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 4238c2ecf20Sopenharmony_ci }, 4248c2ecf20Sopenharmony_ci { /* 23xx pf */ 4258c2ecf20Sopenharmony_ci PCI_VENDOR_ID_CAVIUM, 0x9702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 4268c2ecf20Sopenharmony_ci }, 4278c2ecf20Sopenharmony_ci { 4288c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, liquidio_pci_tbl); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(liquidio_pm_ops, liquidio_suspend, liquidio_resume); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic struct pci_driver liquidio_pci_driver = { 4368c2ecf20Sopenharmony_ci .name = "LiquidIO", 4378c2ecf20Sopenharmony_ci .id_table = liquidio_pci_tbl, 4388c2ecf20Sopenharmony_ci .probe = liquidio_probe, 4398c2ecf20Sopenharmony_ci .remove = liquidio_remove, 4408c2ecf20Sopenharmony_ci .err_handler = &liquidio_err_handler, /* For AER */ 4418c2ecf20Sopenharmony_ci .driver.pm = &liquidio_pm_ops, 4428c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 4438c2ecf20Sopenharmony_ci .sriov_configure = liquidio_enable_sriov, 4448c2ecf20Sopenharmony_ci#endif 4458c2ecf20Sopenharmony_ci}; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/** 4488c2ecf20Sopenharmony_ci * liquidio_init_pci - register PCI driver 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_cistatic int liquidio_init_pci(void) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci return pci_register_driver(&liquidio_pci_driver); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/** 4568c2ecf20Sopenharmony_ci * liquidio_deinit_pci - unregister PCI driver 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_cistatic void liquidio_deinit_pci(void) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci pci_unregister_driver(&liquidio_pci_driver); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci/** 4648c2ecf20Sopenharmony_ci * check_txq_status - Check Tx queue status, and take appropriate action 4658c2ecf20Sopenharmony_ci * @lio: per-network private data 4668c2ecf20Sopenharmony_ci * Return: 0 if full, number of queues woken up otherwise 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_cistatic inline int check_txq_status(struct lio *lio) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci int numqs = lio->netdev->real_num_tx_queues; 4718c2ecf20Sopenharmony_ci int ret_val = 0; 4728c2ecf20Sopenharmony_ci int q, iq; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* check each sub-queue state */ 4758c2ecf20Sopenharmony_ci for (q = 0; q < numqs; q++) { 4768c2ecf20Sopenharmony_ci iq = lio->linfo.txpciq[q % 4778c2ecf20Sopenharmony_ci lio->oct_dev->num_iqs].s.q_no; 4788c2ecf20Sopenharmony_ci if (octnet_iq_is_full(lio->oct_dev, iq)) 4798c2ecf20Sopenharmony_ci continue; 4808c2ecf20Sopenharmony_ci if (__netif_subqueue_stopped(lio->netdev, q)) { 4818c2ecf20Sopenharmony_ci netif_wake_subqueue(lio->netdev, q); 4828c2ecf20Sopenharmony_ci INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq, 4838c2ecf20Sopenharmony_ci tx_restart, 1); 4848c2ecf20Sopenharmony_ci ret_val++; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return ret_val; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci/** 4928c2ecf20Sopenharmony_ci * print_link_info - Print link information 4938c2ecf20Sopenharmony_ci * @netdev: network device 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_cistatic void print_link_info(struct net_device *netdev) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (!ifstate_check(lio, LIO_IFSTATE_RESETTING) && 5008c2ecf20Sopenharmony_ci ifstate_check(lio, LIO_IFSTATE_REGISTERED)) { 5018c2ecf20Sopenharmony_ci struct oct_link_info *linfo = &lio->linfo; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (linfo->link.s.link_up) { 5048c2ecf20Sopenharmony_ci netif_info(lio, link, lio->netdev, "%d Mbps %s Duplex UP\n", 5058c2ecf20Sopenharmony_ci linfo->link.s.speed, 5068c2ecf20Sopenharmony_ci (linfo->link.s.duplex) ? "Full" : "Half"); 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci netif_info(lio, link, lio->netdev, "Link Down\n"); 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/** 5148c2ecf20Sopenharmony_ci * octnet_link_status_change - Routine to notify MTU change 5158c2ecf20Sopenharmony_ci * @work: work_struct data structure 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_cistatic void octnet_link_status_change(struct work_struct *work) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct cavium_wk *wk = (struct cavium_wk *)work; 5208c2ecf20Sopenharmony_ci struct lio *lio = (struct lio *)wk->ctxptr; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* lio->linfo.link.s.mtu always contains max MTU of the lio interface. 5238c2ecf20Sopenharmony_ci * this API is invoked only when new max-MTU of the interface is 5248c2ecf20Sopenharmony_ci * less than current MTU. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci rtnl_lock(); 5278c2ecf20Sopenharmony_ci dev_set_mtu(lio->netdev, lio->linfo.link.s.mtu); 5288c2ecf20Sopenharmony_ci rtnl_unlock(); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/** 5328c2ecf20Sopenharmony_ci * setup_link_status_change_wq - Sets up the mtu status change work 5338c2ecf20Sopenharmony_ci * @netdev: network device 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistatic inline int setup_link_status_change_wq(struct net_device *netdev) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 5388c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci lio->link_status_wq.wq = alloc_workqueue("link-status", 5418c2ecf20Sopenharmony_ci WQ_MEM_RECLAIM, 0); 5428c2ecf20Sopenharmony_ci if (!lio->link_status_wq.wq) { 5438c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "unable to create cavium link status wq\n"); 5448c2ecf20Sopenharmony_ci return -1; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&lio->link_status_wq.wk.work, 5478c2ecf20Sopenharmony_ci octnet_link_status_change); 5488c2ecf20Sopenharmony_ci lio->link_status_wq.wk.ctxptr = lio; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic inline void cleanup_link_status_change_wq(struct net_device *netdev) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (lio->link_status_wq.wq) { 5588c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&lio->link_status_wq.wk.work); 5598c2ecf20Sopenharmony_ci destroy_workqueue(lio->link_status_wq.wq); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci/** 5648c2ecf20Sopenharmony_ci * update_link_status - Update link status 5658c2ecf20Sopenharmony_ci * @netdev: network device 5668c2ecf20Sopenharmony_ci * @ls: link status structure 5678c2ecf20Sopenharmony_ci * 5688c2ecf20Sopenharmony_ci * Called on receipt of a link status response from the core application to 5698c2ecf20Sopenharmony_ci * update each interface's link status. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_cistatic inline void update_link_status(struct net_device *netdev, 5728c2ecf20Sopenharmony_ci union oct_link_status *ls) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 5758c2ecf20Sopenharmony_ci int changed = (lio->linfo.link.u64 != ls->u64); 5768c2ecf20Sopenharmony_ci int current_max_mtu = lio->linfo.link.s.mtu; 5778c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "%s: lio->linfo.link.u64=%llx, ls->u64=%llx\n", 5808c2ecf20Sopenharmony_ci __func__, lio->linfo.link.u64, ls->u64); 5818c2ecf20Sopenharmony_ci lio->linfo.link.u64 = ls->u64; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if ((lio->intf_open) && (changed)) { 5848c2ecf20Sopenharmony_ci print_link_info(netdev); 5858c2ecf20Sopenharmony_ci lio->link_changes++; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (lio->linfo.link.s.link_up) { 5888c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "%s: link_up", __func__); 5898c2ecf20Sopenharmony_ci netif_carrier_on(netdev); 5908c2ecf20Sopenharmony_ci wake_txqs(netdev); 5918c2ecf20Sopenharmony_ci } else { 5928c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "%s: link_off", __func__); 5938c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 5948c2ecf20Sopenharmony_ci stop_txqs(netdev); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci if (lio->linfo.link.s.mtu != current_max_mtu) { 5978c2ecf20Sopenharmony_ci netif_info(lio, probe, lio->netdev, "Max MTU changed from %d to %d\n", 5988c2ecf20Sopenharmony_ci current_max_mtu, lio->linfo.link.s.mtu); 5998c2ecf20Sopenharmony_ci netdev->max_mtu = lio->linfo.link.s.mtu; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci if (lio->linfo.link.s.mtu < netdev->mtu) { 6028c2ecf20Sopenharmony_ci dev_warn(&oct->pci_dev->dev, 6038c2ecf20Sopenharmony_ci "Current MTU is higher than new max MTU; Reducing the current mtu from %d to %d\n", 6048c2ecf20Sopenharmony_ci netdev->mtu, lio->linfo.link.s.mtu); 6058c2ecf20Sopenharmony_ci queue_delayed_work(lio->link_status_wq.wq, 6068c2ecf20Sopenharmony_ci &lio->link_status_wq.wk.work, 0); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/** 6128c2ecf20Sopenharmony_ci * lio_sync_octeon_time - send latest localtime to octeon firmware so that 6138c2ecf20Sopenharmony_ci * firmware will correct it's time, in case there is a time skew 6148c2ecf20Sopenharmony_ci * 6158c2ecf20Sopenharmony_ci * @work: work scheduled to send time update to octeon firmware 6168c2ecf20Sopenharmony_ci **/ 6178c2ecf20Sopenharmony_cistatic void lio_sync_octeon_time(struct work_struct *work) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci struct cavium_wk *wk = (struct cavium_wk *)work; 6208c2ecf20Sopenharmony_ci struct lio *lio = (struct lio *)wk->ctxptr; 6218c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 6228c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 6238c2ecf20Sopenharmony_ci struct timespec64 ts; 6248c2ecf20Sopenharmony_ci struct lio_time *lt; 6258c2ecf20Sopenharmony_ci int ret; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci sc = octeon_alloc_soft_command(oct, sizeof(struct lio_time), 16, 0); 6288c2ecf20Sopenharmony_ci if (!sc) { 6298c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 6308c2ecf20Sopenharmony_ci "Failed to sync time to octeon: soft command allocation failed\n"); 6318c2ecf20Sopenharmony_ci return; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci lt = (struct lio_time *)sc->virtdptr; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* Get time of the day */ 6378c2ecf20Sopenharmony_ci ktime_get_real_ts64(&ts); 6388c2ecf20Sopenharmony_ci lt->sec = ts.tv_sec; 6398c2ecf20Sopenharmony_ci lt->nsec = ts.tv_nsec; 6408c2ecf20Sopenharmony_ci octeon_swap_8B_data((u64 *)lt, (sizeof(struct lio_time)) / 8); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci sc->iq_no = lio->linfo.txpciq[0].s.q_no; 6438c2ecf20Sopenharmony_ci octeon_prepare_soft_command(oct, sc, OPCODE_NIC, 6448c2ecf20Sopenharmony_ci OPCODE_NIC_SYNC_OCTEON_TIME, 0, 0, 0); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci init_completion(&sc->complete); 6478c2ecf20Sopenharmony_ci sc->sc_status = OCTEON_REQUEST_PENDING; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci ret = octeon_send_soft_command(oct, sc); 6508c2ecf20Sopenharmony_ci if (ret == IQ_SEND_FAILED) { 6518c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 6528c2ecf20Sopenharmony_ci "Failed to sync time to octeon: failed to send soft command\n"); 6538c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 6548c2ecf20Sopenharmony_ci } else { 6558c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci queue_delayed_work(lio->sync_octeon_time_wq.wq, 6598c2ecf20Sopenharmony_ci &lio->sync_octeon_time_wq.wk.work, 6608c2ecf20Sopenharmony_ci msecs_to_jiffies(LIO_SYNC_OCTEON_TIME_INTERVAL_MS)); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/** 6648c2ecf20Sopenharmony_ci * setup_sync_octeon_time_wq - prepare work to periodically update local time to octeon firmware 6658c2ecf20Sopenharmony_ci * 6668c2ecf20Sopenharmony_ci * @netdev: network device which should send time update to firmware 6678c2ecf20Sopenharmony_ci **/ 6688c2ecf20Sopenharmony_cistatic inline int setup_sync_octeon_time_wq(struct net_device *netdev) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 6718c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci lio->sync_octeon_time_wq.wq = 6748c2ecf20Sopenharmony_ci alloc_workqueue("update-octeon-time", WQ_MEM_RECLAIM, 0); 6758c2ecf20Sopenharmony_ci if (!lio->sync_octeon_time_wq.wq) { 6768c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Unable to create wq to update octeon time\n"); 6778c2ecf20Sopenharmony_ci return -1; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&lio->sync_octeon_time_wq.wk.work, 6808c2ecf20Sopenharmony_ci lio_sync_octeon_time); 6818c2ecf20Sopenharmony_ci lio->sync_octeon_time_wq.wk.ctxptr = lio; 6828c2ecf20Sopenharmony_ci queue_delayed_work(lio->sync_octeon_time_wq.wq, 6838c2ecf20Sopenharmony_ci &lio->sync_octeon_time_wq.wk.work, 6848c2ecf20Sopenharmony_ci msecs_to_jiffies(LIO_SYNC_OCTEON_TIME_INTERVAL_MS)); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return 0; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/** 6908c2ecf20Sopenharmony_ci * cleanup_sync_octeon_time_wq - destroy wq 6918c2ecf20Sopenharmony_ci * 6928c2ecf20Sopenharmony_ci * @netdev: network device which should send time update to firmware 6938c2ecf20Sopenharmony_ci * 6948c2ecf20Sopenharmony_ci * Stop scheduling and destroy the work created to periodically update local 6958c2ecf20Sopenharmony_ci * time to octeon firmware. 6968c2ecf20Sopenharmony_ci **/ 6978c2ecf20Sopenharmony_cistatic inline void cleanup_sync_octeon_time_wq(struct net_device *netdev) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 7008c2ecf20Sopenharmony_ci struct cavium_wq *time_wq = &lio->sync_octeon_time_wq; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (time_wq->wq) { 7038c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&time_wq->wk.work); 7048c2ecf20Sopenharmony_ci destroy_workqueue(time_wq->wq); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic struct octeon_device *get_other_octeon_device(struct octeon_device *oct) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct octeon_device *other_oct; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci other_oct = lio_get_device(oct->octeon_id + 1); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (other_oct && other_oct->pci_dev) { 7158c2ecf20Sopenharmony_ci int oct_busnum, other_oct_busnum; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci oct_busnum = oct->pci_dev->bus->number; 7188c2ecf20Sopenharmony_ci other_oct_busnum = other_oct->pci_dev->bus->number; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (oct_busnum == other_oct_busnum) { 7218c2ecf20Sopenharmony_ci int oct_slot, other_oct_slot; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci oct_slot = PCI_SLOT(oct->pci_dev->devfn); 7248c2ecf20Sopenharmony_ci other_oct_slot = PCI_SLOT(other_oct->pci_dev->devfn); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (oct_slot == other_oct_slot) 7278c2ecf20Sopenharmony_ci return other_oct; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return NULL; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic void disable_all_vf_links(struct octeon_device *oct) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct net_device *netdev; 7378c2ecf20Sopenharmony_ci int max_vfs, vf, i; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (!oct) 7408c2ecf20Sopenharmony_ci return; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci max_vfs = oct->sriov_info.max_vfs; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci for (i = 0; i < oct->ifcount; i++) { 7458c2ecf20Sopenharmony_ci netdev = oct->props[i].netdev; 7468c2ecf20Sopenharmony_ci if (!netdev) 7478c2ecf20Sopenharmony_ci continue; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci for (vf = 0; vf < max_vfs; vf++) 7508c2ecf20Sopenharmony_ci liquidio_set_vf_link_state(netdev, vf, 7518c2ecf20Sopenharmony_ci IFLA_VF_LINK_STATE_DISABLE); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int liquidio_watchdog(void *param) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci bool err_msg_was_printed[LIO_MAX_CORES]; 7588c2ecf20Sopenharmony_ci u16 mask_of_crashed_or_stuck_cores = 0; 7598c2ecf20Sopenharmony_ci bool all_vf_links_are_disabled = false; 7608c2ecf20Sopenharmony_ci struct octeon_device *oct = param; 7618c2ecf20Sopenharmony_ci struct octeon_device *other_oct; 7628c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULE_UNLOAD 7638c2ecf20Sopenharmony_ci long refcount, vfs_referencing_pf; 7648c2ecf20Sopenharmony_ci u64 vfs_mask1, vfs_mask2; 7658c2ecf20Sopenharmony_ci#endif 7668c2ecf20Sopenharmony_ci int core; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci memset(err_msg_was_printed, 0, sizeof(err_msg_was_printed)); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 7718c2ecf20Sopenharmony_ci /* sleep for a couple of seconds so that we don't hog the CPU */ 7728c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 7738c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(2000)); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci mask_of_crashed_or_stuck_cores = 7768c2ecf20Sopenharmony_ci (u16)octeon_read_csr64(oct, CN23XX_SLI_SCRATCH2); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (!mask_of_crashed_or_stuck_cores) 7798c2ecf20Sopenharmony_ci continue; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci WRITE_ONCE(oct->cores_crashed, true); 7828c2ecf20Sopenharmony_ci other_oct = get_other_octeon_device(oct); 7838c2ecf20Sopenharmony_ci if (other_oct) 7848c2ecf20Sopenharmony_ci WRITE_ONCE(other_oct->cores_crashed, true); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci for (core = 0; core < LIO_MAX_CORES; core++) { 7878c2ecf20Sopenharmony_ci bool core_crashed_or_got_stuck; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci core_crashed_or_got_stuck = 7908c2ecf20Sopenharmony_ci (mask_of_crashed_or_stuck_cores 7918c2ecf20Sopenharmony_ci >> core) & 1; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (core_crashed_or_got_stuck && 7948c2ecf20Sopenharmony_ci !err_msg_was_printed[core]) { 7958c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 7968c2ecf20Sopenharmony_ci "ERROR: Octeon core %d crashed or got stuck! See oct-fwdump for details.\n", 7978c2ecf20Sopenharmony_ci core); 7988c2ecf20Sopenharmony_ci err_msg_was_printed[core] = true; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (all_vf_links_are_disabled) 8038c2ecf20Sopenharmony_ci continue; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci disable_all_vf_links(oct); 8068c2ecf20Sopenharmony_ci disable_all_vf_links(other_oct); 8078c2ecf20Sopenharmony_ci all_vf_links_are_disabled = true; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULE_UNLOAD 8108c2ecf20Sopenharmony_ci vfs_mask1 = READ_ONCE(oct->sriov_info.vf_drv_loaded_mask); 8118c2ecf20Sopenharmony_ci vfs_mask2 = READ_ONCE(other_oct->sriov_info.vf_drv_loaded_mask); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci vfs_referencing_pf = hweight64(vfs_mask1); 8148c2ecf20Sopenharmony_ci vfs_referencing_pf += hweight64(vfs_mask2); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci refcount = module_refcount(THIS_MODULE); 8178c2ecf20Sopenharmony_ci if (refcount >= vfs_referencing_pf) { 8188c2ecf20Sopenharmony_ci while (vfs_referencing_pf) { 8198c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 8208c2ecf20Sopenharmony_ci vfs_referencing_pf--; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci#endif 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return 0; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci/** 8308c2ecf20Sopenharmony_ci * liquidio_probe - PCI probe handler 8318c2ecf20Sopenharmony_ci * @pdev: PCI device structure 8328c2ecf20Sopenharmony_ci * @ent: unused 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_cistatic int 8358c2ecf20Sopenharmony_ciliquidio_probe(struct pci_dev *pdev, const struct pci_device_id __maybe_unused *ent) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct octeon_device *oct_dev = NULL; 8388c2ecf20Sopenharmony_ci struct handshake *hs; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci oct_dev = octeon_allocate_device(pdev->device, 8418c2ecf20Sopenharmony_ci sizeof(struct octeon_device_priv)); 8428c2ecf20Sopenharmony_ci if (!oct_dev) { 8438c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to allocate device\n"); 8448c2ecf20Sopenharmony_ci return -ENOMEM; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (pdev->device == OCTEON_CN23XX_PF_VID) 8488c2ecf20Sopenharmony_ci oct_dev->msix_on = LIO_FLAG_MSIX_ENABLED; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Enable PTP for 6XXX Device */ 8518c2ecf20Sopenharmony_ci if (((pdev->device == OCTEON_CN66XX) || 8528c2ecf20Sopenharmony_ci (pdev->device == OCTEON_CN68XX))) 8538c2ecf20Sopenharmony_ci oct_dev->ptp_enable = true; 8548c2ecf20Sopenharmony_ci else 8558c2ecf20Sopenharmony_ci oct_dev->ptp_enable = false; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Initializing device %x:%x.\n", 8588c2ecf20Sopenharmony_ci (u32)pdev->vendor, (u32)pdev->device); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Assign octeon_device for this device to the private data area. */ 8618c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, oct_dev); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* set linux specific device pointer */ 8648c2ecf20Sopenharmony_ci oct_dev->pci_dev = (void *)pdev; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci oct_dev->subsystem_id = pdev->subsystem_vendor | 8678c2ecf20Sopenharmony_ci (pdev->subsystem_device << 16); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci hs = &handshake[oct_dev->octeon_id]; 8708c2ecf20Sopenharmony_ci init_completion(&hs->init); 8718c2ecf20Sopenharmony_ci init_completion(&hs->started); 8728c2ecf20Sopenharmony_ci hs->pci_dev = pdev; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (oct_dev->octeon_id == 0) 8758c2ecf20Sopenharmony_ci /* first LiquidIO NIC is detected */ 8768c2ecf20Sopenharmony_ci complete(&first_stage); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (octeon_device_init(oct_dev)) { 8798c2ecf20Sopenharmony_ci complete(&hs->init); 8808c2ecf20Sopenharmony_ci liquidio_remove(pdev); 8818c2ecf20Sopenharmony_ci return -ENOMEM; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct_dev)) { 8858c2ecf20Sopenharmony_ci u8 bus, device, function; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (atomic_read(oct_dev->adapter_refcount) == 1) { 8888c2ecf20Sopenharmony_ci /* Each NIC gets one watchdog kernel thread. The first 8898c2ecf20Sopenharmony_ci * PF (of each NIC) that gets pci_driver->probe()'d 8908c2ecf20Sopenharmony_ci * creates that thread. 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci bus = pdev->bus->number; 8938c2ecf20Sopenharmony_ci device = PCI_SLOT(pdev->devfn); 8948c2ecf20Sopenharmony_ci function = PCI_FUNC(pdev->devfn); 8958c2ecf20Sopenharmony_ci oct_dev->watchdog_task = kthread_create( 8968c2ecf20Sopenharmony_ci liquidio_watchdog, oct_dev, 8978c2ecf20Sopenharmony_ci "liowd/%02hhx:%02hhx.%hhx", bus, device, function); 8988c2ecf20Sopenharmony_ci if (!IS_ERR(oct_dev->watchdog_task)) { 8998c2ecf20Sopenharmony_ci wake_up_process(oct_dev->watchdog_task); 9008c2ecf20Sopenharmony_ci } else { 9018c2ecf20Sopenharmony_ci oct_dev->watchdog_task = NULL; 9028c2ecf20Sopenharmony_ci dev_err(&oct_dev->pci_dev->dev, 9038c2ecf20Sopenharmony_ci "failed to create kernel_thread\n"); 9048c2ecf20Sopenharmony_ci liquidio_remove(pdev); 9058c2ecf20Sopenharmony_ci return -1; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci oct_dev->rx_pause = 1; 9118c2ecf20Sopenharmony_ci oct_dev->tx_pause = 1; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci dev_dbg(&oct_dev->pci_dev->dev, "Device is ready\n"); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return 0; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic bool fw_type_is_auto(void) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci return strncmp(fw_type, LIO_FW_NAME_TYPE_AUTO, 9218c2ecf20Sopenharmony_ci sizeof(LIO_FW_NAME_TYPE_AUTO)) == 0; 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci/** 9258c2ecf20Sopenharmony_ci * octeon_pci_flr - PCI FLR for each Octeon device. 9268c2ecf20Sopenharmony_ci * @oct: octeon device 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_cistatic void octeon_pci_flr(struct octeon_device *oct) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci int rc; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci pci_save_state(oct->pci_dev); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci pci_cfg_access_lock(oct->pci_dev); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* Quiesce the device completely */ 9378c2ecf20Sopenharmony_ci pci_write_config_word(oct->pci_dev, PCI_COMMAND, 9388c2ecf20Sopenharmony_ci PCI_COMMAND_INTX_DISABLE); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci rc = __pci_reset_function_locked(oct->pci_dev); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (rc != 0) 9438c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Error %d resetting PCI function %d\n", 9448c2ecf20Sopenharmony_ci rc, oct->pf_num); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci pci_cfg_access_unlock(oct->pci_dev); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci pci_restore_state(oct->pci_dev); 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci/** 9528c2ecf20Sopenharmony_ci * octeon_destroy_resources - Destroy resources associated with octeon device 9538c2ecf20Sopenharmony_ci * @oct: octeon device 9548c2ecf20Sopenharmony_ci */ 9558c2ecf20Sopenharmony_cistatic void octeon_destroy_resources(struct octeon_device *oct) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci int i, refcount; 9588c2ecf20Sopenharmony_ci struct msix_entry *msix_entries; 9598c2ecf20Sopenharmony_ci struct octeon_device_priv *oct_priv = 9608c2ecf20Sopenharmony_ci (struct octeon_device_priv *)oct->priv; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci struct handshake *hs; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci switch (atomic_read(&oct->status)) { 9658c2ecf20Sopenharmony_ci case OCT_DEV_RUNNING: 9668c2ecf20Sopenharmony_ci case OCT_DEV_CORE_OK: 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* No more instructions will be forwarded. */ 9698c2ecf20Sopenharmony_ci atomic_set(&oct->status, OCT_DEV_IN_RESET); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci oct->app_mode = CVM_DRV_INVALID_APP; 9728c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Device state is now %s\n", 9738c2ecf20Sopenharmony_ci lio_get_state_string(&oct->status)); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(HZ / 10); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci fallthrough; 9788c2ecf20Sopenharmony_ci case OCT_DEV_HOST_OK: 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci case OCT_DEV_CONSOLE_INIT_DONE: 9818c2ecf20Sopenharmony_ci /* Remove any consoles */ 9828c2ecf20Sopenharmony_ci octeon_remove_consoles(oct); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci fallthrough; 9858c2ecf20Sopenharmony_ci case OCT_DEV_IO_QUEUES_DONE: 9868c2ecf20Sopenharmony_ci if (lio_wait_for_instr_fetch(oct)) 9878c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n"); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (wait_for_pending_requests(oct)) 9908c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "There were pending requests\n"); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* Disable the input and output queues now. No more packets will 9938c2ecf20Sopenharmony_ci * arrive from Octeon, but we should wait for all packet 9948c2ecf20Sopenharmony_ci * processing to finish. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci oct->fn_list.disable_io_queues(oct); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (lio_wait_for_oq_pkts(oct)) 9998c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "OQ had pending packets\n"); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Force all requests waiting to be fetched by OCTEON to 10028c2ecf20Sopenharmony_ci * complete. 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { 10058c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (!(oct->io_qmask.iq & BIT_ULL(i))) 10088c2ecf20Sopenharmony_ci continue; 10098c2ecf20Sopenharmony_ci iq = oct->instr_queue[i]; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (atomic_read(&iq->instr_pending)) { 10128c2ecf20Sopenharmony_ci spin_lock_bh(&iq->lock); 10138c2ecf20Sopenharmony_ci iq->fill_cnt = 0; 10148c2ecf20Sopenharmony_ci iq->octeon_read_index = iq->host_write_index; 10158c2ecf20Sopenharmony_ci iq->stats.instr_processed += 10168c2ecf20Sopenharmony_ci atomic_read(&iq->instr_pending); 10178c2ecf20Sopenharmony_ci lio_process_iq_request_list(oct, iq, 0); 10188c2ecf20Sopenharmony_ci spin_unlock_bh(&iq->lock); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci lio_process_ordered_list(oct, 1); 10238c2ecf20Sopenharmony_ci octeon_free_sc_done_list(oct); 10248c2ecf20Sopenharmony_ci octeon_free_sc_zombie_list(oct); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci fallthrough; 10278c2ecf20Sopenharmony_ci case OCT_DEV_INTR_SET_DONE: 10288c2ecf20Sopenharmony_ci /* Disable interrupts */ 10298c2ecf20Sopenharmony_ci oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (oct->msix_on) { 10328c2ecf20Sopenharmony_ci msix_entries = (struct msix_entry *)oct->msix_entries; 10338c2ecf20Sopenharmony_ci for (i = 0; i < oct->num_msix_irqs - 1; i++) { 10348c2ecf20Sopenharmony_ci if (oct->ioq_vector[i].vector) { 10358c2ecf20Sopenharmony_ci /* clear the affinity_cpumask */ 10368c2ecf20Sopenharmony_ci irq_set_affinity_hint( 10378c2ecf20Sopenharmony_ci msix_entries[i].vector, 10388c2ecf20Sopenharmony_ci NULL); 10398c2ecf20Sopenharmony_ci free_irq(msix_entries[i].vector, 10408c2ecf20Sopenharmony_ci &oct->ioq_vector[i]); 10418c2ecf20Sopenharmony_ci oct->ioq_vector[i].vector = 0; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci /* non-iov vector's argument is oct struct */ 10458c2ecf20Sopenharmony_ci free_irq(msix_entries[i].vector, oct); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci pci_disable_msix(oct->pci_dev); 10488c2ecf20Sopenharmony_ci kfree(oct->msix_entries); 10498c2ecf20Sopenharmony_ci oct->msix_entries = NULL; 10508c2ecf20Sopenharmony_ci } else { 10518c2ecf20Sopenharmony_ci /* Release the interrupt line */ 10528c2ecf20Sopenharmony_ci free_irq(oct->pci_dev->irq, oct); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (oct->flags & LIO_FLAG_MSI_ENABLED) 10558c2ecf20Sopenharmony_ci pci_disable_msi(oct->pci_dev); 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci kfree(oct->irq_name_storage); 10598c2ecf20Sopenharmony_ci oct->irq_name_storage = NULL; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci fallthrough; 10628c2ecf20Sopenharmony_ci case OCT_DEV_MSIX_ALLOC_VECTOR_DONE: 10638c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 10648c2ecf20Sopenharmony_ci octeon_free_ioq_vector(oct); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci fallthrough; 10678c2ecf20Sopenharmony_ci case OCT_DEV_MBOX_SETUP_DONE: 10688c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 10698c2ecf20Sopenharmony_ci oct->fn_list.free_mbox(oct); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci fallthrough; 10728c2ecf20Sopenharmony_ci case OCT_DEV_IN_RESET: 10738c2ecf20Sopenharmony_ci case OCT_DEV_DROQ_INIT_DONE: 10748c2ecf20Sopenharmony_ci /* Wait for any pending operations */ 10758c2ecf20Sopenharmony_ci mdelay(100); 10768c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) { 10778c2ecf20Sopenharmony_ci if (!(oct->io_qmask.oq & BIT_ULL(i))) 10788c2ecf20Sopenharmony_ci continue; 10798c2ecf20Sopenharmony_ci octeon_delete_droq(oct, i); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* Force any pending handshakes to complete */ 10838c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_DEVICES; i++) { 10848c2ecf20Sopenharmony_ci hs = &handshake[i]; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (hs->pci_dev) { 10878c2ecf20Sopenharmony_ci handshake[oct->octeon_id].init_ok = 0; 10888c2ecf20Sopenharmony_ci complete(&handshake[oct->octeon_id].init); 10898c2ecf20Sopenharmony_ci handshake[oct->octeon_id].started_ok = 0; 10908c2ecf20Sopenharmony_ci complete(&handshake[oct->octeon_id].started); 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci fallthrough; 10958c2ecf20Sopenharmony_ci case OCT_DEV_RESP_LIST_INIT_DONE: 10968c2ecf20Sopenharmony_ci octeon_delete_response_list(oct); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci fallthrough; 10998c2ecf20Sopenharmony_ci case OCT_DEV_INSTR_QUEUE_INIT_DONE: 11008c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { 11018c2ecf20Sopenharmony_ci if (!(oct->io_qmask.iq & BIT_ULL(i))) 11028c2ecf20Sopenharmony_ci continue; 11038c2ecf20Sopenharmony_ci octeon_delete_instr_queue(oct, i); 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 11068c2ecf20Sopenharmony_ci if (oct->sriov_info.sriov_enabled) 11078c2ecf20Sopenharmony_ci pci_disable_sriov(oct->pci_dev); 11088c2ecf20Sopenharmony_ci#endif 11098c2ecf20Sopenharmony_ci fallthrough; 11108c2ecf20Sopenharmony_ci case OCT_DEV_SC_BUFF_POOL_INIT_DONE: 11118c2ecf20Sopenharmony_ci octeon_free_sc_buffer_pool(oct); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci fallthrough; 11148c2ecf20Sopenharmony_ci case OCT_DEV_DISPATCH_INIT_DONE: 11158c2ecf20Sopenharmony_ci octeon_delete_dispatch_list(oct); 11168c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&oct->nic_poll_work.work); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci fallthrough; 11198c2ecf20Sopenharmony_ci case OCT_DEV_PCI_MAP_DONE: 11208c2ecf20Sopenharmony_ci refcount = octeon_deregister_device(oct); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* Soft reset the octeon device before exiting. 11238c2ecf20Sopenharmony_ci * However, if fw was loaded from card (i.e. autoboot), 11248c2ecf20Sopenharmony_ci * perform an FLR instead. 11258c2ecf20Sopenharmony_ci * Implementation note: only soft-reset the device 11268c2ecf20Sopenharmony_ci * if it is a CN6XXX OR the LAST CN23XX device. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci if (atomic_read(oct->adapter_fw_state) == FW_IS_PRELOADED) 11298c2ecf20Sopenharmony_ci octeon_pci_flr(oct); 11308c2ecf20Sopenharmony_ci else if (OCTEON_CN6XXX(oct) || !refcount) 11318c2ecf20Sopenharmony_ci oct->fn_list.soft_reset(oct); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci octeon_unmap_pci_barx(oct, 0); 11348c2ecf20Sopenharmony_ci octeon_unmap_pci_barx(oct, 1); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci fallthrough; 11378c2ecf20Sopenharmony_ci case OCT_DEV_PCI_ENABLE_DONE: 11388c2ecf20Sopenharmony_ci pci_clear_master(oct->pci_dev); 11398c2ecf20Sopenharmony_ci /* Disable the device, releasing the PCI INT */ 11408c2ecf20Sopenharmony_ci pci_disable_device(oct->pci_dev); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci fallthrough; 11438c2ecf20Sopenharmony_ci case OCT_DEV_BEGIN_STATE: 11448c2ecf20Sopenharmony_ci /* Nothing to be done here either */ 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci } /* end switch (oct->status) */ 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci tasklet_kill(&oct_priv->droq_tasklet); 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci/** 11528c2ecf20Sopenharmony_ci * send_rx_ctrl_cmd - Send Rx control command 11538c2ecf20Sopenharmony_ci * @lio: per-network private data 11548c2ecf20Sopenharmony_ci * @start_stop: whether to start or stop 11558c2ecf20Sopenharmony_ci */ 11568c2ecf20Sopenharmony_cistatic int send_rx_ctrl_cmd(struct lio *lio, int start_stop) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 11598c2ecf20Sopenharmony_ci union octnet_cmd *ncmd; 11608c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; 11618c2ecf20Sopenharmony_ci int retval; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci if (oct->props[lio->ifidx].rx_on == start_stop) 11648c2ecf20Sopenharmony_ci return 0; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *) 11678c2ecf20Sopenharmony_ci octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 11688c2ecf20Sopenharmony_ci 16, 0); 11698c2ecf20Sopenharmony_ci if (!sc) { 11708c2ecf20Sopenharmony_ci netif_info(lio, rx_err, lio->netdev, 11718c2ecf20Sopenharmony_ci "Failed to allocate octeon_soft_command struct\n"); 11728c2ecf20Sopenharmony_ci return -ENOMEM; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci ncmd = (union octnet_cmd *)sc->virtdptr; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci ncmd->u64 = 0; 11788c2ecf20Sopenharmony_ci ncmd->s.cmd = OCTNET_CMD_RX_CTL; 11798c2ecf20Sopenharmony_ci ncmd->s.param1 = start_stop; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3)); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci sc->iq_no = lio->linfo.txpciq[0].s.q_no; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci octeon_prepare_soft_command(oct, sc, OPCODE_NIC, 11868c2ecf20Sopenharmony_ci OPCODE_NIC_CMD, 0, 0, 0); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci init_completion(&sc->complete); 11898c2ecf20Sopenharmony_ci sc->sc_status = OCTEON_REQUEST_PENDING; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci retval = octeon_send_soft_command(oct, sc); 11928c2ecf20Sopenharmony_ci if (retval == IQ_SEND_FAILED) { 11938c2ecf20Sopenharmony_ci netif_info(lio, rx_err, lio->netdev, "Failed to send RX Control message\n"); 11948c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 11958c2ecf20Sopenharmony_ci } else { 11968c2ecf20Sopenharmony_ci /* Sleep on a wait queue till the cond flag indicates that the 11978c2ecf20Sopenharmony_ci * response arrived or timed-out. 11988c2ecf20Sopenharmony_ci */ 11998c2ecf20Sopenharmony_ci retval = wait_for_sc_completion_timeout(oct, sc, 0); 12008c2ecf20Sopenharmony_ci if (retval) 12018c2ecf20Sopenharmony_ci return retval; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci oct->props[lio->ifidx].rx_on = start_stop; 12048c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci return retval; 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci/** 12118c2ecf20Sopenharmony_ci * liquidio_destroy_nic_device - Destroy NIC device interface 12128c2ecf20Sopenharmony_ci * @oct: octeon device 12138c2ecf20Sopenharmony_ci * @ifidx: which interface to destroy 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * Cleanup associated with each interface for an Octeon device when NIC 12168c2ecf20Sopenharmony_ci * module is being unloaded or if initialization fails during load. 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_cistatic void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci struct net_device *netdev = oct->props[ifidx].netdev; 12218c2ecf20Sopenharmony_ci struct octeon_device_priv *oct_priv = 12228c2ecf20Sopenharmony_ci (struct octeon_device_priv *)oct->priv; 12238c2ecf20Sopenharmony_ci struct napi_struct *napi, *n; 12248c2ecf20Sopenharmony_ci struct lio *lio; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (!netdev) { 12278c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s No netdevice ptr for index %d\n", 12288c2ecf20Sopenharmony_ci __func__, ifidx); 12298c2ecf20Sopenharmony_ci return; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci lio = GET_LIO(netdev); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "NIC device cleanup\n"); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci if (atomic_read(&lio->ifstate) & LIO_IFSTATE_RUNNING) 12378c2ecf20Sopenharmony_ci liquidio_stop(netdev); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (oct->props[lio->ifidx].napi_enabled == 1) { 12408c2ecf20Sopenharmony_ci list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) 12418c2ecf20Sopenharmony_ci napi_disable(napi); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci oct->props[lio->ifidx].napi_enabled = 0; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 12468c2ecf20Sopenharmony_ci oct->droq[0]->ops.poll_mode = 0; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* Delete NAPI */ 12508c2ecf20Sopenharmony_ci list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) 12518c2ecf20Sopenharmony_ci netif_napi_del(napi); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci tasklet_enable(&oct_priv->droq_tasklet); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED) 12568c2ecf20Sopenharmony_ci unregister_netdev(netdev); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci cleanup_sync_octeon_time_wq(netdev); 12598c2ecf20Sopenharmony_ci cleanup_link_status_change_wq(netdev); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci cleanup_rx_oom_poll_fn(netdev); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci lio_delete_glists(lio); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci free_netdev(netdev); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci oct->props[ifidx].gmxport = -1; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci oct->props[ifidx].netdev = NULL; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci/** 12738c2ecf20Sopenharmony_ci * liquidio_stop_nic_module - Stop complete NIC functionality 12748c2ecf20Sopenharmony_ci * @oct: octeon device 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_cistatic int liquidio_stop_nic_module(struct octeon_device *oct) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci int i, j; 12798c2ecf20Sopenharmony_ci struct lio *lio; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Stopping network interfaces\n"); 12828c2ecf20Sopenharmony_ci if (!oct->ifcount) { 12838c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Init for Octeon was not completed\n"); 12848c2ecf20Sopenharmony_ci return 1; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci spin_lock_bh(&oct->cmd_resp_wqlock); 12888c2ecf20Sopenharmony_ci oct->cmd_resp_state = OCT_DRV_OFFLINE; 12898c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->cmd_resp_wqlock); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci lio_vf_rep_destroy(oct); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci for (i = 0; i < oct->ifcount; i++) { 12948c2ecf20Sopenharmony_ci lio = GET_LIO(oct->props[i].netdev); 12958c2ecf20Sopenharmony_ci for (j = 0; j < oct->num_oqs; j++) 12968c2ecf20Sopenharmony_ci octeon_unregister_droq_ops(oct, 12978c2ecf20Sopenharmony_ci lio->linfo.rxpciq[j].s.q_no); 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci for (i = 0; i < oct->ifcount; i++) 13018c2ecf20Sopenharmony_ci liquidio_destroy_nic_device(oct, i); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (oct->devlink) { 13048c2ecf20Sopenharmony_ci devlink_unregister(oct->devlink); 13058c2ecf20Sopenharmony_ci devlink_free(oct->devlink); 13068c2ecf20Sopenharmony_ci oct->devlink = NULL; 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Network interfaces stopped\n"); 13108c2ecf20Sopenharmony_ci return 0; 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci/** 13148c2ecf20Sopenharmony_ci * liquidio_remove - Cleans up resources at unload time 13158c2ecf20Sopenharmony_ci * @pdev: PCI device structure 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_cistatic void liquidio_remove(struct pci_dev *pdev) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci struct octeon_device *oct_dev = pci_get_drvdata(pdev); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci dev_dbg(&oct_dev->pci_dev->dev, "Stopping device\n"); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (oct_dev->watchdog_task) 13248c2ecf20Sopenharmony_ci kthread_stop(oct_dev->watchdog_task); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (!oct_dev->octeon_id && 13278c2ecf20Sopenharmony_ci oct_dev->fw_info.app_cap_flags & LIQUIDIO_SWITCHDEV_CAP) 13288c2ecf20Sopenharmony_ci lio_vf_rep_modexit(); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (oct_dev->app_mode && (oct_dev->app_mode == CVM_DRV_NIC_APP)) 13318c2ecf20Sopenharmony_ci liquidio_stop_nic_module(oct_dev); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci /* Reset the octeon device and cleanup all memory allocated for 13348c2ecf20Sopenharmony_ci * the octeon device by driver. 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ci octeon_destroy_resources(oct_dev); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci dev_info(&oct_dev->pci_dev->dev, "Device removed\n"); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* This octeon device has been removed. Update the global 13418c2ecf20Sopenharmony_ci * data structure to reflect this. Free the device structure. 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_ci octeon_free_device_mem(oct_dev); 13448c2ecf20Sopenharmony_ci} 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci/** 13478c2ecf20Sopenharmony_ci * octeon_chip_specific_setup - Identify the Octeon device and to map the BAR address space 13488c2ecf20Sopenharmony_ci * @oct: octeon device 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_cistatic int octeon_chip_specific_setup(struct octeon_device *oct) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci u32 dev_id, rev_id; 13538c2ecf20Sopenharmony_ci int ret = 1; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci pci_read_config_dword(oct->pci_dev, 0, &dev_id); 13568c2ecf20Sopenharmony_ci pci_read_config_dword(oct->pci_dev, 8, &rev_id); 13578c2ecf20Sopenharmony_ci oct->rev_id = rev_id & 0xff; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci switch (dev_id) { 13608c2ecf20Sopenharmony_ci case OCTEON_CN68XX_PCIID: 13618c2ecf20Sopenharmony_ci oct->chip_id = OCTEON_CN68XX; 13628c2ecf20Sopenharmony_ci ret = lio_setup_cn68xx_octeon_device(oct); 13638c2ecf20Sopenharmony_ci break; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci case OCTEON_CN66XX_PCIID: 13668c2ecf20Sopenharmony_ci oct->chip_id = OCTEON_CN66XX; 13678c2ecf20Sopenharmony_ci ret = lio_setup_cn66xx_octeon_device(oct); 13688c2ecf20Sopenharmony_ci break; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci case OCTEON_CN23XX_PCIID_PF: 13718c2ecf20Sopenharmony_ci oct->chip_id = OCTEON_CN23XX_PF_VID; 13728c2ecf20Sopenharmony_ci ret = setup_cn23xx_octeon_pf_device(oct); 13738c2ecf20Sopenharmony_ci if (ret) 13748c2ecf20Sopenharmony_ci break; 13758c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 13768c2ecf20Sopenharmony_ci if (!ret) 13778c2ecf20Sopenharmony_ci pci_sriov_set_totalvfs(oct->pci_dev, 13788c2ecf20Sopenharmony_ci oct->sriov_info.max_vfs); 13798c2ecf20Sopenharmony_ci#endif 13808c2ecf20Sopenharmony_ci break; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci default: 13838c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Unknown device found (dev_id: %x)\n", 13848c2ecf20Sopenharmony_ci dev_id); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci return ret; 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci/** 13918c2ecf20Sopenharmony_ci * octeon_pci_os_setup - PCI initialization for each Octeon device. 13928c2ecf20Sopenharmony_ci * @oct: octeon device 13938c2ecf20Sopenharmony_ci */ 13948c2ecf20Sopenharmony_cistatic int octeon_pci_os_setup(struct octeon_device *oct) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci /* setup PCI stuff first */ 13978c2ecf20Sopenharmony_ci if (pci_enable_device(oct->pci_dev)) { 13988c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "pci_enable_device failed\n"); 13998c2ecf20Sopenharmony_ci return 1; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(&oct->pci_dev->dev, DMA_BIT_MASK(64))) { 14038c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Unexpected DMA device capability\n"); 14048c2ecf20Sopenharmony_ci pci_disable_device(oct->pci_dev); 14058c2ecf20Sopenharmony_ci return 1; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* Enable PCI DMA Master. */ 14098c2ecf20Sopenharmony_ci pci_set_master(oct->pci_dev); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci return 0; 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci/** 14158c2ecf20Sopenharmony_ci * free_netbuf - Unmap and free network buffer 14168c2ecf20Sopenharmony_ci * @buf: buffer 14178c2ecf20Sopenharmony_ci */ 14188c2ecf20Sopenharmony_cistatic void free_netbuf(void *buf) 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci struct sk_buff *skb; 14218c2ecf20Sopenharmony_ci struct octnet_buf_free_info *finfo; 14228c2ecf20Sopenharmony_ci struct lio *lio; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci finfo = (struct octnet_buf_free_info *)buf; 14258c2ecf20Sopenharmony_ci skb = finfo->skb; 14268c2ecf20Sopenharmony_ci lio = finfo->lio; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci dma_unmap_single(&lio->oct_dev->pci_dev->dev, finfo->dptr, skb->len, 14298c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci tx_buffer_free(skb); 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci/** 14358c2ecf20Sopenharmony_ci * free_netsgbuf - Unmap and free gather buffer 14368c2ecf20Sopenharmony_ci * @buf: buffer 14378c2ecf20Sopenharmony_ci */ 14388c2ecf20Sopenharmony_cistatic void free_netsgbuf(void *buf) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci struct octnet_buf_free_info *finfo; 14418c2ecf20Sopenharmony_ci struct sk_buff *skb; 14428c2ecf20Sopenharmony_ci struct lio *lio; 14438c2ecf20Sopenharmony_ci struct octnic_gather *g; 14448c2ecf20Sopenharmony_ci int i, frags, iq; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci finfo = (struct octnet_buf_free_info *)buf; 14478c2ecf20Sopenharmony_ci skb = finfo->skb; 14488c2ecf20Sopenharmony_ci lio = finfo->lio; 14498c2ecf20Sopenharmony_ci g = finfo->g; 14508c2ecf20Sopenharmony_ci frags = skb_shinfo(skb)->nr_frags; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci dma_unmap_single(&lio->oct_dev->pci_dev->dev, 14538c2ecf20Sopenharmony_ci g->sg[0].ptr[0], (skb->len - skb->data_len), 14548c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci i = 1; 14578c2ecf20Sopenharmony_ci while (frags--) { 14588c2ecf20Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci pci_unmap_page((lio->oct_dev)->pci_dev, 14618c2ecf20Sopenharmony_ci g->sg[(i >> 2)].ptr[(i & 3)], 14628c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 14638c2ecf20Sopenharmony_ci i++; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci iq = skb_iq(lio->oct_dev, skb); 14678c2ecf20Sopenharmony_ci spin_lock(&lio->glist_lock[iq]); 14688c2ecf20Sopenharmony_ci list_add_tail(&g->list, &lio->glist[iq]); 14698c2ecf20Sopenharmony_ci spin_unlock(&lio->glist_lock[iq]); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci tx_buffer_free(skb); 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci/** 14758c2ecf20Sopenharmony_ci * free_netsgbuf_with_resp - Unmap and free gather buffer with response 14768c2ecf20Sopenharmony_ci * @buf: buffer 14778c2ecf20Sopenharmony_ci */ 14788c2ecf20Sopenharmony_cistatic void free_netsgbuf_with_resp(void *buf) 14798c2ecf20Sopenharmony_ci{ 14808c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 14818c2ecf20Sopenharmony_ci struct octnet_buf_free_info *finfo; 14828c2ecf20Sopenharmony_ci struct sk_buff *skb; 14838c2ecf20Sopenharmony_ci struct lio *lio; 14848c2ecf20Sopenharmony_ci struct octnic_gather *g; 14858c2ecf20Sopenharmony_ci int i, frags, iq; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *)buf; 14888c2ecf20Sopenharmony_ci skb = (struct sk_buff *)sc->callback_arg; 14898c2ecf20Sopenharmony_ci finfo = (struct octnet_buf_free_info *)&skb->cb; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci lio = finfo->lio; 14928c2ecf20Sopenharmony_ci g = finfo->g; 14938c2ecf20Sopenharmony_ci frags = skb_shinfo(skb)->nr_frags; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci dma_unmap_single(&lio->oct_dev->pci_dev->dev, 14968c2ecf20Sopenharmony_ci g->sg[0].ptr[0], (skb->len - skb->data_len), 14978c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci i = 1; 15008c2ecf20Sopenharmony_ci while (frags--) { 15018c2ecf20Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci pci_unmap_page((lio->oct_dev)->pci_dev, 15048c2ecf20Sopenharmony_ci g->sg[(i >> 2)].ptr[(i & 3)], 15058c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 15068c2ecf20Sopenharmony_ci i++; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci iq = skb_iq(lio->oct_dev, skb); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci spin_lock(&lio->glist_lock[iq]); 15128c2ecf20Sopenharmony_ci list_add_tail(&g->list, &lio->glist[iq]); 15138c2ecf20Sopenharmony_ci spin_unlock(&lio->glist_lock[iq]); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* Don't free the skb yet */ 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci/** 15198c2ecf20Sopenharmony_ci * liquidio_ptp_adjfreq - Adjust ptp frequency 15208c2ecf20Sopenharmony_ci * @ptp: PTP clock info 15218c2ecf20Sopenharmony_ci * @ppb: how much to adjust by, in parts-per-billion 15228c2ecf20Sopenharmony_ci */ 15238c2ecf20Sopenharmony_cistatic int liquidio_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci struct lio *lio = container_of(ptp, struct lio, ptp_info); 15268c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; 15278c2ecf20Sopenharmony_ci u64 comp, delta; 15288c2ecf20Sopenharmony_ci unsigned long flags; 15298c2ecf20Sopenharmony_ci bool neg_adj = false; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (ppb < 0) { 15328c2ecf20Sopenharmony_ci neg_adj = true; 15338c2ecf20Sopenharmony_ci ppb = -ppb; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* The hardware adds the clock compensation value to the 15378c2ecf20Sopenharmony_ci * PTP clock on every coprocessor clock cycle, so we 15388c2ecf20Sopenharmony_ci * compute the delta in terms of coprocessor clocks. 15398c2ecf20Sopenharmony_ci */ 15408c2ecf20Sopenharmony_ci delta = (u64)ppb << 32; 15418c2ecf20Sopenharmony_ci do_div(delta, oct->coproc_clock_rate); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci spin_lock_irqsave(&lio->ptp_lock, flags); 15448c2ecf20Sopenharmony_ci comp = lio_pci_readq(oct, CN6XXX_MIO_PTP_CLOCK_COMP); 15458c2ecf20Sopenharmony_ci if (neg_adj) 15468c2ecf20Sopenharmony_ci comp -= delta; 15478c2ecf20Sopenharmony_ci else 15488c2ecf20Sopenharmony_ci comp += delta; 15498c2ecf20Sopenharmony_ci lio_pci_writeq(oct, comp, CN6XXX_MIO_PTP_CLOCK_COMP); 15508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lio->ptp_lock, flags); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci return 0; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci/** 15568c2ecf20Sopenharmony_ci * liquidio_ptp_adjtime - Adjust ptp time 15578c2ecf20Sopenharmony_ci * @ptp: PTP clock info 15588c2ecf20Sopenharmony_ci * @delta: how much to adjust by, in nanosecs 15598c2ecf20Sopenharmony_ci */ 15608c2ecf20Sopenharmony_cistatic int liquidio_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci unsigned long flags; 15638c2ecf20Sopenharmony_ci struct lio *lio = container_of(ptp, struct lio, ptp_info); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci spin_lock_irqsave(&lio->ptp_lock, flags); 15668c2ecf20Sopenharmony_ci lio->ptp_adjust += delta; 15678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lio->ptp_lock, flags); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci return 0; 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci/** 15738c2ecf20Sopenharmony_ci * liquidio_ptp_gettime - Get hardware clock time, including any adjustment 15748c2ecf20Sopenharmony_ci * @ptp: PTP clock info 15758c2ecf20Sopenharmony_ci * @ts: timespec 15768c2ecf20Sopenharmony_ci */ 15778c2ecf20Sopenharmony_cistatic int liquidio_ptp_gettime(struct ptp_clock_info *ptp, 15788c2ecf20Sopenharmony_ci struct timespec64 *ts) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci u64 ns; 15818c2ecf20Sopenharmony_ci unsigned long flags; 15828c2ecf20Sopenharmony_ci struct lio *lio = container_of(ptp, struct lio, ptp_info); 15838c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci spin_lock_irqsave(&lio->ptp_lock, flags); 15868c2ecf20Sopenharmony_ci ns = lio_pci_readq(oct, CN6XXX_MIO_PTP_CLOCK_HI); 15878c2ecf20Sopenharmony_ci ns += lio->ptp_adjust; 15888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lio->ptp_lock, flags); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci *ts = ns_to_timespec64(ns); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci return 0; 15938c2ecf20Sopenharmony_ci} 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci/** 15968c2ecf20Sopenharmony_ci * liquidio_ptp_settime - Set hardware clock time. Reset adjustment 15978c2ecf20Sopenharmony_ci * @ptp: PTP clock info 15988c2ecf20Sopenharmony_ci * @ts: timespec 15998c2ecf20Sopenharmony_ci */ 16008c2ecf20Sopenharmony_cistatic int liquidio_ptp_settime(struct ptp_clock_info *ptp, 16018c2ecf20Sopenharmony_ci const struct timespec64 *ts) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci u64 ns; 16048c2ecf20Sopenharmony_ci unsigned long flags; 16058c2ecf20Sopenharmony_ci struct lio *lio = container_of(ptp, struct lio, ptp_info); 16068c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci ns = timespec64_to_ns(ts); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci spin_lock_irqsave(&lio->ptp_lock, flags); 16118c2ecf20Sopenharmony_ci lio_pci_writeq(oct, ns, CN6XXX_MIO_PTP_CLOCK_HI); 16128c2ecf20Sopenharmony_ci lio->ptp_adjust = 0; 16138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lio->ptp_lock, flags); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci return 0; 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci/** 16198c2ecf20Sopenharmony_ci * liquidio_ptp_enable - Check if PTP is enabled 16208c2ecf20Sopenharmony_ci * @ptp: PTP clock info 16218c2ecf20Sopenharmony_ci * @rq: request 16228c2ecf20Sopenharmony_ci * @on: is it on 16238c2ecf20Sopenharmony_ci */ 16248c2ecf20Sopenharmony_cistatic int 16258c2ecf20Sopenharmony_ciliquidio_ptp_enable(struct ptp_clock_info __maybe_unused *ptp, 16268c2ecf20Sopenharmony_ci struct ptp_clock_request __maybe_unused *rq, 16278c2ecf20Sopenharmony_ci int __maybe_unused on) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci/** 16338c2ecf20Sopenharmony_ci * oct_ptp_open - Open PTP clock source 16348c2ecf20Sopenharmony_ci * @netdev: network device 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_cistatic void oct_ptp_open(struct net_device *netdev) 16378c2ecf20Sopenharmony_ci{ 16388c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 16398c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci spin_lock_init(&lio->ptp_lock); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci snprintf(lio->ptp_info.name, 16, "%s", netdev->name); 16448c2ecf20Sopenharmony_ci lio->ptp_info.owner = THIS_MODULE; 16458c2ecf20Sopenharmony_ci lio->ptp_info.max_adj = 250000000; 16468c2ecf20Sopenharmony_ci lio->ptp_info.n_alarm = 0; 16478c2ecf20Sopenharmony_ci lio->ptp_info.n_ext_ts = 0; 16488c2ecf20Sopenharmony_ci lio->ptp_info.n_per_out = 0; 16498c2ecf20Sopenharmony_ci lio->ptp_info.pps = 0; 16508c2ecf20Sopenharmony_ci lio->ptp_info.adjfreq = liquidio_ptp_adjfreq; 16518c2ecf20Sopenharmony_ci lio->ptp_info.adjtime = liquidio_ptp_adjtime; 16528c2ecf20Sopenharmony_ci lio->ptp_info.gettime64 = liquidio_ptp_gettime; 16538c2ecf20Sopenharmony_ci lio->ptp_info.settime64 = liquidio_ptp_settime; 16548c2ecf20Sopenharmony_ci lio->ptp_info.enable = liquidio_ptp_enable; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci lio->ptp_adjust = 0; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci lio->ptp_clock = ptp_clock_register(&lio->ptp_info, 16598c2ecf20Sopenharmony_ci &oct->pci_dev->dev); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (IS_ERR(lio->ptp_clock)) 16628c2ecf20Sopenharmony_ci lio->ptp_clock = NULL; 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci/** 16668c2ecf20Sopenharmony_ci * liquidio_ptp_init - Init PTP clock 16678c2ecf20Sopenharmony_ci * @oct: octeon device 16688c2ecf20Sopenharmony_ci */ 16698c2ecf20Sopenharmony_cistatic void liquidio_ptp_init(struct octeon_device *oct) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci u64 clock_comp, cfg; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci clock_comp = (u64)NSEC_PER_SEC << 32; 16748c2ecf20Sopenharmony_ci do_div(clock_comp, oct->coproc_clock_rate); 16758c2ecf20Sopenharmony_ci lio_pci_writeq(oct, clock_comp, CN6XXX_MIO_PTP_CLOCK_COMP); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci /* Enable */ 16788c2ecf20Sopenharmony_ci cfg = lio_pci_readq(oct, CN6XXX_MIO_PTP_CLOCK_CFG); 16798c2ecf20Sopenharmony_ci lio_pci_writeq(oct, cfg | 0x01, CN6XXX_MIO_PTP_CLOCK_CFG); 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci/** 16838c2ecf20Sopenharmony_ci * load_firmware - Load firmware to device 16848c2ecf20Sopenharmony_ci * @oct: octeon device 16858c2ecf20Sopenharmony_ci * 16868c2ecf20Sopenharmony_ci * Maps device to firmware filename, requests firmware, and downloads it 16878c2ecf20Sopenharmony_ci */ 16888c2ecf20Sopenharmony_cistatic int load_firmware(struct octeon_device *oct) 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci int ret = 0; 16918c2ecf20Sopenharmony_ci const struct firmware *fw; 16928c2ecf20Sopenharmony_ci char fw_name[LIO_MAX_FW_FILENAME_LEN]; 16938c2ecf20Sopenharmony_ci char *tmp_fw_type; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (fw_type_is_auto()) { 16968c2ecf20Sopenharmony_ci tmp_fw_type = LIO_FW_NAME_TYPE_NIC; 16978c2ecf20Sopenharmony_ci strncpy(fw_type, tmp_fw_type, sizeof(fw_type)); 16988c2ecf20Sopenharmony_ci } else { 16998c2ecf20Sopenharmony_ci tmp_fw_type = fw_type; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci sprintf(fw_name, "%s%s%s_%s%s", LIO_FW_DIR, LIO_FW_BASE_NAME, 17038c2ecf20Sopenharmony_ci octeon_get_conf(oct)->card_name, tmp_fw_type, 17048c2ecf20Sopenharmony_ci LIO_FW_NAME_SUFFIX); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci ret = request_firmware(&fw, fw_name, &oct->pci_dev->dev); 17078c2ecf20Sopenharmony_ci if (ret) { 17088c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Request firmware failed. Could not find file %s.\n", 17098c2ecf20Sopenharmony_ci fw_name); 17108c2ecf20Sopenharmony_ci release_firmware(fw); 17118c2ecf20Sopenharmony_ci return ret; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci ret = octeon_download_firmware(oct, fw->data, fw->size); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci release_firmware(fw); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return ret; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci/** 17228c2ecf20Sopenharmony_ci * octnet_poll_check_txq_status - Poll routine for checking transmit queue status 17238c2ecf20Sopenharmony_ci * @work: work_struct data structure 17248c2ecf20Sopenharmony_ci */ 17258c2ecf20Sopenharmony_cistatic void octnet_poll_check_txq_status(struct work_struct *work) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci struct cavium_wk *wk = (struct cavium_wk *)work; 17288c2ecf20Sopenharmony_ci struct lio *lio = (struct lio *)wk->ctxptr; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (!ifstate_check(lio, LIO_IFSTATE_RUNNING)) 17318c2ecf20Sopenharmony_ci return; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci check_txq_status(lio); 17348c2ecf20Sopenharmony_ci queue_delayed_work(lio->txq_status_wq.wq, 17358c2ecf20Sopenharmony_ci &lio->txq_status_wq.wk.work, msecs_to_jiffies(1)); 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci/** 17398c2ecf20Sopenharmony_ci * setup_tx_poll_fn - Sets up the txq poll check 17408c2ecf20Sopenharmony_ci * @netdev: network device 17418c2ecf20Sopenharmony_ci */ 17428c2ecf20Sopenharmony_cistatic inline int setup_tx_poll_fn(struct net_device *netdev) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 17458c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci lio->txq_status_wq.wq = alloc_workqueue("txq-status", 17488c2ecf20Sopenharmony_ci WQ_MEM_RECLAIM, 0); 17498c2ecf20Sopenharmony_ci if (!lio->txq_status_wq.wq) { 17508c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "unable to create cavium txq status wq\n"); 17518c2ecf20Sopenharmony_ci return -1; 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&lio->txq_status_wq.wk.work, 17548c2ecf20Sopenharmony_ci octnet_poll_check_txq_status); 17558c2ecf20Sopenharmony_ci lio->txq_status_wq.wk.ctxptr = lio; 17568c2ecf20Sopenharmony_ci queue_delayed_work(lio->txq_status_wq.wq, 17578c2ecf20Sopenharmony_ci &lio->txq_status_wq.wk.work, msecs_to_jiffies(1)); 17588c2ecf20Sopenharmony_ci return 0; 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_cistatic inline void cleanup_tx_poll_fn(struct net_device *netdev) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (lio->txq_status_wq.wq) { 17668c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&lio->txq_status_wq.wk.work); 17678c2ecf20Sopenharmony_ci destroy_workqueue(lio->txq_status_wq.wq); 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci/** 17728c2ecf20Sopenharmony_ci * liquidio_open - Net device open for LiquidIO 17738c2ecf20Sopenharmony_ci * @netdev: network device 17748c2ecf20Sopenharmony_ci */ 17758c2ecf20Sopenharmony_cistatic int liquidio_open(struct net_device *netdev) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 17788c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 17798c2ecf20Sopenharmony_ci struct octeon_device_priv *oct_priv = 17808c2ecf20Sopenharmony_ci (struct octeon_device_priv *)oct->priv; 17818c2ecf20Sopenharmony_ci struct napi_struct *napi, *n; 17828c2ecf20Sopenharmony_ci int ret = 0; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (oct->props[lio->ifidx].napi_enabled == 0) { 17858c2ecf20Sopenharmony_ci tasklet_disable(&oct_priv->droq_tasklet); 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) 17888c2ecf20Sopenharmony_ci napi_enable(napi); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci oct->props[lio->ifidx].napi_enabled = 1; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 17938c2ecf20Sopenharmony_ci oct->droq[0]->ops.poll_mode = 1; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (oct->ptp_enable) 17978c2ecf20Sopenharmony_ci oct_ptp_open(netdev); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci ifstate_set(lio, LIO_IFSTATE_RUNNING); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on) { 18028c2ecf20Sopenharmony_ci ret = setup_tx_poll_fn(netdev); 18038c2ecf20Sopenharmony_ci if (ret) 18048c2ecf20Sopenharmony_ci goto err_poll; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci netif_tx_start_all_queues(netdev); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci /* Ready for link status updates */ 18108c2ecf20Sopenharmony_ci lio->intf_open = 1; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci netif_info(lio, ifup, lio->netdev, "Interface Open, ready for traffic\n"); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci /* tell Octeon to start forwarding packets to host */ 18158c2ecf20Sopenharmony_ci ret = send_rx_ctrl_cmd(lio, 1); 18168c2ecf20Sopenharmony_ci if (ret) 18178c2ecf20Sopenharmony_ci goto err_rx_ctrl; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci /* start periodical statistics fetch */ 18208c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&lio->stats_wk.work, lio_fetch_stats); 18218c2ecf20Sopenharmony_ci lio->stats_wk.ctxptr = lio; 18228c2ecf20Sopenharmony_ci schedule_delayed_work(&lio->stats_wk.work, msecs_to_jiffies 18238c2ecf20Sopenharmony_ci (LIQUIDIO_NDEV_STATS_POLL_TIME_MS)); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "%s interface is opened\n", 18268c2ecf20Sopenharmony_ci netdev->name); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci return 0; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_cierr_rx_ctrl: 18318c2ecf20Sopenharmony_ci if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on) 18328c2ecf20Sopenharmony_ci cleanup_tx_poll_fn(netdev); 18338c2ecf20Sopenharmony_cierr_poll: 18348c2ecf20Sopenharmony_ci if (lio->ptp_clock) { 18358c2ecf20Sopenharmony_ci ptp_clock_unregister(lio->ptp_clock); 18368c2ecf20Sopenharmony_ci lio->ptp_clock = NULL; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (oct->props[lio->ifidx].napi_enabled == 1) { 18408c2ecf20Sopenharmony_ci list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) 18418c2ecf20Sopenharmony_ci napi_disable(napi); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci oct->props[lio->ifidx].napi_enabled = 0; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 18468c2ecf20Sopenharmony_ci oct->droq[0]->ops.poll_mode = 0; 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci return ret; 18508c2ecf20Sopenharmony_ci} 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci/** 18538c2ecf20Sopenharmony_ci * liquidio_stop - Net device stop for LiquidIO 18548c2ecf20Sopenharmony_ci * @netdev: network device 18558c2ecf20Sopenharmony_ci */ 18568c2ecf20Sopenharmony_cistatic int liquidio_stop(struct net_device *netdev) 18578c2ecf20Sopenharmony_ci{ 18588c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 18598c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 18608c2ecf20Sopenharmony_ci struct octeon_device_priv *oct_priv = 18618c2ecf20Sopenharmony_ci (struct octeon_device_priv *)oct->priv; 18628c2ecf20Sopenharmony_ci struct napi_struct *napi, *n; 18638c2ecf20Sopenharmony_ci int ret = 0; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci ifstate_reset(lio, LIO_IFSTATE_RUNNING); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci /* Stop any link updates */ 18688c2ecf20Sopenharmony_ci lio->intf_open = 0; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci stop_txqs(netdev); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci /* Inform that netif carrier is down */ 18738c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 18748c2ecf20Sopenharmony_ci netif_tx_disable(netdev); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci lio->linfo.link.s.link_up = 0; 18778c2ecf20Sopenharmony_ci lio->link_changes++; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci /* Tell Octeon that nic interface is down. */ 18808c2ecf20Sopenharmony_ci ret = send_rx_ctrl_cmd(lio, 0); 18818c2ecf20Sopenharmony_ci if (ret) 18828c2ecf20Sopenharmony_ci return ret; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) { 18858c2ecf20Sopenharmony_ci if (!oct->msix_on) 18868c2ecf20Sopenharmony_ci cleanup_tx_poll_fn(netdev); 18878c2ecf20Sopenharmony_ci } else { 18888c2ecf20Sopenharmony_ci cleanup_tx_poll_fn(netdev); 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&lio->stats_wk.work); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci if (lio->ptp_clock) { 18948c2ecf20Sopenharmony_ci ptp_clock_unregister(lio->ptp_clock); 18958c2ecf20Sopenharmony_ci lio->ptp_clock = NULL; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci /* Wait for any pending Rx descriptors */ 18998c2ecf20Sopenharmony_ci if (lio_wait_for_clean_oq(oct)) 19008c2ecf20Sopenharmony_ci netif_info(lio, rx_err, lio->netdev, 19018c2ecf20Sopenharmony_ci "Proceeding with stop interface after partial RX desc processing\n"); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci if (oct->props[lio->ifidx].napi_enabled == 1) { 19048c2ecf20Sopenharmony_ci list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) 19058c2ecf20Sopenharmony_ci napi_disable(napi); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci oct->props[lio->ifidx].napi_enabled = 0; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 19108c2ecf20Sopenharmony_ci oct->droq[0]->ops.poll_mode = 0; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci tasklet_enable(&oct_priv->droq_tasklet); 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci return ret; 19188c2ecf20Sopenharmony_ci} 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci/** 19218c2ecf20Sopenharmony_ci * get_new_flags - Converts a mask based on net device flags 19228c2ecf20Sopenharmony_ci * @netdev: network device 19238c2ecf20Sopenharmony_ci * 19248c2ecf20Sopenharmony_ci * This routine generates a octnet_ifflags mask from the net device flags 19258c2ecf20Sopenharmony_ci * received from the OS. 19268c2ecf20Sopenharmony_ci */ 19278c2ecf20Sopenharmony_cistatic inline enum octnet_ifflags get_new_flags(struct net_device *netdev) 19288c2ecf20Sopenharmony_ci{ 19298c2ecf20Sopenharmony_ci enum octnet_ifflags f = OCTNET_IFFLAG_UNICAST; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (netdev->flags & IFF_PROMISC) 19328c2ecf20Sopenharmony_ci f |= OCTNET_IFFLAG_PROMISC; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (netdev->flags & IFF_ALLMULTI) 19358c2ecf20Sopenharmony_ci f |= OCTNET_IFFLAG_ALLMULTI; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (netdev->flags & IFF_MULTICAST) { 19388c2ecf20Sopenharmony_ci f |= OCTNET_IFFLAG_MULTICAST; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci /* Accept all multicast addresses if there are more than we 19418c2ecf20Sopenharmony_ci * can handle 19428c2ecf20Sopenharmony_ci */ 19438c2ecf20Sopenharmony_ci if (netdev_mc_count(netdev) > MAX_OCTEON_MULTICAST_ADDR) 19448c2ecf20Sopenharmony_ci f |= OCTNET_IFFLAG_ALLMULTI; 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci if (netdev->flags & IFF_BROADCAST) 19488c2ecf20Sopenharmony_ci f |= OCTNET_IFFLAG_BROADCAST; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci return f; 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci/** 19548c2ecf20Sopenharmony_ci * liquidio_set_mcast_list - Net device set_multicast_list 19558c2ecf20Sopenharmony_ci * @netdev: network device 19568c2ecf20Sopenharmony_ci */ 19578c2ecf20Sopenharmony_cistatic void liquidio_set_mcast_list(struct net_device *netdev) 19588c2ecf20Sopenharmony_ci{ 19598c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 19608c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 19618c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 19628c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 19638c2ecf20Sopenharmony_ci u64 *mc; 19648c2ecf20Sopenharmony_ci int ret; 19658c2ecf20Sopenharmony_ci int mc_count = min(netdev_mc_count(netdev), MAX_OCTEON_MULTICAST_ADDR); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci /* Create a ctrl pkt command to be sent to core app. */ 19708c2ecf20Sopenharmony_ci nctrl.ncmd.u64 = 0; 19718c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_SET_MULTI_LIST; 19728c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = get_new_flags(netdev); 19738c2ecf20Sopenharmony_ci nctrl.ncmd.s.param2 = mc_count; 19748c2ecf20Sopenharmony_ci nctrl.ncmd.s.more = mc_count; 19758c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 19768c2ecf20Sopenharmony_ci nctrl.netpndev = (u64)netdev; 19778c2ecf20Sopenharmony_ci nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci /* copy all the addresses into the udd */ 19808c2ecf20Sopenharmony_ci mc = &nctrl.udd[0]; 19818c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 19828c2ecf20Sopenharmony_ci *mc = 0; 19838c2ecf20Sopenharmony_ci memcpy(((u8 *)mc) + 2, ha->addr, ETH_ALEN); 19848c2ecf20Sopenharmony_ci /* no need to swap bytes */ 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (++mc > &nctrl.udd[mc_count]) 19878c2ecf20Sopenharmony_ci break; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci /* Apparently, any activity in this call from the kernel has to 19918c2ecf20Sopenharmony_ci * be atomic. So we won't wait for response. 19928c2ecf20Sopenharmony_ci */ 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); 19958c2ecf20Sopenharmony_ci if (ret) { 19968c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "DEVFLAGS change failed in core (ret: 0x%x)\n", 19978c2ecf20Sopenharmony_ci ret); 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci/** 20028c2ecf20Sopenharmony_ci * liquidio_set_mac - Net device set_mac_address 20038c2ecf20Sopenharmony_ci * @netdev: network device 20048c2ecf20Sopenharmony_ci * @p: pointer to sockaddr 20058c2ecf20Sopenharmony_ci */ 20068c2ecf20Sopenharmony_cistatic int liquidio_set_mac(struct net_device *netdev, void *p) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci int ret = 0; 20098c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 20108c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 20118c2ecf20Sopenharmony_ci struct sockaddr *addr = (struct sockaddr *)p; 20128c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 20158c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci nctrl.ncmd.u64 = 0; 20208c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MACADDR; 20218c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = 0; 20228c2ecf20Sopenharmony_ci nctrl.ncmd.s.more = 1; 20238c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 20248c2ecf20Sopenharmony_ci nctrl.netpndev = (u64)netdev; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci nctrl.udd[0] = 0; 20278c2ecf20Sopenharmony_ci /* The MAC Address is presented in network byte order. */ 20288c2ecf20Sopenharmony_ci memcpy((u8 *)&nctrl.udd[0] + 2, addr->sa_data, ETH_ALEN); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); 20318c2ecf20Sopenharmony_ci if (ret < 0) { 20328c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "MAC Address change failed\n"); 20338c2ecf20Sopenharmony_ci return -ENOMEM; 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (nctrl.sc_status) { 20378c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 20388c2ecf20Sopenharmony_ci "%s: MAC Address change failed. sc return=%x\n", 20398c2ecf20Sopenharmony_ci __func__, nctrl.sc_status); 20408c2ecf20Sopenharmony_ci return -EIO; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); 20448c2ecf20Sopenharmony_ci memcpy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data, ETH_ALEN); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci return 0; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_cistatic void 20508c2ecf20Sopenharmony_ciliquidio_get_stats64(struct net_device *netdev, 20518c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *lstats) 20528c2ecf20Sopenharmony_ci{ 20538c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 20548c2ecf20Sopenharmony_ci struct octeon_device *oct; 20558c2ecf20Sopenharmony_ci u64 pkts = 0, drop = 0, bytes = 0; 20568c2ecf20Sopenharmony_ci struct oct_droq_stats *oq_stats; 20578c2ecf20Sopenharmony_ci struct oct_iq_stats *iq_stats; 20588c2ecf20Sopenharmony_ci int i, iq_no, oq_no; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci oct = lio->oct_dev; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci if (ifstate_check(lio, LIO_IFSTATE_RESETTING)) 20638c2ecf20Sopenharmony_ci return; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci for (i = 0; i < oct->num_iqs; i++) { 20668c2ecf20Sopenharmony_ci iq_no = lio->linfo.txpciq[i].s.q_no; 20678c2ecf20Sopenharmony_ci iq_stats = &oct->instr_queue[iq_no]->stats; 20688c2ecf20Sopenharmony_ci pkts += iq_stats->tx_done; 20698c2ecf20Sopenharmony_ci drop += iq_stats->tx_dropped; 20708c2ecf20Sopenharmony_ci bytes += iq_stats->tx_tot_bytes; 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci lstats->tx_packets = pkts; 20748c2ecf20Sopenharmony_ci lstats->tx_bytes = bytes; 20758c2ecf20Sopenharmony_ci lstats->tx_dropped = drop; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci pkts = 0; 20788c2ecf20Sopenharmony_ci drop = 0; 20798c2ecf20Sopenharmony_ci bytes = 0; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci for (i = 0; i < oct->num_oqs; i++) { 20828c2ecf20Sopenharmony_ci oq_no = lio->linfo.rxpciq[i].s.q_no; 20838c2ecf20Sopenharmony_ci oq_stats = &oct->droq[oq_no]->stats; 20848c2ecf20Sopenharmony_ci pkts += oq_stats->rx_pkts_received; 20858c2ecf20Sopenharmony_ci drop += (oq_stats->rx_dropped + 20868c2ecf20Sopenharmony_ci oq_stats->dropped_nodispatch + 20878c2ecf20Sopenharmony_ci oq_stats->dropped_toomany + 20888c2ecf20Sopenharmony_ci oq_stats->dropped_nomem); 20898c2ecf20Sopenharmony_ci bytes += oq_stats->rx_bytes_received; 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci lstats->rx_bytes = bytes; 20938c2ecf20Sopenharmony_ci lstats->rx_packets = pkts; 20948c2ecf20Sopenharmony_ci lstats->rx_dropped = drop; 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci lstats->multicast = oct->link_stats.fromwire.fw_total_mcast; 20978c2ecf20Sopenharmony_ci lstats->collisions = oct->link_stats.fromhost.total_collisions; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci /* detailed rx_errors: */ 21008c2ecf20Sopenharmony_ci lstats->rx_length_errors = oct->link_stats.fromwire.l2_err; 21018c2ecf20Sopenharmony_ci /* recved pkt with crc error */ 21028c2ecf20Sopenharmony_ci lstats->rx_crc_errors = oct->link_stats.fromwire.fcs_err; 21038c2ecf20Sopenharmony_ci /* recv'd frame alignment error */ 21048c2ecf20Sopenharmony_ci lstats->rx_frame_errors = oct->link_stats.fromwire.frame_err; 21058c2ecf20Sopenharmony_ci /* recv'r fifo overrun */ 21068c2ecf20Sopenharmony_ci lstats->rx_fifo_errors = oct->link_stats.fromwire.fifo_err; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci lstats->rx_errors = lstats->rx_length_errors + lstats->rx_crc_errors + 21098c2ecf20Sopenharmony_ci lstats->rx_frame_errors + lstats->rx_fifo_errors; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci /* detailed tx_errors */ 21128c2ecf20Sopenharmony_ci lstats->tx_aborted_errors = oct->link_stats.fromhost.fw_err_pko; 21138c2ecf20Sopenharmony_ci lstats->tx_carrier_errors = oct->link_stats.fromhost.fw_err_link; 21148c2ecf20Sopenharmony_ci lstats->tx_fifo_errors = oct->link_stats.fromhost.fifo_err; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci lstats->tx_errors = lstats->tx_aborted_errors + 21178c2ecf20Sopenharmony_ci lstats->tx_carrier_errors + 21188c2ecf20Sopenharmony_ci lstats->tx_fifo_errors; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci/** 21228c2ecf20Sopenharmony_ci * hwtstamp_ioctl - Handler for SIOCSHWTSTAMP ioctl 21238c2ecf20Sopenharmony_ci * @netdev: network device 21248c2ecf20Sopenharmony_ci * @ifr: interface request 21258c2ecf20Sopenharmony_ci */ 21268c2ecf20Sopenharmony_cistatic int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr) 21278c2ecf20Sopenharmony_ci{ 21288c2ecf20Sopenharmony_ci struct hwtstamp_config conf; 21298c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci if (copy_from_user(&conf, ifr->ifr_data, sizeof(conf))) 21328c2ecf20Sopenharmony_ci return -EFAULT; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if (conf.flags) 21358c2ecf20Sopenharmony_ci return -EINVAL; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci switch (conf.tx_type) { 21388c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 21398c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 21408c2ecf20Sopenharmony_ci break; 21418c2ecf20Sopenharmony_ci default: 21428c2ecf20Sopenharmony_ci return -ERANGE; 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci switch (conf.rx_filter) { 21468c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 21478c2ecf20Sopenharmony_ci break; 21488c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 21498c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_SOME: 21508c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 21518c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 21528c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 21538c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 21548c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 21558c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 21568c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 21578c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 21588c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 21598c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 21608c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 21618c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 21628c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 21638c2ecf20Sopenharmony_ci conf.rx_filter = HWTSTAMP_FILTER_ALL; 21648c2ecf20Sopenharmony_ci break; 21658c2ecf20Sopenharmony_ci default: 21668c2ecf20Sopenharmony_ci return -ERANGE; 21678c2ecf20Sopenharmony_ci } 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (conf.rx_filter == HWTSTAMP_FILTER_ALL) 21708c2ecf20Sopenharmony_ci ifstate_set(lio, LIO_IFSTATE_RX_TIMESTAMP_ENABLED); 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci else 21738c2ecf20Sopenharmony_ci ifstate_reset(lio, LIO_IFSTATE_RX_TIMESTAMP_ENABLED); 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, &conf, sizeof(conf)) ? -EFAULT : 0; 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci/** 21798c2ecf20Sopenharmony_ci * liquidio_ioctl - ioctl handler 21808c2ecf20Sopenharmony_ci * @netdev: network device 21818c2ecf20Sopenharmony_ci * @ifr: interface request 21828c2ecf20Sopenharmony_ci * @cmd: command 21838c2ecf20Sopenharmony_ci */ 21848c2ecf20Sopenharmony_cistatic int liquidio_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 21858c2ecf20Sopenharmony_ci{ 21868c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci switch (cmd) { 21898c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 21908c2ecf20Sopenharmony_ci if (lio->oct_dev->ptp_enable) 21918c2ecf20Sopenharmony_ci return hwtstamp_ioctl(netdev, ifr); 21928c2ecf20Sopenharmony_ci fallthrough; 21938c2ecf20Sopenharmony_ci default: 21948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci} 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci/** 21998c2ecf20Sopenharmony_ci * handle_timestamp - handle a Tx timestamp response 22008c2ecf20Sopenharmony_ci * @oct: octeon device 22018c2ecf20Sopenharmony_ci * @status: response status 22028c2ecf20Sopenharmony_ci * @buf: pointer to skb 22038c2ecf20Sopenharmony_ci */ 22048c2ecf20Sopenharmony_cistatic void handle_timestamp(struct octeon_device *oct, 22058c2ecf20Sopenharmony_ci u32 status, 22068c2ecf20Sopenharmony_ci void *buf) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci struct octnet_buf_free_info *finfo; 22098c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 22108c2ecf20Sopenharmony_ci struct oct_timestamp_resp *resp; 22118c2ecf20Sopenharmony_ci struct lio *lio; 22128c2ecf20Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *)buf; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci finfo = (struct octnet_buf_free_info *)skb->cb; 22158c2ecf20Sopenharmony_ci lio = finfo->lio; 22168c2ecf20Sopenharmony_ci sc = finfo->sc; 22178c2ecf20Sopenharmony_ci oct = lio->oct_dev; 22188c2ecf20Sopenharmony_ci resp = (struct oct_timestamp_resp *)sc->virtrptr; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (status != OCTEON_REQUEST_DONE) { 22218c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Tx timestamp instruction failed. Status: %llx\n", 22228c2ecf20Sopenharmony_ci CVM_CAST64(status)); 22238c2ecf20Sopenharmony_ci resp->timestamp = 0; 22248c2ecf20Sopenharmony_ci } 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci octeon_swap_8B_data(&resp->timestamp, 1); 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) != 0)) { 22298c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps ts; 22308c2ecf20Sopenharmony_ci u64 ns = resp->timestamp; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci netif_info(lio, tx_done, lio->netdev, 22338c2ecf20Sopenharmony_ci "Got resulting SKBTX_HW_TSTAMP skb=%p ns=%016llu\n", 22348c2ecf20Sopenharmony_ci skb, (unsigned long long)ns); 22358c2ecf20Sopenharmony_ci ts.hwtstamp = ns_to_ktime(ns + lio->ptp_adjust); 22368c2ecf20Sopenharmony_ci skb_tstamp_tx(skb, &ts); 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 22408c2ecf20Sopenharmony_ci tx_buffer_free(skb); 22418c2ecf20Sopenharmony_ci} 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci/** 22448c2ecf20Sopenharmony_ci * send_nic_timestamp_pkt - Send a data packet that will be timestamped 22458c2ecf20Sopenharmony_ci * @oct: octeon device 22468c2ecf20Sopenharmony_ci * @ndata: pointer to network data 22478c2ecf20Sopenharmony_ci * @finfo: pointer to private network data 22488c2ecf20Sopenharmony_ci * @xmit_more: more is coming 22498c2ecf20Sopenharmony_ci */ 22508c2ecf20Sopenharmony_cistatic inline int send_nic_timestamp_pkt(struct octeon_device *oct, 22518c2ecf20Sopenharmony_ci struct octnic_data_pkt *ndata, 22528c2ecf20Sopenharmony_ci struct octnet_buf_free_info *finfo, 22538c2ecf20Sopenharmony_ci int xmit_more) 22548c2ecf20Sopenharmony_ci{ 22558c2ecf20Sopenharmony_ci int retval; 22568c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 22578c2ecf20Sopenharmony_ci struct lio *lio; 22588c2ecf20Sopenharmony_ci int ring_doorbell; 22598c2ecf20Sopenharmony_ci u32 len; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci lio = finfo->lio; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci sc = octeon_alloc_soft_command_resp(oct, &ndata->cmd, 22648c2ecf20Sopenharmony_ci sizeof(struct oct_timestamp_resp)); 22658c2ecf20Sopenharmony_ci finfo->sc = sc; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci if (!sc) { 22688c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "No memory for timestamped data packet\n"); 22698c2ecf20Sopenharmony_ci return IQ_SEND_FAILED; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci if (ndata->reqtype == REQTYPE_NORESP_NET) 22738c2ecf20Sopenharmony_ci ndata->reqtype = REQTYPE_RESP_NET; 22748c2ecf20Sopenharmony_ci else if (ndata->reqtype == REQTYPE_NORESP_NET_SG) 22758c2ecf20Sopenharmony_ci ndata->reqtype = REQTYPE_RESP_NET_SG; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci sc->callback = handle_timestamp; 22788c2ecf20Sopenharmony_ci sc->callback_arg = finfo->skb; 22798c2ecf20Sopenharmony_ci sc->iq_no = ndata->q_no; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 22828c2ecf20Sopenharmony_ci len = (u32)((struct octeon_instr_ih3 *) 22838c2ecf20Sopenharmony_ci (&sc->cmd.cmd3.ih3))->dlengsz; 22848c2ecf20Sopenharmony_ci else 22858c2ecf20Sopenharmony_ci len = (u32)((struct octeon_instr_ih2 *) 22868c2ecf20Sopenharmony_ci (&sc->cmd.cmd2.ih2))->dlengsz; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci ring_doorbell = !xmit_more; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci retval = octeon_send_command(oct, sc->iq_no, ring_doorbell, &sc->cmd, 22918c2ecf20Sopenharmony_ci sc, len, ndata->reqtype); 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci if (retval == IQ_SEND_FAILED) { 22948c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "timestamp data packet failed status: %x\n", 22958c2ecf20Sopenharmony_ci retval); 22968c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 22978c2ecf20Sopenharmony_ci } else { 22988c2ecf20Sopenharmony_ci netif_info(lio, tx_queued, lio->netdev, "Queued timestamp packet\n"); 22998c2ecf20Sopenharmony_ci } 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci return retval; 23028c2ecf20Sopenharmony_ci} 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci/** 23058c2ecf20Sopenharmony_ci * liquidio_xmit - Transmit networks packets to the Octeon interface 23068c2ecf20Sopenharmony_ci * @skb: skbuff struct to be passed to network layer. 23078c2ecf20Sopenharmony_ci * @netdev: pointer to network device 23088c2ecf20Sopenharmony_ci * 23098c2ecf20Sopenharmony_ci * Return: whether the packet was transmitted to the device okay or not 23108c2ecf20Sopenharmony_ci * (NETDEV_TX_OK or NETDEV_TX_BUSY) 23118c2ecf20Sopenharmony_ci */ 23128c2ecf20Sopenharmony_cistatic netdev_tx_t liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) 23138c2ecf20Sopenharmony_ci{ 23148c2ecf20Sopenharmony_ci struct lio *lio; 23158c2ecf20Sopenharmony_ci struct octnet_buf_free_info *finfo; 23168c2ecf20Sopenharmony_ci union octnic_cmd_setup cmdsetup; 23178c2ecf20Sopenharmony_ci struct octnic_data_pkt ndata; 23188c2ecf20Sopenharmony_ci struct octeon_device *oct; 23198c2ecf20Sopenharmony_ci struct oct_iq_stats *stats; 23208c2ecf20Sopenharmony_ci struct octeon_instr_irh *irh; 23218c2ecf20Sopenharmony_ci union tx_info *tx_info; 23228c2ecf20Sopenharmony_ci int status = 0; 23238c2ecf20Sopenharmony_ci int q_idx = 0, iq_no = 0; 23248c2ecf20Sopenharmony_ci int j, xmit_more = 0; 23258c2ecf20Sopenharmony_ci u64 dptr = 0; 23268c2ecf20Sopenharmony_ci u32 tag = 0; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci lio = GET_LIO(netdev); 23298c2ecf20Sopenharmony_ci oct = lio->oct_dev; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci q_idx = skb_iq(oct, skb); 23328c2ecf20Sopenharmony_ci tag = q_idx; 23338c2ecf20Sopenharmony_ci iq_no = lio->linfo.txpciq[q_idx].s.q_no; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci stats = &oct->instr_queue[iq_no]->stats; 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci /* Check for all conditions in which the current packet cannot be 23388c2ecf20Sopenharmony_ci * transmitted. 23398c2ecf20Sopenharmony_ci */ 23408c2ecf20Sopenharmony_ci if (!(atomic_read(&lio->ifstate) & LIO_IFSTATE_RUNNING) || 23418c2ecf20Sopenharmony_ci (!lio->linfo.link.s.link_up) || 23428c2ecf20Sopenharmony_ci (skb->len <= 0)) { 23438c2ecf20Sopenharmony_ci netif_info(lio, tx_err, lio->netdev, 23448c2ecf20Sopenharmony_ci "Transmit failed link_status : %d\n", 23458c2ecf20Sopenharmony_ci lio->linfo.link.s.link_up); 23468c2ecf20Sopenharmony_ci goto lio_xmit_failed; 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci /* Use space in skb->cb to store info used to unmap and 23508c2ecf20Sopenharmony_ci * free the buffers. 23518c2ecf20Sopenharmony_ci */ 23528c2ecf20Sopenharmony_ci finfo = (struct octnet_buf_free_info *)skb->cb; 23538c2ecf20Sopenharmony_ci finfo->lio = lio; 23548c2ecf20Sopenharmony_ci finfo->skb = skb; 23558c2ecf20Sopenharmony_ci finfo->sc = NULL; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci /* Prepare the attributes for the data to be passed to OSI. */ 23588c2ecf20Sopenharmony_ci memset(&ndata, 0, sizeof(struct octnic_data_pkt)); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci ndata.buf = (void *)finfo; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci ndata.q_no = iq_no; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci if (octnet_iq_is_full(oct, ndata.q_no)) { 23658c2ecf20Sopenharmony_ci /* defer sending if queue is full */ 23668c2ecf20Sopenharmony_ci netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n", 23678c2ecf20Sopenharmony_ci ndata.q_no); 23688c2ecf20Sopenharmony_ci stats->tx_iq_busy++; 23698c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci /* pr_info(" XMIT - valid Qs: %d, 1st Q no: %d, cpu: %d, q_no:%d\n", 23738c2ecf20Sopenharmony_ci * lio->linfo.num_txpciq, lio->txq, cpu, ndata.q_no); 23748c2ecf20Sopenharmony_ci */ 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci ndata.datasize = skb->len; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci cmdsetup.u64 = 0; 23798c2ecf20Sopenharmony_ci cmdsetup.s.iq_no = iq_no; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 23828c2ecf20Sopenharmony_ci if (skb->encapsulation) { 23838c2ecf20Sopenharmony_ci cmdsetup.s.tnl_csum = 1; 23848c2ecf20Sopenharmony_ci stats->tx_vxlan++; 23858c2ecf20Sopenharmony_ci } else { 23868c2ecf20Sopenharmony_ci cmdsetup.s.transport_csum = 1; 23878c2ecf20Sopenharmony_ci } 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 23908c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 23918c2ecf20Sopenharmony_ci cmdsetup.s.timestamp = 1; 23928c2ecf20Sopenharmony_ci } 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->nr_frags == 0) { 23958c2ecf20Sopenharmony_ci cmdsetup.s.u.datasize = skb->len; 23968c2ecf20Sopenharmony_ci octnet_prepare_pci_cmd(oct, &ndata.cmd, &cmdsetup, tag); 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci /* Offload checksum calculation for TCP/UDP packets */ 23998c2ecf20Sopenharmony_ci dptr = dma_map_single(&oct->pci_dev->dev, 24008c2ecf20Sopenharmony_ci skb->data, 24018c2ecf20Sopenharmony_ci skb->len, 24028c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 24038c2ecf20Sopenharmony_ci if (dma_mapping_error(&oct->pci_dev->dev, dptr)) { 24048c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s DMA mapping error 1\n", 24058c2ecf20Sopenharmony_ci __func__); 24068c2ecf20Sopenharmony_ci stats->tx_dmamap_fail++; 24078c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 24118c2ecf20Sopenharmony_ci ndata.cmd.cmd3.dptr = dptr; 24128c2ecf20Sopenharmony_ci else 24138c2ecf20Sopenharmony_ci ndata.cmd.cmd2.dptr = dptr; 24148c2ecf20Sopenharmony_ci finfo->dptr = dptr; 24158c2ecf20Sopenharmony_ci ndata.reqtype = REQTYPE_NORESP_NET; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci } else { 24188c2ecf20Sopenharmony_ci int i, frags; 24198c2ecf20Sopenharmony_ci skb_frag_t *frag; 24208c2ecf20Sopenharmony_ci struct octnic_gather *g; 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci spin_lock(&lio->glist_lock[q_idx]); 24238c2ecf20Sopenharmony_ci g = (struct octnic_gather *) 24248c2ecf20Sopenharmony_ci lio_list_delete_head(&lio->glist[q_idx]); 24258c2ecf20Sopenharmony_ci spin_unlock(&lio->glist_lock[q_idx]); 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci if (!g) { 24288c2ecf20Sopenharmony_ci netif_info(lio, tx_err, lio->netdev, 24298c2ecf20Sopenharmony_ci "Transmit scatter gather: glist null!\n"); 24308c2ecf20Sopenharmony_ci goto lio_xmit_failed; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci cmdsetup.s.gather = 1; 24348c2ecf20Sopenharmony_ci cmdsetup.s.u.gatherptrs = (skb_shinfo(skb)->nr_frags + 1); 24358c2ecf20Sopenharmony_ci octnet_prepare_pci_cmd(oct, &ndata.cmd, &cmdsetup, tag); 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci memset(g->sg, 0, g->sg_size); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci g->sg[0].ptr[0] = dma_map_single(&oct->pci_dev->dev, 24408c2ecf20Sopenharmony_ci skb->data, 24418c2ecf20Sopenharmony_ci (skb->len - skb->data_len), 24428c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 24438c2ecf20Sopenharmony_ci if (dma_mapping_error(&oct->pci_dev->dev, g->sg[0].ptr[0])) { 24448c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s DMA mapping error 2\n", 24458c2ecf20Sopenharmony_ci __func__); 24468c2ecf20Sopenharmony_ci stats->tx_dmamap_fail++; 24478c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci add_sg_size(&g->sg[0], (skb->len - skb->data_len), 0); 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci frags = skb_shinfo(skb)->nr_frags; 24528c2ecf20Sopenharmony_ci i = 1; 24538c2ecf20Sopenharmony_ci while (frags--) { 24548c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[i - 1]; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci g->sg[(i >> 2)].ptr[(i & 3)] = 24578c2ecf20Sopenharmony_ci skb_frag_dma_map(&oct->pci_dev->dev, 24588c2ecf20Sopenharmony_ci frag, 0, skb_frag_size(frag), 24598c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci if (dma_mapping_error(&oct->pci_dev->dev, 24628c2ecf20Sopenharmony_ci g->sg[i >> 2].ptr[i & 3])) { 24638c2ecf20Sopenharmony_ci dma_unmap_single(&oct->pci_dev->dev, 24648c2ecf20Sopenharmony_ci g->sg[0].ptr[0], 24658c2ecf20Sopenharmony_ci skb->len - skb->data_len, 24668c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 24678c2ecf20Sopenharmony_ci for (j = 1; j < i; j++) { 24688c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[j - 1]; 24698c2ecf20Sopenharmony_ci dma_unmap_page(&oct->pci_dev->dev, 24708c2ecf20Sopenharmony_ci g->sg[j >> 2].ptr[j & 3], 24718c2ecf20Sopenharmony_ci skb_frag_size(frag), 24728c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s DMA mapping error 3\n", 24758c2ecf20Sopenharmony_ci __func__); 24768c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 24778c2ecf20Sopenharmony_ci } 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci add_sg_size(&g->sg[(i >> 2)], skb_frag_size(frag), 24808c2ecf20Sopenharmony_ci (i & 3)); 24818c2ecf20Sopenharmony_ci i++; 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci dptr = g->sg_dma_ptr; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) 24878c2ecf20Sopenharmony_ci ndata.cmd.cmd3.dptr = dptr; 24888c2ecf20Sopenharmony_ci else 24898c2ecf20Sopenharmony_ci ndata.cmd.cmd2.dptr = dptr; 24908c2ecf20Sopenharmony_ci finfo->dptr = dptr; 24918c2ecf20Sopenharmony_ci finfo->g = g; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci ndata.reqtype = REQTYPE_NORESP_NET_SG; 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct)) { 24978c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&ndata.cmd.cmd3.irh; 24988c2ecf20Sopenharmony_ci tx_info = (union tx_info *)&ndata.cmd.cmd3.ossp[0]; 24998c2ecf20Sopenharmony_ci } else { 25008c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&ndata.cmd.cmd2.irh; 25018c2ecf20Sopenharmony_ci tx_info = (union tx_info *)&ndata.cmd.cmd2.ossp[0]; 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_size) { 25058c2ecf20Sopenharmony_ci tx_info->s.gso_size = skb_shinfo(skb)->gso_size; 25068c2ecf20Sopenharmony_ci tx_info->s.gso_segs = skb_shinfo(skb)->gso_segs; 25078c2ecf20Sopenharmony_ci stats->tx_gso++; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci /* HW insert VLAN tag */ 25118c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 25128c2ecf20Sopenharmony_ci irh->priority = skb_vlan_tag_get(skb) >> 13; 25138c2ecf20Sopenharmony_ci irh->vlan = skb_vlan_tag_get(skb) & 0xfff; 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci xmit_more = netdev_xmit_more(); 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci if (unlikely(cmdsetup.s.timestamp)) 25198c2ecf20Sopenharmony_ci status = send_nic_timestamp_pkt(oct, &ndata, finfo, xmit_more); 25208c2ecf20Sopenharmony_ci else 25218c2ecf20Sopenharmony_ci status = octnet_send_nic_data_pkt(oct, &ndata, xmit_more); 25228c2ecf20Sopenharmony_ci if (status == IQ_SEND_FAILED) 25238c2ecf20Sopenharmony_ci goto lio_xmit_failed; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci netif_info(lio, tx_queued, lio->netdev, "Transmit queued successfully\n"); 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci if (status == IQ_SEND_STOP) 25288c2ecf20Sopenharmony_ci netif_stop_subqueue(netdev, q_idx); 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci netif_trans_update(netdev); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci if (tx_info->s.gso_segs) 25338c2ecf20Sopenharmony_ci stats->tx_done += tx_info->s.gso_segs; 25348c2ecf20Sopenharmony_ci else 25358c2ecf20Sopenharmony_ci stats->tx_done++; 25368c2ecf20Sopenharmony_ci stats->tx_tot_bytes += ndata.datasize; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_cilio_xmit_failed: 25418c2ecf20Sopenharmony_ci stats->tx_dropped++; 25428c2ecf20Sopenharmony_ci netif_info(lio, tx_err, lio->netdev, "IQ%d Transmit dropped:%llu\n", 25438c2ecf20Sopenharmony_ci iq_no, stats->tx_dropped); 25448c2ecf20Sopenharmony_ci if (dptr) 25458c2ecf20Sopenharmony_ci dma_unmap_single(&oct->pci_dev->dev, dptr, 25468c2ecf20Sopenharmony_ci ndata.datasize, DMA_TO_DEVICE); 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci octeon_ring_doorbell_locked(oct, iq_no); 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci tx_buffer_free(skb); 25518c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 25528c2ecf20Sopenharmony_ci} 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci/** 25558c2ecf20Sopenharmony_ci * liquidio_tx_timeout - Network device Tx timeout 25568c2ecf20Sopenharmony_ci * @netdev: pointer to network device 25578c2ecf20Sopenharmony_ci * @txqueue: index of the hung transmit queue 25588c2ecf20Sopenharmony_ci */ 25598c2ecf20Sopenharmony_cistatic void liquidio_tx_timeout(struct net_device *netdev, unsigned int txqueue) 25608c2ecf20Sopenharmony_ci{ 25618c2ecf20Sopenharmony_ci struct lio *lio; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci lio = GET_LIO(netdev); 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci netif_info(lio, tx_err, lio->netdev, 25668c2ecf20Sopenharmony_ci "Transmit timeout tx_dropped:%ld, waking up queues now!!\n", 25678c2ecf20Sopenharmony_ci netdev->stats.tx_dropped); 25688c2ecf20Sopenharmony_ci netif_trans_update(netdev); 25698c2ecf20Sopenharmony_ci wake_txqs(netdev); 25708c2ecf20Sopenharmony_ci} 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_cistatic int liquidio_vlan_rx_add_vid(struct net_device *netdev, 25738c2ecf20Sopenharmony_ci __be16 proto __attribute__((unused)), 25748c2ecf20Sopenharmony_ci u16 vid) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 25778c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 25788c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 25798c2ecf20Sopenharmony_ci int ret = 0; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci nctrl.ncmd.u64 = 0; 25848c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_ADD_VLAN_FILTER; 25858c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = vid; 25868c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 25878c2ecf20Sopenharmony_ci nctrl.netpndev = (u64)netdev; 25888c2ecf20Sopenharmony_ci nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); 25918c2ecf20Sopenharmony_ci if (ret) { 25928c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n", 25938c2ecf20Sopenharmony_ci ret); 25948c2ecf20Sopenharmony_ci if (ret > 0) 25958c2ecf20Sopenharmony_ci ret = -EIO; 25968c2ecf20Sopenharmony_ci } 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci return ret; 25998c2ecf20Sopenharmony_ci} 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_cistatic int liquidio_vlan_rx_kill_vid(struct net_device *netdev, 26028c2ecf20Sopenharmony_ci __be16 proto __attribute__((unused)), 26038c2ecf20Sopenharmony_ci u16 vid) 26048c2ecf20Sopenharmony_ci{ 26058c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 26068c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 26078c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 26088c2ecf20Sopenharmony_ci int ret = 0; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci nctrl.ncmd.u64 = 0; 26138c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_DEL_VLAN_FILTER; 26148c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = vid; 26158c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 26168c2ecf20Sopenharmony_ci nctrl.netpndev = (u64)netdev; 26178c2ecf20Sopenharmony_ci nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); 26208c2ecf20Sopenharmony_ci if (ret) { 26218c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Del VLAN filter failed in core (ret: 0x%x)\n", 26228c2ecf20Sopenharmony_ci ret); 26238c2ecf20Sopenharmony_ci if (ret > 0) 26248c2ecf20Sopenharmony_ci ret = -EIO; 26258c2ecf20Sopenharmony_ci } 26268c2ecf20Sopenharmony_ci return ret; 26278c2ecf20Sopenharmony_ci} 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci/** 26308c2ecf20Sopenharmony_ci * liquidio_set_rxcsum_command - Sending command to enable/disable RX checksum offload 26318c2ecf20Sopenharmony_ci * @netdev: pointer to network device 26328c2ecf20Sopenharmony_ci * @command: OCTNET_CMD_TNL_RX_CSUM_CTL 26338c2ecf20Sopenharmony_ci * @rx_cmd: OCTNET_CMD_RXCSUM_ENABLE/OCTNET_CMD_RXCSUM_DISABLE 26348c2ecf20Sopenharmony_ci * Returns: SUCCESS or FAILURE 26358c2ecf20Sopenharmony_ci */ 26368c2ecf20Sopenharmony_cistatic int liquidio_set_rxcsum_command(struct net_device *netdev, int command, 26378c2ecf20Sopenharmony_ci u8 rx_cmd) 26388c2ecf20Sopenharmony_ci{ 26398c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 26408c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 26418c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 26428c2ecf20Sopenharmony_ci int ret = 0; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci nctrl.ncmd.u64 = 0; 26478c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = command; 26488c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = rx_cmd; 26498c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 26508c2ecf20Sopenharmony_ci nctrl.netpndev = (u64)netdev; 26518c2ecf20Sopenharmony_ci nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); 26548c2ecf20Sopenharmony_ci if (ret) { 26558c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 26568c2ecf20Sopenharmony_ci "DEVFLAGS RXCSUM change failed in core(ret:0x%x)\n", 26578c2ecf20Sopenharmony_ci ret); 26588c2ecf20Sopenharmony_ci if (ret > 0) 26598c2ecf20Sopenharmony_ci ret = -EIO; 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci return ret; 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci/** 26658c2ecf20Sopenharmony_ci * liquidio_vxlan_port_command - Sending command to add/delete VxLAN UDP port to firmware 26668c2ecf20Sopenharmony_ci * @netdev: pointer to network device 26678c2ecf20Sopenharmony_ci * @command: OCTNET_CMD_VXLAN_PORT_CONFIG 26688c2ecf20Sopenharmony_ci * @vxlan_port: VxLAN port to be added or deleted 26698c2ecf20Sopenharmony_ci * @vxlan_cmd_bit: OCTNET_CMD_VXLAN_PORT_ADD, 26708c2ecf20Sopenharmony_ci * OCTNET_CMD_VXLAN_PORT_DEL 26718c2ecf20Sopenharmony_ci * Return: SUCCESS or FAILURE 26728c2ecf20Sopenharmony_ci */ 26738c2ecf20Sopenharmony_cistatic int liquidio_vxlan_port_command(struct net_device *netdev, int command, 26748c2ecf20Sopenharmony_ci u16 vxlan_port, u8 vxlan_cmd_bit) 26758c2ecf20Sopenharmony_ci{ 26768c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 26778c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 26788c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 26798c2ecf20Sopenharmony_ci int ret = 0; 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci nctrl.ncmd.u64 = 0; 26848c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = command; 26858c2ecf20Sopenharmony_ci nctrl.ncmd.s.more = vxlan_cmd_bit; 26868c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = vxlan_port; 26878c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 26888c2ecf20Sopenharmony_ci nctrl.netpndev = (u64)netdev; 26898c2ecf20Sopenharmony_ci nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); 26928c2ecf20Sopenharmony_ci if (ret) { 26938c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 26948c2ecf20Sopenharmony_ci "VxLAN port add/delete failed in core (ret:0x%x)\n", 26958c2ecf20Sopenharmony_ci ret); 26968c2ecf20Sopenharmony_ci if (ret > 0) 26978c2ecf20Sopenharmony_ci ret = -EIO; 26988c2ecf20Sopenharmony_ci } 26998c2ecf20Sopenharmony_ci return ret; 27008c2ecf20Sopenharmony_ci} 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_cistatic int liquidio_udp_tunnel_set_port(struct net_device *netdev, 27038c2ecf20Sopenharmony_ci unsigned int table, unsigned int entry, 27048c2ecf20Sopenharmony_ci struct udp_tunnel_info *ti) 27058c2ecf20Sopenharmony_ci{ 27068c2ecf20Sopenharmony_ci return liquidio_vxlan_port_command(netdev, 27078c2ecf20Sopenharmony_ci OCTNET_CMD_VXLAN_PORT_CONFIG, 27088c2ecf20Sopenharmony_ci htons(ti->port), 27098c2ecf20Sopenharmony_ci OCTNET_CMD_VXLAN_PORT_ADD); 27108c2ecf20Sopenharmony_ci} 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_cistatic int liquidio_udp_tunnel_unset_port(struct net_device *netdev, 27138c2ecf20Sopenharmony_ci unsigned int table, 27148c2ecf20Sopenharmony_ci unsigned int entry, 27158c2ecf20Sopenharmony_ci struct udp_tunnel_info *ti) 27168c2ecf20Sopenharmony_ci{ 27178c2ecf20Sopenharmony_ci return liquidio_vxlan_port_command(netdev, 27188c2ecf20Sopenharmony_ci OCTNET_CMD_VXLAN_PORT_CONFIG, 27198c2ecf20Sopenharmony_ci htons(ti->port), 27208c2ecf20Sopenharmony_ci OCTNET_CMD_VXLAN_PORT_DEL); 27218c2ecf20Sopenharmony_ci} 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_cistatic const struct udp_tunnel_nic_info liquidio_udp_tunnels = { 27248c2ecf20Sopenharmony_ci .set_port = liquidio_udp_tunnel_set_port, 27258c2ecf20Sopenharmony_ci .unset_port = liquidio_udp_tunnel_unset_port, 27268c2ecf20Sopenharmony_ci .tables = { 27278c2ecf20Sopenharmony_ci { .n_entries = 1024, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, 27288c2ecf20Sopenharmony_ci }, 27298c2ecf20Sopenharmony_ci}; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci/** 27328c2ecf20Sopenharmony_ci * liquidio_fix_features - Net device fix features 27338c2ecf20Sopenharmony_ci * @netdev: pointer to network device 27348c2ecf20Sopenharmony_ci * @request: features requested 27358c2ecf20Sopenharmony_ci * Return: updated features list 27368c2ecf20Sopenharmony_ci */ 27378c2ecf20Sopenharmony_cistatic netdev_features_t liquidio_fix_features(struct net_device *netdev, 27388c2ecf20Sopenharmony_ci netdev_features_t request) 27398c2ecf20Sopenharmony_ci{ 27408c2ecf20Sopenharmony_ci struct lio *lio = netdev_priv(netdev); 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci if ((request & NETIF_F_RXCSUM) && 27438c2ecf20Sopenharmony_ci !(lio->dev_capability & NETIF_F_RXCSUM)) 27448c2ecf20Sopenharmony_ci request &= ~NETIF_F_RXCSUM; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci if ((request & NETIF_F_HW_CSUM) && 27478c2ecf20Sopenharmony_ci !(lio->dev_capability & NETIF_F_HW_CSUM)) 27488c2ecf20Sopenharmony_ci request &= ~NETIF_F_HW_CSUM; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci if ((request & NETIF_F_TSO) && !(lio->dev_capability & NETIF_F_TSO)) 27518c2ecf20Sopenharmony_ci request &= ~NETIF_F_TSO; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci if ((request & NETIF_F_TSO6) && !(lio->dev_capability & NETIF_F_TSO6)) 27548c2ecf20Sopenharmony_ci request &= ~NETIF_F_TSO6; 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci if ((request & NETIF_F_LRO) && !(lio->dev_capability & NETIF_F_LRO)) 27578c2ecf20Sopenharmony_ci request &= ~NETIF_F_LRO; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci /*Disable LRO if RXCSUM is off */ 27608c2ecf20Sopenharmony_ci if (!(request & NETIF_F_RXCSUM) && (netdev->features & NETIF_F_LRO) && 27618c2ecf20Sopenharmony_ci (lio->dev_capability & NETIF_F_LRO)) 27628c2ecf20Sopenharmony_ci request &= ~NETIF_F_LRO; 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci if ((request & NETIF_F_HW_VLAN_CTAG_FILTER) && 27658c2ecf20Sopenharmony_ci !(lio->dev_capability & NETIF_F_HW_VLAN_CTAG_FILTER)) 27668c2ecf20Sopenharmony_ci request &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci return request; 27698c2ecf20Sopenharmony_ci} 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci/** 27728c2ecf20Sopenharmony_ci * liquidio_set_features - Net device set features 27738c2ecf20Sopenharmony_ci * @netdev: pointer to network device 27748c2ecf20Sopenharmony_ci * @features: features to enable/disable 27758c2ecf20Sopenharmony_ci */ 27768c2ecf20Sopenharmony_cistatic int liquidio_set_features(struct net_device *netdev, 27778c2ecf20Sopenharmony_ci netdev_features_t features) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci struct lio *lio = netdev_priv(netdev); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci if ((features & NETIF_F_LRO) && 27828c2ecf20Sopenharmony_ci (lio->dev_capability & NETIF_F_LRO) && 27838c2ecf20Sopenharmony_ci !(netdev->features & NETIF_F_LRO)) 27848c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE, 27858c2ecf20Sopenharmony_ci OCTNIC_LROIPV4 | OCTNIC_LROIPV6); 27868c2ecf20Sopenharmony_ci else if (!(features & NETIF_F_LRO) && 27878c2ecf20Sopenharmony_ci (lio->dev_capability & NETIF_F_LRO) && 27888c2ecf20Sopenharmony_ci (netdev->features & NETIF_F_LRO)) 27898c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, OCTNET_CMD_LRO_DISABLE, 27908c2ecf20Sopenharmony_ci OCTNIC_LROIPV4 | OCTNIC_LROIPV6); 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci /* Sending command to firmware to enable/disable RX checksum 27938c2ecf20Sopenharmony_ci * offload settings using ethtool 27948c2ecf20Sopenharmony_ci */ 27958c2ecf20Sopenharmony_ci if (!(netdev->features & NETIF_F_RXCSUM) && 27968c2ecf20Sopenharmony_ci (lio->enc_dev_capability & NETIF_F_RXCSUM) && 27978c2ecf20Sopenharmony_ci (features & NETIF_F_RXCSUM)) 27988c2ecf20Sopenharmony_ci liquidio_set_rxcsum_command(netdev, 27998c2ecf20Sopenharmony_ci OCTNET_CMD_TNL_RX_CSUM_CTL, 28008c2ecf20Sopenharmony_ci OCTNET_CMD_RXCSUM_ENABLE); 28018c2ecf20Sopenharmony_ci else if ((netdev->features & NETIF_F_RXCSUM) && 28028c2ecf20Sopenharmony_ci (lio->enc_dev_capability & NETIF_F_RXCSUM) && 28038c2ecf20Sopenharmony_ci !(features & NETIF_F_RXCSUM)) 28048c2ecf20Sopenharmony_ci liquidio_set_rxcsum_command(netdev, OCTNET_CMD_TNL_RX_CSUM_CTL, 28058c2ecf20Sopenharmony_ci OCTNET_CMD_RXCSUM_DISABLE); 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && 28088c2ecf20Sopenharmony_ci (lio->dev_capability & NETIF_F_HW_VLAN_CTAG_FILTER) && 28098c2ecf20Sopenharmony_ci !(netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) 28108c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, OCTNET_CMD_VLAN_FILTER_CTL, 28118c2ecf20Sopenharmony_ci OCTNET_CMD_VLAN_FILTER_ENABLE); 28128c2ecf20Sopenharmony_ci else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && 28138c2ecf20Sopenharmony_ci (lio->dev_capability & NETIF_F_HW_VLAN_CTAG_FILTER) && 28148c2ecf20Sopenharmony_ci (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) 28158c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, OCTNET_CMD_VLAN_FILTER_CTL, 28168c2ecf20Sopenharmony_ci OCTNET_CMD_VLAN_FILTER_DISABLE); 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci return 0; 28198c2ecf20Sopenharmony_ci} 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_cistatic int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx, 28228c2ecf20Sopenharmony_ci u8 *mac, bool is_admin_assigned) 28238c2ecf20Sopenharmony_ci{ 28248c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 28258c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 28268c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 28278c2ecf20Sopenharmony_ci int ret = 0; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(mac)) 28308c2ecf20Sopenharmony_ci return -EINVAL; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.max_vfs) 28338c2ecf20Sopenharmony_ci return -EINVAL; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci nctrl.ncmd.u64 = 0; 28388c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MACADDR; 28398c2ecf20Sopenharmony_ci /* vfidx is 0 based, but vf_num (param1) is 1 based */ 28408c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = vfidx + 1; 28418c2ecf20Sopenharmony_ci nctrl.ncmd.s.more = 1; 28428c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 28438c2ecf20Sopenharmony_ci nctrl.netpndev = (u64)netdev; 28448c2ecf20Sopenharmony_ci if (is_admin_assigned) { 28458c2ecf20Sopenharmony_ci nctrl.ncmd.s.param2 = true; 28468c2ecf20Sopenharmony_ci nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; 28478c2ecf20Sopenharmony_ci } 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci nctrl.udd[0] = 0; 28508c2ecf20Sopenharmony_ci /* The MAC Address is presented in network byte order. */ 28518c2ecf20Sopenharmony_ci ether_addr_copy((u8 *)&nctrl.udd[0] + 2, mac); 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci oct->sriov_info.vf_macaddr[vfidx] = nctrl.udd[0]; 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(oct, &nctrl); 28568c2ecf20Sopenharmony_ci if (ret > 0) 28578c2ecf20Sopenharmony_ci ret = -EIO; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci return ret; 28608c2ecf20Sopenharmony_ci} 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_cistatic int liquidio_set_vf_mac(struct net_device *netdev, int vfidx, u8 *mac) 28638c2ecf20Sopenharmony_ci{ 28648c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 28658c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 28668c2ecf20Sopenharmony_ci int retval; 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) 28698c2ecf20Sopenharmony_ci return -EINVAL; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci retval = __liquidio_set_vf_mac(netdev, vfidx, mac, true); 28728c2ecf20Sopenharmony_ci if (!retval) 28738c2ecf20Sopenharmony_ci cn23xx_tell_vf_its_macaddr_changed(oct, vfidx, mac); 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci return retval; 28768c2ecf20Sopenharmony_ci} 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_cistatic int liquidio_set_vf_spoofchk(struct net_device *netdev, int vfidx, 28798c2ecf20Sopenharmony_ci bool enable) 28808c2ecf20Sopenharmony_ci{ 28818c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 28828c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 28838c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 28848c2ecf20Sopenharmony_ci int retval; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci if (!(oct->fw_info.app_cap_flags & LIQUIDIO_SPOOFCHK_CAP)) { 28878c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, 28888c2ecf20Sopenharmony_ci "firmware does not support spoofchk\n"); 28898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 28908c2ecf20Sopenharmony_ci } 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) { 28938c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, "Invalid vfidx %d\n", vfidx); 28948c2ecf20Sopenharmony_ci return -EINVAL; 28958c2ecf20Sopenharmony_ci } 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci if (enable) { 28988c2ecf20Sopenharmony_ci if (oct->sriov_info.vf_spoofchk[vfidx]) 28998c2ecf20Sopenharmony_ci return 0; 29008c2ecf20Sopenharmony_ci } else { 29018c2ecf20Sopenharmony_ci /* Clear */ 29028c2ecf20Sopenharmony_ci if (!oct->sriov_info.vf_spoofchk[vfidx]) 29038c2ecf20Sopenharmony_ci return 0; 29048c2ecf20Sopenharmony_ci } 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 29078c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmdgroup = OCTNET_CMD_GROUP1; 29088c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_SET_VF_SPOOFCHK; 29098c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = 29108c2ecf20Sopenharmony_ci vfidx + 1; /* vfidx is 0 based, 29118c2ecf20Sopenharmony_ci * but vf_num (param1) is 1 based 29128c2ecf20Sopenharmony_ci */ 29138c2ecf20Sopenharmony_ci nctrl.ncmd.s.param2 = enable; 29148c2ecf20Sopenharmony_ci nctrl.ncmd.s.more = 0; 29158c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 29168c2ecf20Sopenharmony_ci nctrl.cb_fn = NULL; 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci retval = octnet_send_nic_ctrl_pkt(oct, &nctrl); 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci if (retval) { 29218c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, 29228c2ecf20Sopenharmony_ci "Failed to set VF %d spoofchk %s\n", vfidx, 29238c2ecf20Sopenharmony_ci enable ? "on" : "off"); 29248c2ecf20Sopenharmony_ci return -1; 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci oct->sriov_info.vf_spoofchk[vfidx] = enable; 29288c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, "VF %u spoofchk is %s\n", vfidx, 29298c2ecf20Sopenharmony_ci enable ? "on" : "off"); 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci return 0; 29328c2ecf20Sopenharmony_ci} 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_cistatic int liquidio_set_vf_vlan(struct net_device *netdev, int vfidx, 29358c2ecf20Sopenharmony_ci u16 vlan, u8 qos, __be16 vlan_proto) 29368c2ecf20Sopenharmony_ci{ 29378c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 29388c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 29398c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 29408c2ecf20Sopenharmony_ci u16 vlantci; 29418c2ecf20Sopenharmony_ci int ret = 0; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) 29448c2ecf20Sopenharmony_ci return -EINVAL; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci if (vlan_proto != htons(ETH_P_8021Q)) 29478c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci if (vlan >= VLAN_N_VID || qos > 7) 29508c2ecf20Sopenharmony_ci return -EINVAL; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci if (vlan) 29538c2ecf20Sopenharmony_ci vlantci = vlan | (u16)qos << VLAN_PRIO_SHIFT; 29548c2ecf20Sopenharmony_ci else 29558c2ecf20Sopenharmony_ci vlantci = 0; 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci if (oct->sriov_info.vf_vlantci[vfidx] == vlantci) 29588c2ecf20Sopenharmony_ci return 0; 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci if (vlan) 29638c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_ADD_VLAN_FILTER; 29648c2ecf20Sopenharmony_ci else 29658c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_DEL_VLAN_FILTER; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = vlantci; 29688c2ecf20Sopenharmony_ci nctrl.ncmd.s.param2 = 29698c2ecf20Sopenharmony_ci vfidx + 1; /* vfidx is 0 based, but vf_num (param2) is 1 based */ 29708c2ecf20Sopenharmony_ci nctrl.ncmd.s.more = 0; 29718c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 29728c2ecf20Sopenharmony_ci nctrl.cb_fn = NULL; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(oct, &nctrl); 29758c2ecf20Sopenharmony_ci if (ret) { 29768c2ecf20Sopenharmony_ci if (ret > 0) 29778c2ecf20Sopenharmony_ci ret = -EIO; 29788c2ecf20Sopenharmony_ci return ret; 29798c2ecf20Sopenharmony_ci } 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci oct->sriov_info.vf_vlantci[vfidx] = vlantci; 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci return ret; 29848c2ecf20Sopenharmony_ci} 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_cistatic int liquidio_get_vf_config(struct net_device *netdev, int vfidx, 29878c2ecf20Sopenharmony_ci struct ifla_vf_info *ivi) 29888c2ecf20Sopenharmony_ci{ 29898c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 29908c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 29918c2ecf20Sopenharmony_ci u8 *macaddr; 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) 29948c2ecf20Sopenharmony_ci return -EINVAL; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci memset(ivi, 0, sizeof(struct ifla_vf_info)); 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci ivi->vf = vfidx; 29998c2ecf20Sopenharmony_ci macaddr = 2 + (u8 *)&oct->sriov_info.vf_macaddr[vfidx]; 30008c2ecf20Sopenharmony_ci ether_addr_copy(&ivi->mac[0], macaddr); 30018c2ecf20Sopenharmony_ci ivi->vlan = oct->sriov_info.vf_vlantci[vfidx] & VLAN_VID_MASK; 30028c2ecf20Sopenharmony_ci ivi->qos = oct->sriov_info.vf_vlantci[vfidx] >> VLAN_PRIO_SHIFT; 30038c2ecf20Sopenharmony_ci if (oct->sriov_info.trusted_vf.active && 30048c2ecf20Sopenharmony_ci oct->sriov_info.trusted_vf.id == vfidx) 30058c2ecf20Sopenharmony_ci ivi->trusted = true; 30068c2ecf20Sopenharmony_ci else 30078c2ecf20Sopenharmony_ci ivi->trusted = false; 30088c2ecf20Sopenharmony_ci ivi->linkstate = oct->sriov_info.vf_linkstate[vfidx]; 30098c2ecf20Sopenharmony_ci ivi->spoofchk = oct->sriov_info.vf_spoofchk[vfidx]; 30108c2ecf20Sopenharmony_ci ivi->max_tx_rate = lio->linfo.link.s.speed; 30118c2ecf20Sopenharmony_ci ivi->min_tx_rate = 0; 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci return 0; 30148c2ecf20Sopenharmony_ci} 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_cistatic int liquidio_send_vf_trust_cmd(struct lio *lio, int vfidx, bool trusted) 30178c2ecf20Sopenharmony_ci{ 30188c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 30198c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 30208c2ecf20Sopenharmony_ci int retval; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci sc = octeon_alloc_soft_command(oct, 0, 16, 0); 30238c2ecf20Sopenharmony_ci if (!sc) 30248c2ecf20Sopenharmony_ci return -ENOMEM; 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci sc->iq_no = lio->linfo.txpciq[0].s.q_no; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci /* vfidx is 0 based, but vf_num (param1) is 1 based */ 30298c2ecf20Sopenharmony_ci octeon_prepare_soft_command(oct, sc, OPCODE_NIC, 30308c2ecf20Sopenharmony_ci OPCODE_NIC_SET_TRUSTED_VF, 0, vfidx + 1, 30318c2ecf20Sopenharmony_ci trusted); 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci init_completion(&sc->complete); 30348c2ecf20Sopenharmony_ci sc->sc_status = OCTEON_REQUEST_PENDING; 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci retval = octeon_send_soft_command(oct, sc); 30378c2ecf20Sopenharmony_ci if (retval == IQ_SEND_FAILED) { 30388c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 30398c2ecf20Sopenharmony_ci retval = -1; 30408c2ecf20Sopenharmony_ci } else { 30418c2ecf20Sopenharmony_ci /* Wait for response or timeout */ 30428c2ecf20Sopenharmony_ci retval = wait_for_sc_completion_timeout(oct, sc, 0); 30438c2ecf20Sopenharmony_ci if (retval) 30448c2ecf20Sopenharmony_ci return (retval); 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 30478c2ecf20Sopenharmony_ci } 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci return retval; 30508c2ecf20Sopenharmony_ci} 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_cistatic int liquidio_set_vf_trust(struct net_device *netdev, int vfidx, 30538c2ecf20Sopenharmony_ci bool setting) 30548c2ecf20Sopenharmony_ci{ 30558c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 30568c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci if (strcmp(oct->fw_info.liquidio_firmware_version, "1.7.1") < 0) { 30598c2ecf20Sopenharmony_ci /* trusted vf is not supported by firmware older than 1.7.1 */ 30608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30618c2ecf20Sopenharmony_ci } 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) { 30648c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, "Invalid vfidx %d\n", vfidx); 30658c2ecf20Sopenharmony_ci return -EINVAL; 30668c2ecf20Sopenharmony_ci } 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci if (setting) { 30698c2ecf20Sopenharmony_ci /* Set */ 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci if (oct->sriov_info.trusted_vf.active && 30728c2ecf20Sopenharmony_ci oct->sriov_info.trusted_vf.id == vfidx) 30738c2ecf20Sopenharmony_ci return 0; 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci if (oct->sriov_info.trusted_vf.active) { 30768c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, "More than one trusted VF is not allowed\n"); 30778c2ecf20Sopenharmony_ci return -EPERM; 30788c2ecf20Sopenharmony_ci } 30798c2ecf20Sopenharmony_ci } else { 30808c2ecf20Sopenharmony_ci /* Clear */ 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci if (!oct->sriov_info.trusted_vf.active) 30838c2ecf20Sopenharmony_ci return 0; 30848c2ecf20Sopenharmony_ci } 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci if (!liquidio_send_vf_trust_cmd(lio, vfidx, setting)) { 30878c2ecf20Sopenharmony_ci if (setting) { 30888c2ecf20Sopenharmony_ci oct->sriov_info.trusted_vf.id = vfidx; 30898c2ecf20Sopenharmony_ci oct->sriov_info.trusted_vf.active = true; 30908c2ecf20Sopenharmony_ci } else { 30918c2ecf20Sopenharmony_ci oct->sriov_info.trusted_vf.active = false; 30928c2ecf20Sopenharmony_ci } 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, "VF %u is %strusted\n", vfidx, 30958c2ecf20Sopenharmony_ci setting ? "" : "not "); 30968c2ecf20Sopenharmony_ci } else { 30978c2ecf20Sopenharmony_ci netif_info(lio, drv, lio->netdev, "Failed to set VF trusted\n"); 30988c2ecf20Sopenharmony_ci return -1; 30998c2ecf20Sopenharmony_ci } 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci return 0; 31028c2ecf20Sopenharmony_ci} 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_cistatic int liquidio_set_vf_link_state(struct net_device *netdev, int vfidx, 31058c2ecf20Sopenharmony_ci int linkstate) 31068c2ecf20Sopenharmony_ci{ 31078c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 31088c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 31098c2ecf20Sopenharmony_ci struct octnic_ctrl_pkt nctrl; 31108c2ecf20Sopenharmony_ci int ret = 0; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) 31138c2ecf20Sopenharmony_ci return -EINVAL; 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci if (oct->sriov_info.vf_linkstate[vfidx] == linkstate) 31168c2ecf20Sopenharmony_ci return 0; 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); 31198c2ecf20Sopenharmony_ci nctrl.ncmd.s.cmd = OCTNET_CMD_SET_VF_LINKSTATE; 31208c2ecf20Sopenharmony_ci nctrl.ncmd.s.param1 = 31218c2ecf20Sopenharmony_ci vfidx + 1; /* vfidx is 0 based, but vf_num (param1) is 1 based */ 31228c2ecf20Sopenharmony_ci nctrl.ncmd.s.param2 = linkstate; 31238c2ecf20Sopenharmony_ci nctrl.ncmd.s.more = 0; 31248c2ecf20Sopenharmony_ci nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; 31258c2ecf20Sopenharmony_ci nctrl.cb_fn = NULL; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci ret = octnet_send_nic_ctrl_pkt(oct, &nctrl); 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci if (!ret) 31308c2ecf20Sopenharmony_ci oct->sriov_info.vf_linkstate[vfidx] = linkstate; 31318c2ecf20Sopenharmony_ci else if (ret > 0) 31328c2ecf20Sopenharmony_ci ret = -EIO; 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci return ret; 31358c2ecf20Sopenharmony_ci} 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_cistatic int 31388c2ecf20Sopenharmony_ciliquidio_eswitch_mode_get(struct devlink *devlink, u16 *mode) 31398c2ecf20Sopenharmony_ci{ 31408c2ecf20Sopenharmony_ci struct lio_devlink_priv *priv; 31418c2ecf20Sopenharmony_ci struct octeon_device *oct; 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci priv = devlink_priv(devlink); 31448c2ecf20Sopenharmony_ci oct = priv->oct; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci *mode = oct->eswitch_mode; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci return 0; 31498c2ecf20Sopenharmony_ci} 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_cistatic int 31528c2ecf20Sopenharmony_ciliquidio_eswitch_mode_set(struct devlink *devlink, u16 mode, 31538c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 31548c2ecf20Sopenharmony_ci{ 31558c2ecf20Sopenharmony_ci struct lio_devlink_priv *priv; 31568c2ecf20Sopenharmony_ci struct octeon_device *oct; 31578c2ecf20Sopenharmony_ci int ret = 0; 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci priv = devlink_priv(devlink); 31608c2ecf20Sopenharmony_ci oct = priv->oct; 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci if (!(oct->fw_info.app_cap_flags & LIQUIDIO_SWITCHDEV_CAP)) 31638c2ecf20Sopenharmony_ci return -EINVAL; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci if (oct->eswitch_mode == mode) 31668c2ecf20Sopenharmony_ci return 0; 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci switch (mode) { 31698c2ecf20Sopenharmony_ci case DEVLINK_ESWITCH_MODE_SWITCHDEV: 31708c2ecf20Sopenharmony_ci oct->eswitch_mode = mode; 31718c2ecf20Sopenharmony_ci ret = lio_vf_rep_create(oct); 31728c2ecf20Sopenharmony_ci break; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci case DEVLINK_ESWITCH_MODE_LEGACY: 31758c2ecf20Sopenharmony_ci lio_vf_rep_destroy(oct); 31768c2ecf20Sopenharmony_ci oct->eswitch_mode = mode; 31778c2ecf20Sopenharmony_ci break; 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci default: 31808c2ecf20Sopenharmony_ci ret = -EINVAL; 31818c2ecf20Sopenharmony_ci } 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci return ret; 31848c2ecf20Sopenharmony_ci} 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_cistatic const struct devlink_ops liquidio_devlink_ops = { 31878c2ecf20Sopenharmony_ci .eswitch_mode_get = liquidio_eswitch_mode_get, 31888c2ecf20Sopenharmony_ci .eswitch_mode_set = liquidio_eswitch_mode_set, 31898c2ecf20Sopenharmony_ci}; 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_cistatic int 31928c2ecf20Sopenharmony_ciliquidio_get_port_parent_id(struct net_device *dev, 31938c2ecf20Sopenharmony_ci struct netdev_phys_item_id *ppid) 31948c2ecf20Sopenharmony_ci{ 31958c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(dev); 31968c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci if (oct->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 31998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci ppid->id_len = ETH_ALEN; 32028c2ecf20Sopenharmony_ci ether_addr_copy(ppid->id, (void *)&lio->linfo.hw_addr + 2); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci return 0; 32058c2ecf20Sopenharmony_ci} 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_cistatic int liquidio_get_vf_stats(struct net_device *netdev, int vfidx, 32088c2ecf20Sopenharmony_ci struct ifla_vf_stats *vf_stats) 32098c2ecf20Sopenharmony_ci{ 32108c2ecf20Sopenharmony_ci struct lio *lio = GET_LIO(netdev); 32118c2ecf20Sopenharmony_ci struct octeon_device *oct = lio->oct_dev; 32128c2ecf20Sopenharmony_ci struct oct_vf_stats stats; 32138c2ecf20Sopenharmony_ci int ret; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) 32168c2ecf20Sopenharmony_ci return -EINVAL; 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci memset(&stats, 0, sizeof(struct oct_vf_stats)); 32198c2ecf20Sopenharmony_ci ret = cn23xx_get_vf_stats(oct, vfidx, &stats); 32208c2ecf20Sopenharmony_ci if (!ret) { 32218c2ecf20Sopenharmony_ci vf_stats->rx_packets = stats.rx_packets; 32228c2ecf20Sopenharmony_ci vf_stats->tx_packets = stats.tx_packets; 32238c2ecf20Sopenharmony_ci vf_stats->rx_bytes = stats.rx_bytes; 32248c2ecf20Sopenharmony_ci vf_stats->tx_bytes = stats.tx_bytes; 32258c2ecf20Sopenharmony_ci vf_stats->broadcast = stats.broadcast; 32268c2ecf20Sopenharmony_ci vf_stats->multicast = stats.multicast; 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci return ret; 32308c2ecf20Sopenharmony_ci} 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_cistatic const struct net_device_ops lionetdevops = { 32338c2ecf20Sopenharmony_ci .ndo_open = liquidio_open, 32348c2ecf20Sopenharmony_ci .ndo_stop = liquidio_stop, 32358c2ecf20Sopenharmony_ci .ndo_start_xmit = liquidio_xmit, 32368c2ecf20Sopenharmony_ci .ndo_get_stats64 = liquidio_get_stats64, 32378c2ecf20Sopenharmony_ci .ndo_set_mac_address = liquidio_set_mac, 32388c2ecf20Sopenharmony_ci .ndo_set_rx_mode = liquidio_set_mcast_list, 32398c2ecf20Sopenharmony_ci .ndo_tx_timeout = liquidio_tx_timeout, 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = liquidio_vlan_rx_add_vid, 32428c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = liquidio_vlan_rx_kill_vid, 32438c2ecf20Sopenharmony_ci .ndo_change_mtu = liquidio_change_mtu, 32448c2ecf20Sopenharmony_ci .ndo_do_ioctl = liquidio_ioctl, 32458c2ecf20Sopenharmony_ci .ndo_fix_features = liquidio_fix_features, 32468c2ecf20Sopenharmony_ci .ndo_set_features = liquidio_set_features, 32478c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 32488c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 32498c2ecf20Sopenharmony_ci .ndo_set_vf_mac = liquidio_set_vf_mac, 32508c2ecf20Sopenharmony_ci .ndo_set_vf_vlan = liquidio_set_vf_vlan, 32518c2ecf20Sopenharmony_ci .ndo_get_vf_config = liquidio_get_vf_config, 32528c2ecf20Sopenharmony_ci .ndo_set_vf_spoofchk = liquidio_set_vf_spoofchk, 32538c2ecf20Sopenharmony_ci .ndo_set_vf_trust = liquidio_set_vf_trust, 32548c2ecf20Sopenharmony_ci .ndo_set_vf_link_state = liquidio_set_vf_link_state, 32558c2ecf20Sopenharmony_ci .ndo_get_vf_stats = liquidio_get_vf_stats, 32568c2ecf20Sopenharmony_ci .ndo_get_port_parent_id = liquidio_get_port_parent_id, 32578c2ecf20Sopenharmony_ci}; 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci/** 32608c2ecf20Sopenharmony_ci * liquidio_init - Entry point for the liquidio module 32618c2ecf20Sopenharmony_ci */ 32628c2ecf20Sopenharmony_cistatic int __init liquidio_init(void) 32638c2ecf20Sopenharmony_ci{ 32648c2ecf20Sopenharmony_ci int i; 32658c2ecf20Sopenharmony_ci struct handshake *hs; 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci init_completion(&first_stage); 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci octeon_init_device_list(OCTEON_CONFIG_TYPE_DEFAULT); 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci if (liquidio_init_pci()) 32728c2ecf20Sopenharmony_ci return -EINVAL; 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci wait_for_completion_timeout(&first_stage, msecs_to_jiffies(1000)); 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_DEVICES; i++) { 32778c2ecf20Sopenharmony_ci hs = &handshake[i]; 32788c2ecf20Sopenharmony_ci if (hs->pci_dev) { 32798c2ecf20Sopenharmony_ci wait_for_completion(&hs->init); 32808c2ecf20Sopenharmony_ci if (!hs->init_ok) { 32818c2ecf20Sopenharmony_ci /* init handshake failed */ 32828c2ecf20Sopenharmony_ci dev_err(&hs->pci_dev->dev, 32838c2ecf20Sopenharmony_ci "Failed to init device\n"); 32848c2ecf20Sopenharmony_ci liquidio_deinit_pci(); 32858c2ecf20Sopenharmony_ci return -EIO; 32868c2ecf20Sopenharmony_ci } 32878c2ecf20Sopenharmony_ci } 32888c2ecf20Sopenharmony_ci } 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_DEVICES; i++) { 32918c2ecf20Sopenharmony_ci hs = &handshake[i]; 32928c2ecf20Sopenharmony_ci if (hs->pci_dev) { 32938c2ecf20Sopenharmony_ci wait_for_completion_timeout(&hs->started, 32948c2ecf20Sopenharmony_ci msecs_to_jiffies(30000)); 32958c2ecf20Sopenharmony_ci if (!hs->started_ok) { 32968c2ecf20Sopenharmony_ci /* starter handshake failed */ 32978c2ecf20Sopenharmony_ci dev_err(&hs->pci_dev->dev, 32988c2ecf20Sopenharmony_ci "Firmware failed to start\n"); 32998c2ecf20Sopenharmony_ci liquidio_deinit_pci(); 33008c2ecf20Sopenharmony_ci return -EIO; 33018c2ecf20Sopenharmony_ci } 33028c2ecf20Sopenharmony_ci } 33038c2ecf20Sopenharmony_ci } 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci return 0; 33068c2ecf20Sopenharmony_ci} 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_cistatic int lio_nic_info(struct octeon_recv_info *recv_info, void *buf) 33098c2ecf20Sopenharmony_ci{ 33108c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)buf; 33118c2ecf20Sopenharmony_ci struct octeon_recv_pkt *recv_pkt = recv_info->recv_pkt; 33128c2ecf20Sopenharmony_ci int gmxport = 0; 33138c2ecf20Sopenharmony_ci union oct_link_status *ls; 33148c2ecf20Sopenharmony_ci int i; 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci if (recv_pkt->buffer_size[0] != (sizeof(*ls) + OCT_DROQ_INFO_SIZE)) { 33178c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Malformed NIC_INFO, len=%d, ifidx=%d\n", 33188c2ecf20Sopenharmony_ci recv_pkt->buffer_size[0], 33198c2ecf20Sopenharmony_ci recv_pkt->rh.r_nic_info.gmxport); 33208c2ecf20Sopenharmony_ci goto nic_info_err; 33218c2ecf20Sopenharmony_ci } 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci gmxport = recv_pkt->rh.r_nic_info.gmxport; 33248c2ecf20Sopenharmony_ci ls = (union oct_link_status *)(get_rbd(recv_pkt->buffer_ptr[0]) + 33258c2ecf20Sopenharmony_ci OCT_DROQ_INFO_SIZE); 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci octeon_swap_8B_data((u64 *)ls, (sizeof(union oct_link_status)) >> 3); 33288c2ecf20Sopenharmony_ci for (i = 0; i < oct->ifcount; i++) { 33298c2ecf20Sopenharmony_ci if (oct->props[i].gmxport == gmxport) { 33308c2ecf20Sopenharmony_ci update_link_status(oct->props[i].netdev, ls); 33318c2ecf20Sopenharmony_ci break; 33328c2ecf20Sopenharmony_ci } 33338c2ecf20Sopenharmony_ci } 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_cinic_info_err: 33368c2ecf20Sopenharmony_ci for (i = 0; i < recv_pkt->buffer_count; i++) 33378c2ecf20Sopenharmony_ci recv_buffer_free(recv_pkt->buffer_ptr[i]); 33388c2ecf20Sopenharmony_ci octeon_free_recv_info(recv_info); 33398c2ecf20Sopenharmony_ci return 0; 33408c2ecf20Sopenharmony_ci} 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci/** 33438c2ecf20Sopenharmony_ci * setup_nic_devices - Setup network interfaces 33448c2ecf20Sopenharmony_ci * @octeon_dev: octeon device 33458c2ecf20Sopenharmony_ci * 33468c2ecf20Sopenharmony_ci * Called during init time for each device. It assumes the NIC 33478c2ecf20Sopenharmony_ci * is already up and running. The link information for each 33488c2ecf20Sopenharmony_ci * interface is passed in link_info. 33498c2ecf20Sopenharmony_ci */ 33508c2ecf20Sopenharmony_cistatic int setup_nic_devices(struct octeon_device *octeon_dev) 33518c2ecf20Sopenharmony_ci{ 33528c2ecf20Sopenharmony_ci struct lio *lio = NULL; 33538c2ecf20Sopenharmony_ci struct net_device *netdev; 33548c2ecf20Sopenharmony_ci u8 mac[6], i, j, *fw_ver, *micro_ver; 33558c2ecf20Sopenharmony_ci unsigned long micro; 33568c2ecf20Sopenharmony_ci u32 cur_ver; 33578c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 33588c2ecf20Sopenharmony_ci struct liquidio_if_cfg_resp *resp; 33598c2ecf20Sopenharmony_ci struct octdev_props *props; 33608c2ecf20Sopenharmony_ci int retval, num_iqueues, num_oqueues; 33618c2ecf20Sopenharmony_ci int max_num_queues = 0; 33628c2ecf20Sopenharmony_ci union oct_nic_if_cfg if_cfg; 33638c2ecf20Sopenharmony_ci unsigned int base_queue; 33648c2ecf20Sopenharmony_ci unsigned int gmx_port_id; 33658c2ecf20Sopenharmony_ci u32 resp_size, data_size; 33668c2ecf20Sopenharmony_ci u32 ifidx_or_pfnum; 33678c2ecf20Sopenharmony_ci struct lio_version *vdata; 33688c2ecf20Sopenharmony_ci struct devlink *devlink; 33698c2ecf20Sopenharmony_ci struct lio_devlink_priv *lio_devlink; 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci /* This is to handle link status changes */ 33728c2ecf20Sopenharmony_ci octeon_register_dispatch_fn(octeon_dev, OPCODE_NIC, 33738c2ecf20Sopenharmony_ci OPCODE_NIC_INFO, 33748c2ecf20Sopenharmony_ci lio_nic_info, octeon_dev); 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci /* REQTYPE_RESP_NET and REQTYPE_SOFT_COMMAND do not have free functions. 33778c2ecf20Sopenharmony_ci * They are handled directly. 33788c2ecf20Sopenharmony_ci */ 33798c2ecf20Sopenharmony_ci octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_NORESP_NET, 33808c2ecf20Sopenharmony_ci free_netbuf); 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_NORESP_NET_SG, 33838c2ecf20Sopenharmony_ci free_netsgbuf); 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci octeon_register_reqtype_free_fn(octeon_dev, REQTYPE_RESP_NET_SG, 33868c2ecf20Sopenharmony_ci free_netsgbuf_with_resp); 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci for (i = 0; i < octeon_dev->ifcount; i++) { 33898c2ecf20Sopenharmony_ci resp_size = sizeof(struct liquidio_if_cfg_resp); 33908c2ecf20Sopenharmony_ci data_size = sizeof(struct lio_version); 33918c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *) 33928c2ecf20Sopenharmony_ci octeon_alloc_soft_command(octeon_dev, data_size, 33938c2ecf20Sopenharmony_ci resp_size, 0); 33948c2ecf20Sopenharmony_ci resp = (struct liquidio_if_cfg_resp *)sc->virtrptr; 33958c2ecf20Sopenharmony_ci vdata = (struct lio_version *)sc->virtdptr; 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci *((u64 *)vdata) = 0; 33988c2ecf20Sopenharmony_ci vdata->major = cpu_to_be16(LIQUIDIO_BASE_MAJOR_VERSION); 33998c2ecf20Sopenharmony_ci vdata->minor = cpu_to_be16(LIQUIDIO_BASE_MINOR_VERSION); 34008c2ecf20Sopenharmony_ci vdata->micro = cpu_to_be16(LIQUIDIO_BASE_MICRO_VERSION); 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(octeon_dev)) { 34038c2ecf20Sopenharmony_ci num_iqueues = octeon_dev->sriov_info.num_pf_rings; 34048c2ecf20Sopenharmony_ci num_oqueues = octeon_dev->sriov_info.num_pf_rings; 34058c2ecf20Sopenharmony_ci base_queue = octeon_dev->sriov_info.pf_srn; 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci gmx_port_id = octeon_dev->pf_num; 34088c2ecf20Sopenharmony_ci ifidx_or_pfnum = octeon_dev->pf_num; 34098c2ecf20Sopenharmony_ci } else { 34108c2ecf20Sopenharmony_ci num_iqueues = CFG_GET_NUM_TXQS_NIC_IF( 34118c2ecf20Sopenharmony_ci octeon_get_conf(octeon_dev), i); 34128c2ecf20Sopenharmony_ci num_oqueues = CFG_GET_NUM_RXQS_NIC_IF( 34138c2ecf20Sopenharmony_ci octeon_get_conf(octeon_dev), i); 34148c2ecf20Sopenharmony_ci base_queue = CFG_GET_BASE_QUE_NIC_IF( 34158c2ecf20Sopenharmony_ci octeon_get_conf(octeon_dev), i); 34168c2ecf20Sopenharmony_ci gmx_port_id = CFG_GET_GMXID_NIC_IF( 34178c2ecf20Sopenharmony_ci octeon_get_conf(octeon_dev), i); 34188c2ecf20Sopenharmony_ci ifidx_or_pfnum = i; 34198c2ecf20Sopenharmony_ci } 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, 34228c2ecf20Sopenharmony_ci "requesting config for interface %d, iqs %d, oqs %d\n", 34238c2ecf20Sopenharmony_ci ifidx_or_pfnum, num_iqueues, num_oqueues); 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci if_cfg.u64 = 0; 34268c2ecf20Sopenharmony_ci if_cfg.s.num_iqueues = num_iqueues; 34278c2ecf20Sopenharmony_ci if_cfg.s.num_oqueues = num_oqueues; 34288c2ecf20Sopenharmony_ci if_cfg.s.base_queue = base_queue; 34298c2ecf20Sopenharmony_ci if_cfg.s.gmx_port_id = gmx_port_id; 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci sc->iq_no = 0; 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci octeon_prepare_soft_command(octeon_dev, sc, OPCODE_NIC, 34348c2ecf20Sopenharmony_ci OPCODE_NIC_IF_CFG, 0, 34358c2ecf20Sopenharmony_ci if_cfg.u64, 0); 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci init_completion(&sc->complete); 34388c2ecf20Sopenharmony_ci sc->sc_status = OCTEON_REQUEST_PENDING; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci retval = octeon_send_soft_command(octeon_dev, sc); 34418c2ecf20Sopenharmony_ci if (retval == IQ_SEND_FAILED) { 34428c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 34438c2ecf20Sopenharmony_ci "iq/oq config failed status: %x\n", 34448c2ecf20Sopenharmony_ci retval); 34458c2ecf20Sopenharmony_ci /* Soft instr is freed by driver in case of failure. */ 34468c2ecf20Sopenharmony_ci octeon_free_soft_command(octeon_dev, sc); 34478c2ecf20Sopenharmony_ci return(-EIO); 34488c2ecf20Sopenharmony_ci } 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci /* Sleep on a wait queue till the cond flag indicates that the 34518c2ecf20Sopenharmony_ci * response arrived or timed-out. 34528c2ecf20Sopenharmony_ci */ 34538c2ecf20Sopenharmony_ci retval = wait_for_sc_completion_timeout(octeon_dev, sc, 0); 34548c2ecf20Sopenharmony_ci if (retval) 34558c2ecf20Sopenharmony_ci return retval; 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci retval = resp->status; 34588c2ecf20Sopenharmony_ci if (retval) { 34598c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed\n"); 34608c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 34618c2ecf20Sopenharmony_ci goto setup_nic_dev_done; 34628c2ecf20Sopenharmony_ci } 34638c2ecf20Sopenharmony_ci snprintf(octeon_dev->fw_info.liquidio_firmware_version, 34648c2ecf20Sopenharmony_ci 32, "%s", 34658c2ecf20Sopenharmony_ci resp->cfg_info.liquidio_firmware_version); 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci /* Verify f/w version (in case of 'auto' loading from flash) */ 34688c2ecf20Sopenharmony_ci fw_ver = octeon_dev->fw_info.liquidio_firmware_version; 34698c2ecf20Sopenharmony_ci if (memcmp(LIQUIDIO_BASE_VERSION, 34708c2ecf20Sopenharmony_ci fw_ver, 34718c2ecf20Sopenharmony_ci strlen(LIQUIDIO_BASE_VERSION))) { 34728c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 34738c2ecf20Sopenharmony_ci "Unmatched firmware version. Expected %s.x, got %s.\n", 34748c2ecf20Sopenharmony_ci LIQUIDIO_BASE_VERSION, fw_ver); 34758c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 34768c2ecf20Sopenharmony_ci goto setup_nic_dev_done; 34778c2ecf20Sopenharmony_ci } else if (atomic_read(octeon_dev->adapter_fw_state) == 34788c2ecf20Sopenharmony_ci FW_IS_PRELOADED) { 34798c2ecf20Sopenharmony_ci dev_info(&octeon_dev->pci_dev->dev, 34808c2ecf20Sopenharmony_ci "Using auto-loaded firmware version %s.\n", 34818c2ecf20Sopenharmony_ci fw_ver); 34828c2ecf20Sopenharmony_ci } 34838c2ecf20Sopenharmony_ci 34848c2ecf20Sopenharmony_ci /* extract micro version field; point past '<maj>.<min>.' */ 34858c2ecf20Sopenharmony_ci micro_ver = fw_ver + strlen(LIQUIDIO_BASE_VERSION) + 1; 34868c2ecf20Sopenharmony_ci if (kstrtoul(micro_ver, 10, µ) != 0) 34878c2ecf20Sopenharmony_ci micro = 0; 34888c2ecf20Sopenharmony_ci octeon_dev->fw_info.ver.maj = LIQUIDIO_BASE_MAJOR_VERSION; 34898c2ecf20Sopenharmony_ci octeon_dev->fw_info.ver.min = LIQUIDIO_BASE_MINOR_VERSION; 34908c2ecf20Sopenharmony_ci octeon_dev->fw_info.ver.rev = micro; 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ci octeon_swap_8B_data((u64 *)(&resp->cfg_info), 34938c2ecf20Sopenharmony_ci (sizeof(struct liquidio_if_cfg_info)) >> 3); 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_ci num_iqueues = hweight64(resp->cfg_info.iqmask); 34968c2ecf20Sopenharmony_ci num_oqueues = hweight64(resp->cfg_info.oqmask); 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci if (!(num_iqueues) || !(num_oqueues)) { 34998c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 35008c2ecf20Sopenharmony_ci "Got bad iqueues (%016llx) or oqueues (%016llx) from firmware.\n", 35018c2ecf20Sopenharmony_ci resp->cfg_info.iqmask, 35028c2ecf20Sopenharmony_ci resp->cfg_info.oqmask); 35038c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 35048c2ecf20Sopenharmony_ci goto setup_nic_dev_done; 35058c2ecf20Sopenharmony_ci } 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_ci if (OCTEON_CN6XXX(octeon_dev)) { 35088c2ecf20Sopenharmony_ci max_num_queues = CFG_GET_IQ_MAX_Q(CHIP_CONF(octeon_dev, 35098c2ecf20Sopenharmony_ci cn6xxx)); 35108c2ecf20Sopenharmony_ci } else if (OCTEON_CN23XX_PF(octeon_dev)) { 35118c2ecf20Sopenharmony_ci max_num_queues = CFG_GET_IQ_MAX_Q(CHIP_CONF(octeon_dev, 35128c2ecf20Sopenharmony_ci cn23xx_pf)); 35138c2ecf20Sopenharmony_ci } 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, 35168c2ecf20Sopenharmony_ci "interface %d, iqmask %016llx, oqmask %016llx, numiqueues %d, numoqueues %d max_num_queues: %d\n", 35178c2ecf20Sopenharmony_ci i, resp->cfg_info.iqmask, resp->cfg_info.oqmask, 35188c2ecf20Sopenharmony_ci num_iqueues, num_oqueues, max_num_queues); 35198c2ecf20Sopenharmony_ci netdev = alloc_etherdev_mq(LIO_SIZE, max_num_queues); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci if (!netdev) { 35228c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Device allocation failed\n"); 35238c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 35248c2ecf20Sopenharmony_ci goto setup_nic_dev_done; 35258c2ecf20Sopenharmony_ci } 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &octeon_dev->pci_dev->dev); 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_ci /* Associate the routines that will handle different 35308c2ecf20Sopenharmony_ci * netdev tasks. 35318c2ecf20Sopenharmony_ci */ 35328c2ecf20Sopenharmony_ci netdev->netdev_ops = &lionetdevops; 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci retval = netif_set_real_num_rx_queues(netdev, num_oqueues); 35358c2ecf20Sopenharmony_ci if (retval) { 35368c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 35378c2ecf20Sopenharmony_ci "setting real number rx failed\n"); 35388c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 35398c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci retval = netif_set_real_num_tx_queues(netdev, num_iqueues); 35438c2ecf20Sopenharmony_ci if (retval) { 35448c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 35458c2ecf20Sopenharmony_ci "setting real number tx failed\n"); 35468c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 35478c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 35488c2ecf20Sopenharmony_ci } 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci lio = GET_LIO(netdev); 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci memset(lio, 0, sizeof(struct lio)); 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci lio->ifidx = ifidx_or_pfnum; 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_ci props = &octeon_dev->props[i]; 35578c2ecf20Sopenharmony_ci props->gmxport = resp->cfg_info.linfo.gmxport; 35588c2ecf20Sopenharmony_ci props->netdev = netdev; 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci lio->linfo.num_rxpciq = num_oqueues; 35618c2ecf20Sopenharmony_ci lio->linfo.num_txpciq = num_iqueues; 35628c2ecf20Sopenharmony_ci for (j = 0; j < num_oqueues; j++) { 35638c2ecf20Sopenharmony_ci lio->linfo.rxpciq[j].u64 = 35648c2ecf20Sopenharmony_ci resp->cfg_info.linfo.rxpciq[j].u64; 35658c2ecf20Sopenharmony_ci } 35668c2ecf20Sopenharmony_ci for (j = 0; j < num_iqueues; j++) { 35678c2ecf20Sopenharmony_ci lio->linfo.txpciq[j].u64 = 35688c2ecf20Sopenharmony_ci resp->cfg_info.linfo.txpciq[j].u64; 35698c2ecf20Sopenharmony_ci } 35708c2ecf20Sopenharmony_ci lio->linfo.hw_addr = resp->cfg_info.linfo.hw_addr; 35718c2ecf20Sopenharmony_ci lio->linfo.gmxport = resp->cfg_info.linfo.gmxport; 35728c2ecf20Sopenharmony_ci lio->linfo.link.u64 = resp->cfg_info.linfo.link.u64; 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci WRITE_ONCE(sc->caller_is_done, true); 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci lio->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(octeon_dev) || 35798c2ecf20Sopenharmony_ci OCTEON_CN6XXX(octeon_dev)) { 35808c2ecf20Sopenharmony_ci lio->dev_capability = NETIF_F_HIGHDMA 35818c2ecf20Sopenharmony_ci | NETIF_F_IP_CSUM 35828c2ecf20Sopenharmony_ci | NETIF_F_IPV6_CSUM 35838c2ecf20Sopenharmony_ci | NETIF_F_SG | NETIF_F_RXCSUM 35848c2ecf20Sopenharmony_ci | NETIF_F_GRO 35858c2ecf20Sopenharmony_ci | NETIF_F_TSO | NETIF_F_TSO6 35868c2ecf20Sopenharmony_ci | NETIF_F_LRO; 35878c2ecf20Sopenharmony_ci } 35888c2ecf20Sopenharmony_ci netif_set_gso_max_size(netdev, OCTNIC_GSO_MAX_SIZE); 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci /* Copy of transmit encapsulation capabilities: 35918c2ecf20Sopenharmony_ci * TSO, TSO6, Checksums for this device 35928c2ecf20Sopenharmony_ci */ 35938c2ecf20Sopenharmony_ci lio->enc_dev_capability = NETIF_F_IP_CSUM 35948c2ecf20Sopenharmony_ci | NETIF_F_IPV6_CSUM 35958c2ecf20Sopenharmony_ci | NETIF_F_GSO_UDP_TUNNEL 35968c2ecf20Sopenharmony_ci | NETIF_F_HW_CSUM | NETIF_F_SG 35978c2ecf20Sopenharmony_ci | NETIF_F_RXCSUM 35988c2ecf20Sopenharmony_ci | NETIF_F_TSO | NETIF_F_TSO6 35998c2ecf20Sopenharmony_ci | NETIF_F_LRO; 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci netdev->hw_enc_features = (lio->enc_dev_capability & 36028c2ecf20Sopenharmony_ci ~NETIF_F_LRO); 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_ci netdev->udp_tunnel_nic_info = &liquidio_udp_tunnels; 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci lio->dev_capability |= NETIF_F_GSO_UDP_TUNNEL; 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci netdev->vlan_features = lio->dev_capability; 36098c2ecf20Sopenharmony_ci /* Add any unchangeable hw features */ 36108c2ecf20Sopenharmony_ci lio->dev_capability |= NETIF_F_HW_VLAN_CTAG_FILTER | 36118c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 36128c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX; 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ci netdev->features = (lio->dev_capability & ~NETIF_F_LRO); 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci netdev->hw_features = lio->dev_capability; 36178c2ecf20Sopenharmony_ci /*HW_VLAN_RX and HW_VLAN_FILTER is always on*/ 36188c2ecf20Sopenharmony_ci netdev->hw_features = netdev->hw_features & 36198c2ecf20Sopenharmony_ci ~NETIF_F_HW_VLAN_CTAG_RX; 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci /* MTU range: 68 - 16000 */ 36228c2ecf20Sopenharmony_ci netdev->min_mtu = LIO_MIN_MTU_SIZE; 36238c2ecf20Sopenharmony_ci netdev->max_mtu = LIO_MAX_MTU_SIZE; 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_ci /* Point to the properties for octeon device to which this 36268c2ecf20Sopenharmony_ci * interface belongs. 36278c2ecf20Sopenharmony_ci */ 36288c2ecf20Sopenharmony_ci lio->oct_dev = octeon_dev; 36298c2ecf20Sopenharmony_ci lio->octprops = props; 36308c2ecf20Sopenharmony_ci lio->netdev = netdev; 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, 36338c2ecf20Sopenharmony_ci "if%d gmx: %d hw_addr: 0x%llx\n", i, 36348c2ecf20Sopenharmony_ci lio->linfo.gmxport, CVM_CAST64(lio->linfo.hw_addr)); 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci for (j = 0; j < octeon_dev->sriov_info.max_vfs; j++) { 36378c2ecf20Sopenharmony_ci u8 vfmac[ETH_ALEN]; 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci eth_random_addr(vfmac); 36408c2ecf20Sopenharmony_ci if (__liquidio_set_vf_mac(netdev, j, vfmac, false)) { 36418c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 36428c2ecf20Sopenharmony_ci "Error setting VF%d MAC address\n", 36438c2ecf20Sopenharmony_ci j); 36448c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 36458c2ecf20Sopenharmony_ci } 36468c2ecf20Sopenharmony_ci } 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci /* 64-bit swap required on LE machines */ 36498c2ecf20Sopenharmony_ci octeon_swap_8B_data(&lio->linfo.hw_addr, 1); 36508c2ecf20Sopenharmony_ci for (j = 0; j < 6; j++) 36518c2ecf20Sopenharmony_ci mac[j] = *((u8 *)(((u8 *)&lio->linfo.hw_addr) + 2 + j)); 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci /* Copy MAC Address to OS network device structure */ 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci ether_addr_copy(netdev->dev_addr, mac); 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci /* By default all interfaces on a single Octeon uses the same 36588c2ecf20Sopenharmony_ci * tx and rx queues 36598c2ecf20Sopenharmony_ci */ 36608c2ecf20Sopenharmony_ci lio->txq = lio->linfo.txpciq[0].s.q_no; 36618c2ecf20Sopenharmony_ci lio->rxq = lio->linfo.rxpciq[0].s.q_no; 36628c2ecf20Sopenharmony_ci if (liquidio_setup_io_queues(octeon_dev, i, 36638c2ecf20Sopenharmony_ci lio->linfo.num_txpciq, 36648c2ecf20Sopenharmony_ci lio->linfo.num_rxpciq)) { 36658c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "I/O queues creation failed\n"); 36668c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 36678c2ecf20Sopenharmony_ci } 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci ifstate_set(lio, LIO_IFSTATE_DROQ_OPS); 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci lio->tx_qsize = octeon_get_tx_qsize(octeon_dev, lio->txq); 36728c2ecf20Sopenharmony_ci lio->rx_qsize = octeon_get_rx_qsize(octeon_dev, lio->rxq); 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ci if (lio_setup_glists(octeon_dev, lio, num_iqueues)) { 36758c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 36768c2ecf20Sopenharmony_ci "Gather list allocation failed\n"); 36778c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 36788c2ecf20Sopenharmony_ci } 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci /* Register ethtool support */ 36818c2ecf20Sopenharmony_ci liquidio_set_ethtool_ops(netdev); 36828c2ecf20Sopenharmony_ci if (lio->oct_dev->chip_id == OCTEON_CN23XX_PF_VID) 36838c2ecf20Sopenharmony_ci octeon_dev->priv_flags = OCT_PRIV_FLAG_DEFAULT; 36848c2ecf20Sopenharmony_ci else 36858c2ecf20Sopenharmony_ci octeon_dev->priv_flags = 0x0; 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci if (netdev->features & NETIF_F_LRO) 36888c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE, 36898c2ecf20Sopenharmony_ci OCTNIC_LROIPV4 | OCTNIC_LROIPV6); 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, OCTNET_CMD_VLAN_FILTER_CTL, 36928c2ecf20Sopenharmony_ci OCTNET_CMD_VLAN_FILTER_ENABLE); 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci if ((debug != -1) && (debug & NETIF_MSG_HW)) 36958c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, 36968c2ecf20Sopenharmony_ci OCTNET_CMD_VERBOSE_ENABLE, 0); 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci if (setup_link_status_change_wq(netdev)) 36998c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci if ((octeon_dev->fw_info.app_cap_flags & 37028c2ecf20Sopenharmony_ci LIQUIDIO_TIME_SYNC_CAP) && 37038c2ecf20Sopenharmony_ci setup_sync_octeon_time_wq(netdev)) 37048c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci if (setup_rx_oom_poll_fn(netdev)) 37078c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci /* Register the network device with the OS */ 37108c2ecf20Sopenharmony_ci if (register_netdev(netdev)) { 37118c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n"); 37128c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 37138c2ecf20Sopenharmony_ci } 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, 37168c2ecf20Sopenharmony_ci "Setup NIC ifidx:%d mac:%02x%02x%02x%02x%02x%02x\n", 37178c2ecf20Sopenharmony_ci i, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 37188c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 37198c2ecf20Sopenharmony_ci lio->link_changes++; 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci ifstate_set(lio, LIO_IFSTATE_REGISTERED); 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci /* Sending command to firmware to enable Rx checksum offload 37248c2ecf20Sopenharmony_ci * by default at the time of setup of Liquidio driver for 37258c2ecf20Sopenharmony_ci * this device 37268c2ecf20Sopenharmony_ci */ 37278c2ecf20Sopenharmony_ci liquidio_set_rxcsum_command(netdev, OCTNET_CMD_TNL_RX_CSUM_CTL, 37288c2ecf20Sopenharmony_ci OCTNET_CMD_RXCSUM_ENABLE); 37298c2ecf20Sopenharmony_ci liquidio_set_feature(netdev, OCTNET_CMD_TNL_TX_CSUM_CTL, 37308c2ecf20Sopenharmony_ci OCTNET_CMD_TXCSUM_ENABLE); 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, 37338c2ecf20Sopenharmony_ci "NIC ifidx:%d Setup successful\n", i); 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci if (octeon_dev->subsystem_id == 37368c2ecf20Sopenharmony_ci OCTEON_CN2350_25GB_SUBSYS_ID || 37378c2ecf20Sopenharmony_ci octeon_dev->subsystem_id == 37388c2ecf20Sopenharmony_ci OCTEON_CN2360_25GB_SUBSYS_ID) { 37398c2ecf20Sopenharmony_ci cur_ver = OCT_FW_VER(octeon_dev->fw_info.ver.maj, 37408c2ecf20Sopenharmony_ci octeon_dev->fw_info.ver.min, 37418c2ecf20Sopenharmony_ci octeon_dev->fw_info.ver.rev); 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci /* speed control unsupported in f/w older than 1.7.2 */ 37448c2ecf20Sopenharmony_ci if (cur_ver < OCT_FW_VER(1, 7, 2)) { 37458c2ecf20Sopenharmony_ci dev_info(&octeon_dev->pci_dev->dev, 37468c2ecf20Sopenharmony_ci "speed setting not supported by f/w."); 37478c2ecf20Sopenharmony_ci octeon_dev->speed_setting = 25; 37488c2ecf20Sopenharmony_ci octeon_dev->no_speed_setting = 1; 37498c2ecf20Sopenharmony_ci } else { 37508c2ecf20Sopenharmony_ci liquidio_get_speed(lio); 37518c2ecf20Sopenharmony_ci } 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci if (octeon_dev->speed_setting == 0) { 37548c2ecf20Sopenharmony_ci octeon_dev->speed_setting = 25; 37558c2ecf20Sopenharmony_ci octeon_dev->no_speed_setting = 1; 37568c2ecf20Sopenharmony_ci } 37578c2ecf20Sopenharmony_ci } else { 37588c2ecf20Sopenharmony_ci octeon_dev->no_speed_setting = 1; 37598c2ecf20Sopenharmony_ci octeon_dev->speed_setting = 10; 37608c2ecf20Sopenharmony_ci } 37618c2ecf20Sopenharmony_ci octeon_dev->speed_boot = octeon_dev->speed_setting; 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_ci /* don't read FEC setting if unsupported by f/w (see above) */ 37648c2ecf20Sopenharmony_ci if (octeon_dev->speed_boot == 25 && 37658c2ecf20Sopenharmony_ci !octeon_dev->no_speed_setting) { 37668c2ecf20Sopenharmony_ci liquidio_get_fec(lio); 37678c2ecf20Sopenharmony_ci octeon_dev->props[lio->ifidx].fec_boot = 37688c2ecf20Sopenharmony_ci octeon_dev->props[lio->ifidx].fec; 37698c2ecf20Sopenharmony_ci } 37708c2ecf20Sopenharmony_ci } 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci devlink = devlink_alloc(&liquidio_devlink_ops, 37738c2ecf20Sopenharmony_ci sizeof(struct lio_devlink_priv)); 37748c2ecf20Sopenharmony_ci if (!devlink) { 37758c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "devlink alloc failed\n"); 37768c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 37778c2ecf20Sopenharmony_ci } 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci lio_devlink = devlink_priv(devlink); 37808c2ecf20Sopenharmony_ci lio_devlink->oct = octeon_dev; 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci if (devlink_register(devlink, &octeon_dev->pci_dev->dev)) { 37838c2ecf20Sopenharmony_ci devlink_free(devlink); 37848c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 37858c2ecf20Sopenharmony_ci "devlink registration failed\n"); 37868c2ecf20Sopenharmony_ci goto setup_nic_dev_free; 37878c2ecf20Sopenharmony_ci } 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci octeon_dev->devlink = devlink; 37908c2ecf20Sopenharmony_ci octeon_dev->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_ci return 0; 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_cisetup_nic_dev_free: 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci while (i--) { 37978c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 37988c2ecf20Sopenharmony_ci "NIC ifidx:%d Setup failed\n", i); 37998c2ecf20Sopenharmony_ci liquidio_destroy_nic_device(octeon_dev, i); 38008c2ecf20Sopenharmony_ci } 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_cisetup_nic_dev_done: 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci return -ENODEV; 38058c2ecf20Sopenharmony_ci} 38068c2ecf20Sopenharmony_ci 38078c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 38088c2ecf20Sopenharmony_cistatic int octeon_enable_sriov(struct octeon_device *oct) 38098c2ecf20Sopenharmony_ci{ 38108c2ecf20Sopenharmony_ci unsigned int num_vfs_alloced = oct->sriov_info.num_vfs_alloced; 38118c2ecf20Sopenharmony_ci struct pci_dev *vfdev; 38128c2ecf20Sopenharmony_ci int err; 38138c2ecf20Sopenharmony_ci u32 u; 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct) && num_vfs_alloced) { 38168c2ecf20Sopenharmony_ci err = pci_enable_sriov(oct->pci_dev, 38178c2ecf20Sopenharmony_ci oct->sriov_info.num_vfs_alloced); 38188c2ecf20Sopenharmony_ci if (err) { 38198c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 38208c2ecf20Sopenharmony_ci "OCTEON: Failed to enable PCI sriov: %d\n", 38218c2ecf20Sopenharmony_ci err); 38228c2ecf20Sopenharmony_ci oct->sriov_info.num_vfs_alloced = 0; 38238c2ecf20Sopenharmony_ci return err; 38248c2ecf20Sopenharmony_ci } 38258c2ecf20Sopenharmony_ci oct->sriov_info.sriov_enabled = 1; 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ci /* init lookup table that maps DPI ring number to VF pci_dev 38288c2ecf20Sopenharmony_ci * struct pointer 38298c2ecf20Sopenharmony_ci */ 38308c2ecf20Sopenharmony_ci u = 0; 38318c2ecf20Sopenharmony_ci vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, 38328c2ecf20Sopenharmony_ci OCTEON_CN23XX_VF_VID, NULL); 38338c2ecf20Sopenharmony_ci while (vfdev) { 38348c2ecf20Sopenharmony_ci if (vfdev->is_virtfn && 38358c2ecf20Sopenharmony_ci (vfdev->physfn == oct->pci_dev)) { 38368c2ecf20Sopenharmony_ci oct->sriov_info.dpiring_to_vfpcidev_lut[u] = 38378c2ecf20Sopenharmony_ci vfdev; 38388c2ecf20Sopenharmony_ci u += oct->sriov_info.rings_per_vf; 38398c2ecf20Sopenharmony_ci } 38408c2ecf20Sopenharmony_ci vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, 38418c2ecf20Sopenharmony_ci OCTEON_CN23XX_VF_VID, vfdev); 38428c2ecf20Sopenharmony_ci } 38438c2ecf20Sopenharmony_ci } 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci return num_vfs_alloced; 38468c2ecf20Sopenharmony_ci} 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_cistatic int lio_pci_sriov_disable(struct octeon_device *oct) 38498c2ecf20Sopenharmony_ci{ 38508c2ecf20Sopenharmony_ci int u; 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci if (pci_vfs_assigned(oct->pci_dev)) { 38538c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "VFs are still assigned to VMs.\n"); 38548c2ecf20Sopenharmony_ci return -EPERM; 38558c2ecf20Sopenharmony_ci } 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci pci_disable_sriov(oct->pci_dev); 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci u = 0; 38608c2ecf20Sopenharmony_ci while (u < MAX_POSSIBLE_VFS) { 38618c2ecf20Sopenharmony_ci oct->sriov_info.dpiring_to_vfpcidev_lut[u] = NULL; 38628c2ecf20Sopenharmony_ci u += oct->sriov_info.rings_per_vf; 38638c2ecf20Sopenharmony_ci } 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci oct->sriov_info.num_vfs_alloced = 0; 38668c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "oct->pf_num:%d disabled VFs\n", 38678c2ecf20Sopenharmony_ci oct->pf_num); 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci return 0; 38708c2ecf20Sopenharmony_ci} 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_cistatic int liquidio_enable_sriov(struct pci_dev *dev, int num_vfs) 38738c2ecf20Sopenharmony_ci{ 38748c2ecf20Sopenharmony_ci struct octeon_device *oct = pci_get_drvdata(dev); 38758c2ecf20Sopenharmony_ci int ret = 0; 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci if ((num_vfs == oct->sriov_info.num_vfs_alloced) && 38788c2ecf20Sopenharmony_ci (oct->sriov_info.sriov_enabled)) { 38798c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "oct->pf_num:%d already enabled num_vfs:%d\n", 38808c2ecf20Sopenharmony_ci oct->pf_num, num_vfs); 38818c2ecf20Sopenharmony_ci return 0; 38828c2ecf20Sopenharmony_ci } 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci if (!num_vfs) { 38858c2ecf20Sopenharmony_ci lio_vf_rep_destroy(oct); 38868c2ecf20Sopenharmony_ci ret = lio_pci_sriov_disable(oct); 38878c2ecf20Sopenharmony_ci } else if (num_vfs > oct->sriov_info.max_vfs) { 38888c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 38898c2ecf20Sopenharmony_ci "OCTEON: Max allowed VFs:%d user requested:%d", 38908c2ecf20Sopenharmony_ci oct->sriov_info.max_vfs, num_vfs); 38918c2ecf20Sopenharmony_ci ret = -EPERM; 38928c2ecf20Sopenharmony_ci } else { 38938c2ecf20Sopenharmony_ci oct->sriov_info.num_vfs_alloced = num_vfs; 38948c2ecf20Sopenharmony_ci ret = octeon_enable_sriov(oct); 38958c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "oct->pf_num:%d num_vfs:%d\n", 38968c2ecf20Sopenharmony_ci oct->pf_num, num_vfs); 38978c2ecf20Sopenharmony_ci ret = lio_vf_rep_create(oct); 38988c2ecf20Sopenharmony_ci if (ret) 38998c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, 39008c2ecf20Sopenharmony_ci "vf representor create failed"); 39018c2ecf20Sopenharmony_ci } 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci return ret; 39048c2ecf20Sopenharmony_ci} 39058c2ecf20Sopenharmony_ci#endif 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci/** 39088c2ecf20Sopenharmony_ci * liquidio_init_nic_module - initialize the NIC 39098c2ecf20Sopenharmony_ci * @oct: octeon device 39108c2ecf20Sopenharmony_ci * 39118c2ecf20Sopenharmony_ci * This initialization routine is called once the Octeon device application is 39128c2ecf20Sopenharmony_ci * up and running 39138c2ecf20Sopenharmony_ci */ 39148c2ecf20Sopenharmony_cistatic int liquidio_init_nic_module(struct octeon_device *oct) 39158c2ecf20Sopenharmony_ci{ 39168c2ecf20Sopenharmony_ci int i, retval = 0; 39178c2ecf20Sopenharmony_ci int num_nic_ports = CFG_GET_NUM_NIC_PORTS(octeon_get_conf(oct)); 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Initializing network interfaces\n"); 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci /* only default iq and oq were initialized 39228c2ecf20Sopenharmony_ci * initialize the rest as well 39238c2ecf20Sopenharmony_ci */ 39248c2ecf20Sopenharmony_ci /* run port_config command for each port */ 39258c2ecf20Sopenharmony_ci oct->ifcount = num_nic_ports; 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_ci memset(oct->props, 0, sizeof(struct octdev_props) * num_nic_ports); 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_LINKS; i++) 39308c2ecf20Sopenharmony_ci oct->props[i].gmxport = -1; 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci retval = setup_nic_devices(oct); 39338c2ecf20Sopenharmony_ci if (retval) { 39348c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Setup NIC devices failed\n"); 39358c2ecf20Sopenharmony_ci goto octnet_init_failure; 39368c2ecf20Sopenharmony_ci } 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci /* Call vf_rep_modinit if the firmware is switchdev capable 39398c2ecf20Sopenharmony_ci * and do it from the first liquidio function probed. 39408c2ecf20Sopenharmony_ci */ 39418c2ecf20Sopenharmony_ci if (!oct->octeon_id && 39428c2ecf20Sopenharmony_ci oct->fw_info.app_cap_flags & LIQUIDIO_SWITCHDEV_CAP) { 39438c2ecf20Sopenharmony_ci retval = lio_vf_rep_modinit(); 39448c2ecf20Sopenharmony_ci if (retval) { 39458c2ecf20Sopenharmony_ci liquidio_stop_nic_module(oct); 39468c2ecf20Sopenharmony_ci goto octnet_init_failure; 39478c2ecf20Sopenharmony_ci } 39488c2ecf20Sopenharmony_ci } 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci liquidio_ptp_init(oct); 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Network interfaces ready\n"); 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci return retval; 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_cioctnet_init_failure: 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_ci oct->ifcount = 0; 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_ci return retval; 39618c2ecf20Sopenharmony_ci} 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci/** 39648c2ecf20Sopenharmony_ci * nic_starter - finish init 39658c2ecf20Sopenharmony_ci * @work: work struct work_struct 39668c2ecf20Sopenharmony_ci * 39678c2ecf20Sopenharmony_ci * starter callback that invokes the remaining initialization work after the NIC is up and running. 39688c2ecf20Sopenharmony_ci */ 39698c2ecf20Sopenharmony_cistatic void nic_starter(struct work_struct *work) 39708c2ecf20Sopenharmony_ci{ 39718c2ecf20Sopenharmony_ci struct octeon_device *oct; 39728c2ecf20Sopenharmony_ci struct cavium_wk *wk = (struct cavium_wk *)work; 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci oct = (struct octeon_device *)wk->ctxptr; 39758c2ecf20Sopenharmony_ci 39768c2ecf20Sopenharmony_ci if (atomic_read(&oct->status) == OCT_DEV_RUNNING) 39778c2ecf20Sopenharmony_ci return; 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci /* If the status of the device is CORE_OK, the core 39808c2ecf20Sopenharmony_ci * application has reported its application type. Call 39818c2ecf20Sopenharmony_ci * any registered handlers now and move to the RUNNING 39828c2ecf20Sopenharmony_ci * state. 39838c2ecf20Sopenharmony_ci */ 39848c2ecf20Sopenharmony_ci if (atomic_read(&oct->status) != OCT_DEV_CORE_OK) { 39858c2ecf20Sopenharmony_ci schedule_delayed_work(&oct->nic_poll_work.work, 39868c2ecf20Sopenharmony_ci LIQUIDIO_STARTER_POLL_INTERVAL_MS); 39878c2ecf20Sopenharmony_ci return; 39888c2ecf20Sopenharmony_ci } 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci atomic_set(&oct->status, OCT_DEV_RUNNING); 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci if (oct->app_mode && oct->app_mode == CVM_DRV_NIC_APP) { 39938c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Starting NIC module\n"); 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci if (liquidio_init_nic_module(oct)) 39968c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "NIC initialization failed\n"); 39978c2ecf20Sopenharmony_ci else 39988c2ecf20Sopenharmony_ci handshake[oct->octeon_id].started_ok = 1; 39998c2ecf20Sopenharmony_ci } else { 40008c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 40018c2ecf20Sopenharmony_ci "Unexpected application running on NIC (%d). Check firmware.\n", 40028c2ecf20Sopenharmony_ci oct->app_mode); 40038c2ecf20Sopenharmony_ci } 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_ci complete(&handshake[oct->octeon_id].started); 40068c2ecf20Sopenharmony_ci} 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_cistatic int 40098c2ecf20Sopenharmony_ciocteon_recv_vf_drv_notice(struct octeon_recv_info *recv_info, void *buf) 40108c2ecf20Sopenharmony_ci{ 40118c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)buf; 40128c2ecf20Sopenharmony_ci struct octeon_recv_pkt *recv_pkt = recv_info->recv_pkt; 40138c2ecf20Sopenharmony_ci int i, notice, vf_idx; 40148c2ecf20Sopenharmony_ci bool cores_crashed; 40158c2ecf20Sopenharmony_ci u64 *data, vf_num; 40168c2ecf20Sopenharmony_ci 40178c2ecf20Sopenharmony_ci notice = recv_pkt->rh.r.ossp; 40188c2ecf20Sopenharmony_ci data = (u64 *)(get_rbd(recv_pkt->buffer_ptr[0]) + OCT_DROQ_INFO_SIZE); 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci /* the first 64-bit word of data is the vf_num */ 40218c2ecf20Sopenharmony_ci vf_num = data[0]; 40228c2ecf20Sopenharmony_ci octeon_swap_8B_data(&vf_num, 1); 40238c2ecf20Sopenharmony_ci vf_idx = (int)vf_num - 1; 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci cores_crashed = READ_ONCE(oct->cores_crashed); 40268c2ecf20Sopenharmony_ci 40278c2ecf20Sopenharmony_ci if (notice == VF_DRV_LOADED) { 40288c2ecf20Sopenharmony_ci if (!(oct->sriov_info.vf_drv_loaded_mask & BIT_ULL(vf_idx))) { 40298c2ecf20Sopenharmony_ci oct->sriov_info.vf_drv_loaded_mask |= BIT_ULL(vf_idx); 40308c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, 40318c2ecf20Sopenharmony_ci "driver for VF%d was loaded\n", vf_idx); 40328c2ecf20Sopenharmony_ci if (!cores_crashed) 40338c2ecf20Sopenharmony_ci try_module_get(THIS_MODULE); 40348c2ecf20Sopenharmony_ci } 40358c2ecf20Sopenharmony_ci } else if (notice == VF_DRV_REMOVED) { 40368c2ecf20Sopenharmony_ci if (oct->sriov_info.vf_drv_loaded_mask & BIT_ULL(vf_idx)) { 40378c2ecf20Sopenharmony_ci oct->sriov_info.vf_drv_loaded_mask &= ~BIT_ULL(vf_idx); 40388c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, 40398c2ecf20Sopenharmony_ci "driver for VF%d was removed\n", vf_idx); 40408c2ecf20Sopenharmony_ci if (!cores_crashed) 40418c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 40428c2ecf20Sopenharmony_ci } 40438c2ecf20Sopenharmony_ci } else if (notice == VF_DRV_MACADDR_CHANGED) { 40448c2ecf20Sopenharmony_ci u8 *b = (u8 *)&data[1]; 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci oct->sriov_info.vf_macaddr[vf_idx] = data[1]; 40478c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, 40488c2ecf20Sopenharmony_ci "VF driver changed VF%d's MAC address to %pM\n", 40498c2ecf20Sopenharmony_ci vf_idx, b + 2); 40508c2ecf20Sopenharmony_ci } 40518c2ecf20Sopenharmony_ci 40528c2ecf20Sopenharmony_ci for (i = 0; i < recv_pkt->buffer_count; i++) 40538c2ecf20Sopenharmony_ci recv_buffer_free(recv_pkt->buffer_ptr[i]); 40548c2ecf20Sopenharmony_ci octeon_free_recv_info(recv_info); 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci return 0; 40578c2ecf20Sopenharmony_ci} 40588c2ecf20Sopenharmony_ci 40598c2ecf20Sopenharmony_ci/** 40608c2ecf20Sopenharmony_ci * octeon_device_init - Device initialization for each Octeon device that is probed 40618c2ecf20Sopenharmony_ci * @octeon_dev: octeon device 40628c2ecf20Sopenharmony_ci */ 40638c2ecf20Sopenharmony_cistatic int octeon_device_init(struct octeon_device *octeon_dev) 40648c2ecf20Sopenharmony_ci{ 40658c2ecf20Sopenharmony_ci int j, ret; 40668c2ecf20Sopenharmony_ci char bootcmd[] = "\n"; 40678c2ecf20Sopenharmony_ci char *dbg_enb = NULL; 40688c2ecf20Sopenharmony_ci enum lio_fw_state fw_state; 40698c2ecf20Sopenharmony_ci struct octeon_device_priv *oct_priv = 40708c2ecf20Sopenharmony_ci (struct octeon_device_priv *)octeon_dev->priv; 40718c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_BEGIN_STATE); 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci /* Enable access to the octeon device and make its DMA capability 40748c2ecf20Sopenharmony_ci * known to the OS. 40758c2ecf20Sopenharmony_ci */ 40768c2ecf20Sopenharmony_ci if (octeon_pci_os_setup(octeon_dev)) 40778c2ecf20Sopenharmony_ci return 1; 40788c2ecf20Sopenharmony_ci 40798c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_PCI_ENABLE_DONE); 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci /* Identify the Octeon type and map the BAR address space. */ 40828c2ecf20Sopenharmony_ci if (octeon_chip_specific_setup(octeon_dev)) { 40838c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Chip specific setup failed\n"); 40848c2ecf20Sopenharmony_ci return 1; 40858c2ecf20Sopenharmony_ci } 40868c2ecf20Sopenharmony_ci 40878c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_PCI_MAP_DONE); 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ci /* Only add a reference after setting status 'OCT_DEV_PCI_MAP_DONE', 40908c2ecf20Sopenharmony_ci * since that is what is required for the reference to be removed 40918c2ecf20Sopenharmony_ci * during de-initialization (see 'octeon_destroy_resources'). 40928c2ecf20Sopenharmony_ci */ 40938c2ecf20Sopenharmony_ci octeon_register_device(octeon_dev, octeon_dev->pci_dev->bus->number, 40948c2ecf20Sopenharmony_ci PCI_SLOT(octeon_dev->pci_dev->devfn), 40958c2ecf20Sopenharmony_ci PCI_FUNC(octeon_dev->pci_dev->devfn), 40968c2ecf20Sopenharmony_ci true); 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci octeon_dev->app_mode = CVM_DRV_INVALID_APP; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci /* CN23XX supports preloaded firmware if the following is true: 41018c2ecf20Sopenharmony_ci * 41028c2ecf20Sopenharmony_ci * The adapter indicates that firmware is currently running AND 41038c2ecf20Sopenharmony_ci * 'fw_type' is 'auto'. 41048c2ecf20Sopenharmony_ci * 41058c2ecf20Sopenharmony_ci * (default state is NEEDS_TO_BE_LOADED, override it if appropriate). 41068c2ecf20Sopenharmony_ci */ 41078c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(octeon_dev) && 41088c2ecf20Sopenharmony_ci cn23xx_fw_loaded(octeon_dev) && fw_type_is_auto()) { 41098c2ecf20Sopenharmony_ci atomic_cmpxchg(octeon_dev->adapter_fw_state, 41108c2ecf20Sopenharmony_ci FW_NEEDS_TO_BE_LOADED, FW_IS_PRELOADED); 41118c2ecf20Sopenharmony_ci } 41128c2ecf20Sopenharmony_ci 41138c2ecf20Sopenharmony_ci /* If loading firmware, only first device of adapter needs to do so. */ 41148c2ecf20Sopenharmony_ci fw_state = atomic_cmpxchg(octeon_dev->adapter_fw_state, 41158c2ecf20Sopenharmony_ci FW_NEEDS_TO_BE_LOADED, 41168c2ecf20Sopenharmony_ci FW_IS_BEING_LOADED); 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ci /* Here, [local variable] 'fw_state' is set to one of: 41198c2ecf20Sopenharmony_ci * 41208c2ecf20Sopenharmony_ci * FW_IS_PRELOADED: No firmware is to be loaded (see above) 41218c2ecf20Sopenharmony_ci * FW_NEEDS_TO_BE_LOADED: The driver's first instance will load 41228c2ecf20Sopenharmony_ci * firmware to the adapter. 41238c2ecf20Sopenharmony_ci * FW_IS_BEING_LOADED: The driver's second instance will not load 41248c2ecf20Sopenharmony_ci * firmware to the adapter. 41258c2ecf20Sopenharmony_ci */ 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_ci /* Prior to f/w load, perform a soft reset of the Octeon device; 41288c2ecf20Sopenharmony_ci * if error resetting, return w/error. 41298c2ecf20Sopenharmony_ci */ 41308c2ecf20Sopenharmony_ci if (fw_state == FW_NEEDS_TO_BE_LOADED) 41318c2ecf20Sopenharmony_ci if (octeon_dev->fn_list.soft_reset(octeon_dev)) 41328c2ecf20Sopenharmony_ci return 1; 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci /* Initialize the dispatch mechanism used to push packets arriving on 41358c2ecf20Sopenharmony_ci * Octeon Output queues. 41368c2ecf20Sopenharmony_ci */ 41378c2ecf20Sopenharmony_ci if (octeon_init_dispatch_list(octeon_dev)) 41388c2ecf20Sopenharmony_ci return 1; 41398c2ecf20Sopenharmony_ci 41408c2ecf20Sopenharmony_ci octeon_register_dispatch_fn(octeon_dev, OPCODE_NIC, 41418c2ecf20Sopenharmony_ci OPCODE_NIC_CORE_DRV_ACTIVE, 41428c2ecf20Sopenharmony_ci octeon_core_drv_init, 41438c2ecf20Sopenharmony_ci octeon_dev); 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci octeon_register_dispatch_fn(octeon_dev, OPCODE_NIC, 41468c2ecf20Sopenharmony_ci OPCODE_NIC_VF_DRV_NOTICE, 41478c2ecf20Sopenharmony_ci octeon_recv_vf_drv_notice, octeon_dev); 41488c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&octeon_dev->nic_poll_work.work, nic_starter); 41498c2ecf20Sopenharmony_ci octeon_dev->nic_poll_work.ctxptr = (void *)octeon_dev; 41508c2ecf20Sopenharmony_ci schedule_delayed_work(&octeon_dev->nic_poll_work.work, 41518c2ecf20Sopenharmony_ci LIQUIDIO_STARTER_POLL_INTERVAL_MS); 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_DISPATCH_INIT_DONE); 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci if (octeon_set_io_queues_off(octeon_dev)) { 41568c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "setting io queues off failed\n"); 41578c2ecf20Sopenharmony_ci return 1; 41588c2ecf20Sopenharmony_ci } 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(octeon_dev)) { 41618c2ecf20Sopenharmony_ci ret = octeon_dev->fn_list.setup_device_regs(octeon_dev); 41628c2ecf20Sopenharmony_ci if (ret) { 41638c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "OCTEON: Failed to configure device registers\n"); 41648c2ecf20Sopenharmony_ci return ret; 41658c2ecf20Sopenharmony_ci } 41668c2ecf20Sopenharmony_ci } 41678c2ecf20Sopenharmony_ci 41688c2ecf20Sopenharmony_ci /* Initialize soft command buffer pool 41698c2ecf20Sopenharmony_ci */ 41708c2ecf20Sopenharmony_ci if (octeon_setup_sc_buffer_pool(octeon_dev)) { 41718c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "sc buffer pool allocation failed\n"); 41728c2ecf20Sopenharmony_ci return 1; 41738c2ecf20Sopenharmony_ci } 41748c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_SC_BUFF_POOL_INIT_DONE); 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci /* Setup the data structures that manage this Octeon's Input queues. */ 41778c2ecf20Sopenharmony_ci if (octeon_setup_instr_queues(octeon_dev)) { 41788c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 41798c2ecf20Sopenharmony_ci "instruction queue initialization failed\n"); 41808c2ecf20Sopenharmony_ci return 1; 41818c2ecf20Sopenharmony_ci } 41828c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_INSTR_QUEUE_INIT_DONE); 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci /* Initialize lists to manage the requests of different types that 41858c2ecf20Sopenharmony_ci * arrive from user & kernel applications for this octeon device. 41868c2ecf20Sopenharmony_ci */ 41878c2ecf20Sopenharmony_ci if (octeon_setup_response_list(octeon_dev)) { 41888c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Response list allocation failed\n"); 41898c2ecf20Sopenharmony_ci return 1; 41908c2ecf20Sopenharmony_ci } 41918c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_RESP_LIST_INIT_DONE); 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci if (octeon_setup_output_queues(octeon_dev)) { 41948c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Output queue initialization failed\n"); 41958c2ecf20Sopenharmony_ci return 1; 41968c2ecf20Sopenharmony_ci } 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_DROQ_INIT_DONE); 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(octeon_dev)) { 42018c2ecf20Sopenharmony_ci if (octeon_dev->fn_list.setup_mbox(octeon_dev)) { 42028c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "OCTEON: Mailbox setup failed\n"); 42038c2ecf20Sopenharmony_ci return 1; 42048c2ecf20Sopenharmony_ci } 42058c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_MBOX_SETUP_DONE); 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci if (octeon_allocate_ioq_vector 42088c2ecf20Sopenharmony_ci (octeon_dev, 42098c2ecf20Sopenharmony_ci octeon_dev->sriov_info.num_pf_rings)) { 42108c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "OCTEON: ioq vector allocation failed\n"); 42118c2ecf20Sopenharmony_ci return 1; 42128c2ecf20Sopenharmony_ci } 42138c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_MSIX_ALLOC_VECTOR_DONE); 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci } else { 42168c2ecf20Sopenharmony_ci /* The input and output queue registers were setup earlier (the 42178c2ecf20Sopenharmony_ci * queues were not enabled). Any additional registers 42188c2ecf20Sopenharmony_ci * that need to be programmed should be done now. 42198c2ecf20Sopenharmony_ci */ 42208c2ecf20Sopenharmony_ci ret = octeon_dev->fn_list.setup_device_regs(octeon_dev); 42218c2ecf20Sopenharmony_ci if (ret) { 42228c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 42238c2ecf20Sopenharmony_ci "Failed to configure device registers\n"); 42248c2ecf20Sopenharmony_ci return ret; 42258c2ecf20Sopenharmony_ci } 42268c2ecf20Sopenharmony_ci } 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_ci /* Initialize the tasklet that handles output queue packet processing.*/ 42298c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, "Initializing droq tasklet\n"); 42308c2ecf20Sopenharmony_ci tasklet_setup(&oct_priv->droq_tasklet, octeon_droq_bh); 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci /* Setup the interrupt handler and record the INT SUM register address 42338c2ecf20Sopenharmony_ci */ 42348c2ecf20Sopenharmony_ci if (octeon_setup_interrupt(octeon_dev, 42358c2ecf20Sopenharmony_ci octeon_dev->sriov_info.num_pf_rings)) 42368c2ecf20Sopenharmony_ci return 1; 42378c2ecf20Sopenharmony_ci 42388c2ecf20Sopenharmony_ci /* Enable Octeon device interrupts */ 42398c2ecf20Sopenharmony_ci octeon_dev->fn_list.enable_interrupt(octeon_dev, OCTEON_ALL_INTR); 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_INTR_SET_DONE); 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_ci /* Send Credit for Octeon Output queues. Credits are always sent BEFORE 42448c2ecf20Sopenharmony_ci * the output queue is enabled. 42458c2ecf20Sopenharmony_ci * This ensures that we'll receive the f/w CORE DRV_ACTIVE message in 42468c2ecf20Sopenharmony_ci * case we've configured CN23XX_SLI_GBL_CONTROL[NOPTR_D] = 0. 42478c2ecf20Sopenharmony_ci * Otherwise, it is possible that the DRV_ACTIVE message will be sent 42488c2ecf20Sopenharmony_ci * before any credits have been issued, causing the ring to be reset 42498c2ecf20Sopenharmony_ci * (and the f/w appear to never have started). 42508c2ecf20Sopenharmony_ci */ 42518c2ecf20Sopenharmony_ci for (j = 0; j < octeon_dev->num_oqs; j++) 42528c2ecf20Sopenharmony_ci writel(octeon_dev->droq[j]->max_count, 42538c2ecf20Sopenharmony_ci octeon_dev->droq[j]->pkts_credit_reg); 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci /* Enable the input and output queues for this Octeon device */ 42568c2ecf20Sopenharmony_ci ret = octeon_dev->fn_list.enable_io_queues(octeon_dev); 42578c2ecf20Sopenharmony_ci if (ret) { 42588c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Failed to enable input/output queues"); 42598c2ecf20Sopenharmony_ci return ret; 42608c2ecf20Sopenharmony_ci } 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_IO_QUEUES_DONE); 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_ci if (fw_state == FW_NEEDS_TO_BE_LOADED) { 42658c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, "Waiting for DDR initialization...\n"); 42668c2ecf20Sopenharmony_ci if (!ddr_timeout) { 42678c2ecf20Sopenharmony_ci dev_info(&octeon_dev->pci_dev->dev, 42688c2ecf20Sopenharmony_ci "WAITING. Set ddr_timeout to non-zero value to proceed with initialization.\n"); 42698c2ecf20Sopenharmony_ci } 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(HZ * LIO_RESET_SECS); 42728c2ecf20Sopenharmony_ci 42738c2ecf20Sopenharmony_ci /* Wait for the octeon to initialize DDR after the soft-reset.*/ 42748c2ecf20Sopenharmony_ci while (!ddr_timeout) { 42758c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 42768c2ecf20Sopenharmony_ci if (schedule_timeout(HZ / 10)) { 42778c2ecf20Sopenharmony_ci /* user probably pressed Control-C */ 42788c2ecf20Sopenharmony_ci return 1; 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci } 42818c2ecf20Sopenharmony_ci ret = octeon_wait_for_ddr_init(octeon_dev, &ddr_timeout); 42828c2ecf20Sopenharmony_ci if (ret) { 42838c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, 42848c2ecf20Sopenharmony_ci "DDR not initialized. Please confirm that board is configured to boot from Flash, ret: %d\n", 42858c2ecf20Sopenharmony_ci ret); 42868c2ecf20Sopenharmony_ci return 1; 42878c2ecf20Sopenharmony_ci } 42888c2ecf20Sopenharmony_ci 42898c2ecf20Sopenharmony_ci if (octeon_wait_for_bootloader(octeon_dev, 1000)) { 42908c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Board not responding\n"); 42918c2ecf20Sopenharmony_ci return 1; 42928c2ecf20Sopenharmony_ci } 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ci /* Divert uboot to take commands from host instead. */ 42958c2ecf20Sopenharmony_ci ret = octeon_console_send_cmd(octeon_dev, bootcmd, 50); 42968c2ecf20Sopenharmony_ci 42978c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, "Initializing consoles\n"); 42988c2ecf20Sopenharmony_ci ret = octeon_init_consoles(octeon_dev); 42998c2ecf20Sopenharmony_ci if (ret) { 43008c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Could not access board consoles\n"); 43018c2ecf20Sopenharmony_ci return 1; 43028c2ecf20Sopenharmony_ci } 43038c2ecf20Sopenharmony_ci /* If console debug enabled, specify empty string to use default 43048c2ecf20Sopenharmony_ci * enablement ELSE specify NULL string for 'disabled'. 43058c2ecf20Sopenharmony_ci */ 43068c2ecf20Sopenharmony_ci dbg_enb = octeon_console_debug_enabled(0) ? "" : NULL; 43078c2ecf20Sopenharmony_ci ret = octeon_add_console(octeon_dev, 0, dbg_enb); 43088c2ecf20Sopenharmony_ci if (ret) { 43098c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Could not access board console\n"); 43108c2ecf20Sopenharmony_ci return 1; 43118c2ecf20Sopenharmony_ci } else if (octeon_console_debug_enabled(0)) { 43128c2ecf20Sopenharmony_ci /* If console was added AND we're logging console output 43138c2ecf20Sopenharmony_ci * then set our console print function. 43148c2ecf20Sopenharmony_ci */ 43158c2ecf20Sopenharmony_ci octeon_dev->console[0].print = octeon_dbg_console_print; 43168c2ecf20Sopenharmony_ci } 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_CONSOLE_INIT_DONE); 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci dev_dbg(&octeon_dev->pci_dev->dev, "Loading firmware\n"); 43218c2ecf20Sopenharmony_ci ret = load_firmware(octeon_dev); 43228c2ecf20Sopenharmony_ci if (ret) { 43238c2ecf20Sopenharmony_ci dev_err(&octeon_dev->pci_dev->dev, "Could not load firmware to board\n"); 43248c2ecf20Sopenharmony_ci return 1; 43258c2ecf20Sopenharmony_ci } 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci atomic_set(octeon_dev->adapter_fw_state, FW_HAS_BEEN_LOADED); 43288c2ecf20Sopenharmony_ci } 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_ci handshake[octeon_dev->octeon_id].init_ok = 1; 43318c2ecf20Sopenharmony_ci complete(&handshake[octeon_dev->octeon_id].init); 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_ci atomic_set(&octeon_dev->status, OCT_DEV_HOST_OK); 43348c2ecf20Sopenharmony_ci oct_priv->dev = octeon_dev; 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci return 0; 43378c2ecf20Sopenharmony_ci} 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci/** 43408c2ecf20Sopenharmony_ci * octeon_dbg_console_print - Debug console print function 43418c2ecf20Sopenharmony_ci * @oct: octeon device 43428c2ecf20Sopenharmony_ci * @console_num: console number 43438c2ecf20Sopenharmony_ci * @prefix: first portion of line to display 43448c2ecf20Sopenharmony_ci * @suffix: second portion of line to display 43458c2ecf20Sopenharmony_ci * 43468c2ecf20Sopenharmony_ci * The OCTEON debug console outputs entire lines (excluding '\n'). 43478c2ecf20Sopenharmony_ci * Normally, the line will be passed in the 'prefix' parameter. 43488c2ecf20Sopenharmony_ci * However, due to buffering, it is possible for a line to be split into two 43498c2ecf20Sopenharmony_ci * parts, in which case they will be passed as the 'prefix' parameter and 43508c2ecf20Sopenharmony_ci * 'suffix' parameter. 43518c2ecf20Sopenharmony_ci */ 43528c2ecf20Sopenharmony_cistatic int octeon_dbg_console_print(struct octeon_device *oct, u32 console_num, 43538c2ecf20Sopenharmony_ci char *prefix, char *suffix) 43548c2ecf20Sopenharmony_ci{ 43558c2ecf20Sopenharmony_ci if (prefix && suffix) 43568c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "%u: %s%s\n", console_num, prefix, 43578c2ecf20Sopenharmony_ci suffix); 43588c2ecf20Sopenharmony_ci else if (prefix) 43598c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "%u: %s\n", console_num, prefix); 43608c2ecf20Sopenharmony_ci else if (suffix) 43618c2ecf20Sopenharmony_ci dev_info(&oct->pci_dev->dev, "%u: %s\n", console_num, suffix); 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_ci return 0; 43648c2ecf20Sopenharmony_ci} 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci/** 43678c2ecf20Sopenharmony_ci * liquidio_exit - Exits the module 43688c2ecf20Sopenharmony_ci */ 43698c2ecf20Sopenharmony_cistatic void __exit liquidio_exit(void) 43708c2ecf20Sopenharmony_ci{ 43718c2ecf20Sopenharmony_ci liquidio_deinit_pci(); 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci pr_info("LiquidIO network module is now unloaded\n"); 43748c2ecf20Sopenharmony_ci} 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_cimodule_init(liquidio_init); 43778c2ecf20Sopenharmony_cimodule_exit(liquidio_exit); 4378