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/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 208c2ecf20Sopenharmony_ci#include "liquidio_common.h" 218c2ecf20Sopenharmony_ci#include "octeon_droq.h" 228c2ecf20Sopenharmony_ci#include "octeon_iq.h" 238c2ecf20Sopenharmony_ci#include "response_manager.h" 248c2ecf20Sopenharmony_ci#include "octeon_device.h" 258c2ecf20Sopenharmony_ci#include "octeon_main.h" 268c2ecf20Sopenharmony_ci#include "cn66xx_regs.h" 278c2ecf20Sopenharmony_ci#include "cn66xx_device.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciint lio_cn6xxx_soft_reset(struct octeon_device *oct) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_WIN_WR_MASK_REG, 0xFF); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "BIST enabled for soft reset\n"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci lio_pci_writeq(oct, 1, CN6XXX_CIU_SOFT_BIST); 368c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_SCRATCH1, 0x1234ULL); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci lio_pci_readq(oct, CN6XXX_CIU_SOFT_RST); 398c2ecf20Sopenharmony_ci lio_pci_writeq(oct, 1, CN6XXX_CIU_SOFT_RST); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* Wait for 10ms as Octeon resets. */ 428c2ecf20Sopenharmony_ci mdelay(100); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (octeon_read_csr64(oct, CN6XXX_SLI_SCRATCH1)) { 458c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Soft reset failed\n"); 468c2ecf20Sopenharmony_ci return 1; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Reset completed\n"); 508c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_WIN_WR_MASK_REG, 0xFF); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_civoid lio_cn6xxx_enable_error_reporting(struct octeon_device *oct) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci u32 val; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci pci_read_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, &val); 608c2ecf20Sopenharmony_ci if (val & 0x000c0000) { 618c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "PCI-E Link error detected: 0x%08x\n", 628c2ecf20Sopenharmony_ci val & 0x000c0000); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci val |= 0xf; /* Enable Link error reporting */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Enabling PCI-E error reporting..\n"); 688c2ecf20Sopenharmony_ci pci_write_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, val); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_civoid lio_cn6xxx_setup_pcie_mps(struct octeon_device *oct, 728c2ecf20Sopenharmony_ci enum octeon_pcie_mps mps) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 val; 758c2ecf20Sopenharmony_ci u64 r64; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Read config register for MPS */ 788c2ecf20Sopenharmony_ci pci_read_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, &val); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (mps == PCIE_MPS_DEFAULT) { 818c2ecf20Sopenharmony_ci mps = ((val & (0x7 << 5)) >> 5); 828c2ecf20Sopenharmony_ci } else { 838c2ecf20Sopenharmony_ci val &= ~(0x7 << 5); /* Turn off any MPS bits */ 848c2ecf20Sopenharmony_ci val |= (mps << 5); /* Set MPS */ 858c2ecf20Sopenharmony_ci pci_write_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, val); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Set MPS in DPI_SLI_PRT0_CFG to the same value. */ 898c2ecf20Sopenharmony_ci r64 = lio_pci_readq(oct, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port)); 908c2ecf20Sopenharmony_ci r64 |= (mps << 4); 918c2ecf20Sopenharmony_ci lio_pci_writeq(oct, r64, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port)); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_civoid lio_cn6xxx_setup_pcie_mrrs(struct octeon_device *oct, 958c2ecf20Sopenharmony_ci enum octeon_pcie_mrrs mrrs) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci u32 val; 988c2ecf20Sopenharmony_ci u64 r64; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Read config register for MRRS */ 1018c2ecf20Sopenharmony_ci pci_read_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, &val); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (mrrs == PCIE_MRRS_DEFAULT) { 1048c2ecf20Sopenharmony_ci mrrs = ((val & (0x7 << 12)) >> 12); 1058c2ecf20Sopenharmony_ci } else { 1068c2ecf20Sopenharmony_ci val &= ~(0x7 << 12); /* Turn off any MRRS bits */ 1078c2ecf20Sopenharmony_ci val |= (mrrs << 12); /* Set MRRS */ 1088c2ecf20Sopenharmony_ci pci_write_config_dword(oct->pci_dev, CN6XXX_PCIE_DEVCTL, val); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Set MRRS in SLI_S2M_PORT0_CTL to the same value. */ 1128c2ecf20Sopenharmony_ci r64 = octeon_read_csr64(oct, CN6XXX_SLI_S2M_PORTX_CTL(oct->pcie_port)); 1138c2ecf20Sopenharmony_ci r64 |= mrrs; 1148c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_S2M_PORTX_CTL(oct->pcie_port), r64); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* Set MRRS in DPI_SLI_PRT0_CFG to the same value. */ 1178c2ecf20Sopenharmony_ci r64 = lio_pci_readq(oct, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port)); 1188c2ecf20Sopenharmony_ci r64 |= mrrs; 1198c2ecf20Sopenharmony_ci lio_pci_writeq(oct, r64, CN6XXX_DPI_SLI_PRTX_CFG(oct->pcie_port)); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciu32 lio_cn6xxx_coprocessor_clock(struct octeon_device *oct) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci /* Bits 29:24 of MIO_RST_BOOT holds the ref. clock multiplier 1258c2ecf20Sopenharmony_ci * for SLI. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci return ((lio_pci_readq(oct, CN6XXX_MIO_RST_BOOT) >> 24) & 0x3f) * 50; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciu32 lio_cn6xxx_get_oq_ticks(struct octeon_device *oct, 1318c2ecf20Sopenharmony_ci u32 time_intr_in_us) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci /* This gives the SLI clock per microsec */ 1348c2ecf20Sopenharmony_ci u32 oqticks_per_us = lio_cn6xxx_coprocessor_clock(oct); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* core clock per us / oq ticks will be fractional. TO avoid that 1378c2ecf20Sopenharmony_ci * we use the method below. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* This gives the clock cycles per millisecond */ 1418c2ecf20Sopenharmony_ci oqticks_per_us *= 1000; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* This gives the oq ticks (1024 core clock cycles) per millisecond */ 1448c2ecf20Sopenharmony_ci oqticks_per_us /= 1024; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* time_intr is in microseconds. The next 2 steps gives the oq ticks 1478c2ecf20Sopenharmony_ci * corressponding to time_intr. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci oqticks_per_us *= time_intr_in_us; 1508c2ecf20Sopenharmony_ci oqticks_per_us /= 1000; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return oqticks_per_us; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_civoid lio_cn6xxx_setup_global_input_regs(struct octeon_device *oct) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci /* Select Round-Robin Arb, ES, RO, NS for Input Queues */ 1588c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_INPUT_CONTROL, 1598c2ecf20Sopenharmony_ci CN6XXX_INPUT_CTL_MASK); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Instruction Read Size - Max 4 instructions per PCIE Read */ 1628c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_PKT_INSTR_RD_SIZE, 1638c2ecf20Sopenharmony_ci 0xFFFFFFFFFFFFFFFFULL); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Select PCIE Port for all Input rings. */ 1668c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_IN_PCIE_PORT, 1678c2ecf20Sopenharmony_ci (oct->pcie_port * 0x5555555555555555ULL)); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic void lio_cn66xx_setup_pkt_ctl_regs(struct octeon_device *oct) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci u64 pktctl; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci pktctl = octeon_read_csr64(oct, CN6XXX_SLI_PKT_CTL); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* 66XX SPECIFIC */ 1798c2ecf20Sopenharmony_ci if (CFG_GET_OQ_MAX_Q(cn6xxx->conf) <= 4) 1808c2ecf20Sopenharmony_ci /* Disable RING_EN if only upto 4 rings are used. */ 1818c2ecf20Sopenharmony_ci pktctl &= ~(1 << 4); 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci pktctl |= (1 << 4); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (CFG_GET_IS_SLI_BP_ON(cn6xxx->conf)) 1868c2ecf20Sopenharmony_ci pktctl |= 0xF; 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci /* Disable per-port backpressure. */ 1898c2ecf20Sopenharmony_ci pktctl &= ~0xF; 1908c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_PKT_CTL, pktctl); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_civoid lio_cn6xxx_setup_global_output_regs(struct octeon_device *oct) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u32 time_threshold; 1968c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* / Select PCI-E Port for all Output queues */ 1998c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_PKT_PCIE_PORT64, 2008c2ecf20Sopenharmony_ci (oct->pcie_port * 0x5555555555555555ULL)); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (CFG_GET_IS_SLI_BP_ON(cn6xxx->conf)) { 2038c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_OQ_WMARK, 32); 2048c2ecf20Sopenharmony_ci } else { 2058c2ecf20Sopenharmony_ci /* / Set Output queue watermark to 0 to disable backpressure */ 2068c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_OQ_WMARK, 0); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* / Select Packet count instead of bytes for SLI_PKTi_CNTS[CNT] */ 2108c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_BMODE, 0); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* Select ES, RO, NS setting from register for Output Queue Packet 2138c2ecf20Sopenharmony_ci * Address 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_DPADDR, 0xFFFFFFFF); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* No Relaxed Ordering, No Snoop, 64-bit swap for Output 2188c2ecf20Sopenharmony_ci * Queue ScatterList 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_SLIST_ROR, 0); 2218c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_SLIST_NS, 0); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* / ENDIAN_SPECIFIC CHANGES - 0 works for LE. */ 2248c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN_BITFIELD 2258c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_PKT_SLIST_ES64, 2268c2ecf20Sopenharmony_ci 0x5555555555555555ULL); 2278c2ecf20Sopenharmony_ci#else 2288c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_PKT_SLIST_ES64, 0ULL); 2298c2ecf20Sopenharmony_ci#endif 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* / No Relaxed Ordering, No Snoop, 64-bit swap for Output Queue Data */ 2328c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_DATA_OUT_ROR, 0); 2338c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_DATA_OUT_NS, 0); 2348c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_PKT_DATA_OUT_ES64, 2358c2ecf20Sopenharmony_ci 0x5555555555555555ULL); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* / Set up interrupt packet and time threshold */ 2388c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_OQ_INT_LEVEL_PKTS, 2398c2ecf20Sopenharmony_ci (u32)CFG_GET_OQ_INTR_PKT(cn6xxx->conf)); 2408c2ecf20Sopenharmony_ci time_threshold = 2418c2ecf20Sopenharmony_ci lio_cn6xxx_get_oq_ticks(oct, (u32) 2428c2ecf20Sopenharmony_ci CFG_GET_OQ_INTR_TIME(cn6xxx->conf)); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_OQ_INT_LEVEL_TIME, time_threshold); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int lio_cn6xxx_setup_device_regs(struct octeon_device *oct) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci lio_cn6xxx_setup_pcie_mps(oct, PCIE_MPS_DEFAULT); 2508c2ecf20Sopenharmony_ci lio_cn6xxx_setup_pcie_mrrs(oct, PCIE_MRRS_512B); 2518c2ecf20Sopenharmony_ci lio_cn6xxx_enable_error_reporting(oct); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci lio_cn6xxx_setup_global_input_regs(oct); 2548c2ecf20Sopenharmony_ci lio_cn66xx_setup_pkt_ctl_regs(oct); 2558c2ecf20Sopenharmony_ci lio_cn6xxx_setup_global_output_regs(oct); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Default error timeout value should be 0x200000 to avoid host hang 2588c2ecf20Sopenharmony_ci * when reads invalid register 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_WINDOW_CTL, 0x200000ULL); 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_civoid lio_cn6xxx_setup_iq_regs(struct octeon_device *oct, u32 iq_no) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq = oct->instr_queue[iq_no]; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_IQ_PKT_INSTR_HDR64(iq_no), 0); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Write the start of the input queue's ring and its size */ 2718c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_IQ_BASE_ADDR64(iq_no), 2728c2ecf20Sopenharmony_ci iq->base_addr_dma); 2738c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_IQ_SIZE(iq_no), iq->max_count); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Remember the doorbell & instruction count register addr for this 2768c2ecf20Sopenharmony_ci * queue 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci iq->doorbell_reg = oct->mmio[0].hw_addr + CN6XXX_SLI_IQ_DOORBELL(iq_no); 2798c2ecf20Sopenharmony_ci iq->inst_cnt_reg = oct->mmio[0].hw_addr 2808c2ecf20Sopenharmony_ci + CN6XXX_SLI_IQ_INSTR_COUNT(iq_no); 2818c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "InstQ[%d]:dbell reg @ 0x%p instcnt_reg @ 0x%p\n", 2828c2ecf20Sopenharmony_ci iq_no, iq->doorbell_reg, iq->inst_cnt_reg); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Store the current instruction counter 2858c2ecf20Sopenharmony_ci * (used in flush_iq calculation) 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci iq->reset_instr_cnt = readl(iq->inst_cnt_reg); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void lio_cn66xx_setup_iq_regs(struct octeon_device *oct, u32 iq_no) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci lio_cn6xxx_setup_iq_regs(oct, iq_no); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Backpressure for this queue - WMARK set to all F's. This effectively 2958c2ecf20Sopenharmony_ci * disables the backpressure mechanism. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN66XX_SLI_IQ_BP64(iq_no), 2988c2ecf20Sopenharmony_ci (0xFFFFFFFFULL << 32)); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_civoid lio_cn6xxx_setup_oq_regs(struct octeon_device *oct, u32 oq_no) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci u32 intr; 3048c2ecf20Sopenharmony_ci struct octeon_droq *droq = oct->droq[oq_no]; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci octeon_write_csr64(oct, CN6XXX_SLI_OQ_BASE_ADDR64(oq_no), 3078c2ecf20Sopenharmony_ci droq->desc_ring_dma); 3088c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_OQ_SIZE(oq_no), droq->max_count); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_OQ_BUFF_INFO_SIZE(oq_no), 3118c2ecf20Sopenharmony_ci droq->buffer_size); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Get the mapped address of the pkt_sent and pkts_credit regs */ 3148c2ecf20Sopenharmony_ci droq->pkts_sent_reg = 3158c2ecf20Sopenharmony_ci oct->mmio[0].hw_addr + CN6XXX_SLI_OQ_PKTS_SENT(oq_no); 3168c2ecf20Sopenharmony_ci droq->pkts_credit_reg = 3178c2ecf20Sopenharmony_ci oct->mmio[0].hw_addr + CN6XXX_SLI_OQ_PKTS_CREDIT(oq_no); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Enable this output queue to generate Packet Timer Interrupt */ 3208c2ecf20Sopenharmony_ci intr = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB); 3218c2ecf20Sopenharmony_ci intr |= (1 << oq_no); 3228c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB, intr); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Enable this output queue to generate Packet Timer Interrupt */ 3258c2ecf20Sopenharmony_ci intr = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB); 3268c2ecf20Sopenharmony_ci intr |= (1 << oq_no); 3278c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB, intr); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ciint lio_cn6xxx_enable_io_queues(struct octeon_device *oct) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci u32 mask; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_INSTR_SIZE); 3358c2ecf20Sopenharmony_ci mask |= oct->io_qmask.iq64B; 3368c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_SIZE, mask); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB); 3398c2ecf20Sopenharmony_ci mask |= oct->io_qmask.iq; 3408c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, mask); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_OUT_ENB); 3438c2ecf20Sopenharmony_ci mask |= oct->io_qmask.oq; 3448c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, mask); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_civoid lio_cn6xxx_disable_io_queues(struct octeon_device *oct) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci int i; 3528c2ecf20Sopenharmony_ci u32 mask, loop = HZ; 3538c2ecf20Sopenharmony_ci u32 d32; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Reset the Enable bits for Input Queues. */ 3568c2ecf20Sopenharmony_ci mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB); 3578c2ecf20Sopenharmony_ci mask ^= oct->io_qmask.iq; 3588c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, mask); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Wait until hardware indicates that the queues are out of reset. */ 3618c2ecf20Sopenharmony_ci mask = (u32)oct->io_qmask.iq; 3628c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ); 3638c2ecf20Sopenharmony_ci while (((d32 & mask) != mask) && loop--) { 3648c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ); 3658c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* Reset the doorbell register for each Input queue. */ 3698c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { 3708c2ecf20Sopenharmony_ci if (!(oct->io_qmask.iq & BIT_ULL(i))) 3718c2ecf20Sopenharmony_ci continue; 3728c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i), 0xFFFFFFFF); 3738c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i)); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* Reset the Enable bits for Output Queues. */ 3778c2ecf20Sopenharmony_ci mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_OUT_ENB); 3788c2ecf20Sopenharmony_ci mask ^= oct->io_qmask.oq; 3798c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, mask); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Wait until hardware indicates that the queues are out of reset. */ 3828c2ecf20Sopenharmony_ci loop = HZ; 3838c2ecf20Sopenharmony_ci mask = (u32)oct->io_qmask.oq; 3848c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ); 3858c2ecf20Sopenharmony_ci while (((d32 & mask) != mask) && loop--) { 3868c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ); 3878c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci ; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Reset the doorbell register for each Output queue. */ 3928c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) { 3938c2ecf20Sopenharmony_ci if (!(oct->io_qmask.oq & BIT_ULL(i))) 3948c2ecf20Sopenharmony_ci continue; 3958c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i), 0xFFFFFFFF); 3968c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i)); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_OQ_PKTS_SENT(i)); 3998c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_OQ_PKTS_SENT(i), d32); 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT); 4038c2ecf20Sopenharmony_ci if (d32) 4048c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_CNT_INT, d32); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci d32 = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT); 4078c2ecf20Sopenharmony_ci if (d32) 4088c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_TIME_INT, d32); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_civoid 4128c2ecf20Sopenharmony_cilio_cn6xxx_bar1_idx_setup(struct octeon_device *oct, 4138c2ecf20Sopenharmony_ci u64 core_addr, 4148c2ecf20Sopenharmony_ci u32 idx, 4158c2ecf20Sopenharmony_ci int valid) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci u64 bar1; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (valid == 0) { 4208c2ecf20Sopenharmony_ci bar1 = lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port)); 4218c2ecf20Sopenharmony_ci lio_pci_writeq(oct, (bar1 & 0xFFFFFFFEULL), 4228c2ecf20Sopenharmony_ci CN6XXX_BAR1_REG(idx, oct->pcie_port)); 4238c2ecf20Sopenharmony_ci bar1 = lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port)); 4248c2ecf20Sopenharmony_ci return; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Bits 17:4 of the PCI_BAR1_INDEXx stores bits 35:22 of 4288c2ecf20Sopenharmony_ci * the Core Addr 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci lio_pci_writeq(oct, (((core_addr >> 22) << 4) | PCI_BAR1_MASK), 4318c2ecf20Sopenharmony_ci CN6XXX_BAR1_REG(idx, oct->pcie_port)); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci bar1 = lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port)); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_civoid lio_cn6xxx_bar1_idx_write(struct octeon_device *oct, 4378c2ecf20Sopenharmony_ci u32 idx, 4388c2ecf20Sopenharmony_ci u32 mask) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci lio_pci_writeq(oct, mask, CN6XXX_BAR1_REG(idx, oct->pcie_port)); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ciu32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci return (u32)lio_pci_readq(oct, CN6XXX_BAR1_REG(idx, oct->pcie_port)); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ciu32 4498c2ecf20Sopenharmony_cilio_cn6xxx_update_read_index(struct octeon_instr_queue *iq) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci u32 new_idx = readl(iq->inst_cnt_reg); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* The new instr cnt reg is a 32-bit counter that can roll over. We have 4548c2ecf20Sopenharmony_ci * noted the counter's initial value at init time into 4558c2ecf20Sopenharmony_ci * reset_instr_cnt 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_ci if (iq->reset_instr_cnt < new_idx) 4588c2ecf20Sopenharmony_ci new_idx -= iq->reset_instr_cnt; 4598c2ecf20Sopenharmony_ci else 4608c2ecf20Sopenharmony_ci new_idx += (0xffffffff - iq->reset_instr_cnt) + 1; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* Modulo of the new index with the IQ size will give us 4638c2ecf20Sopenharmony_ci * the new index. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci new_idx %= iq->max_count; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return new_idx; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_civoid lio_cn6xxx_enable_interrupt(struct octeon_device *oct, 4718c2ecf20Sopenharmony_ci u8 unused __attribute__((unused))) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip; 4748c2ecf20Sopenharmony_ci u64 mask = cn6xxx->intr_mask64 | CN6XXX_INTR_DMA0_FORCE; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Enable Interrupt */ 4778c2ecf20Sopenharmony_ci writeq(mask, cn6xxx->intr_enb_reg64); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_civoid lio_cn6xxx_disable_interrupt(struct octeon_device *oct, 4818c2ecf20Sopenharmony_ci u8 unused __attribute__((unused))) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Disable Interrupts */ 4868c2ecf20Sopenharmony_ci writeq(0, cn6xxx->intr_enb_reg64); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic void lio_cn6xxx_get_pcie_qlmport(struct octeon_device *oct) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci /* CN63xx Pass2 and newer parts implements the SLI_MAC_NUMBER register 4928c2ecf20Sopenharmony_ci * to determine the PCIE port # 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci oct->pcie_port = octeon_read_csr(oct, CN6XXX_SLI_MAC_NUMBER) & 0xff; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "Using PCIE Port %d\n", oct->pcie_port); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic void 5008c2ecf20Sopenharmony_cilio_cn6xxx_process_pcie_error_intr(struct octeon_device *oct, u64 intr64) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Error Intr: 0x%016llx\n", 5038c2ecf20Sopenharmony_ci CVM_CAST64(intr64)); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct octeon_droq *droq; 5098c2ecf20Sopenharmony_ci int oq_no; 5108c2ecf20Sopenharmony_ci u32 pkt_count, droq_time_mask, droq_mask, droq_int_enb; 5118c2ecf20Sopenharmony_ci u32 droq_cnt_enb, droq_cnt_mask; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci droq_cnt_enb = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB); 5148c2ecf20Sopenharmony_ci droq_cnt_mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT); 5158c2ecf20Sopenharmony_ci droq_mask = droq_cnt_mask & droq_cnt_enb; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci droq_time_mask = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT); 5188c2ecf20Sopenharmony_ci droq_int_enb = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB); 5198c2ecf20Sopenharmony_ci droq_mask |= (droq_time_mask & droq_int_enb); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci droq_mask &= oct->io_qmask.oq; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci oct->droq_intr = 0; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES(oct); oq_no++) { 5268c2ecf20Sopenharmony_ci if (!(droq_mask & BIT_ULL(oq_no))) 5278c2ecf20Sopenharmony_ci continue; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci droq = oct->droq[oq_no]; 5308c2ecf20Sopenharmony_ci pkt_count = octeon_droq_check_hw_for_pkts(droq); 5318c2ecf20Sopenharmony_ci if (pkt_count) { 5328c2ecf20Sopenharmony_ci oct->droq_intr |= BIT_ULL(oq_no); 5338c2ecf20Sopenharmony_ci if (droq->ops.poll_mode) { 5348c2ecf20Sopenharmony_ci u32 value; 5358c2ecf20Sopenharmony_ci u32 reg; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = 5388c2ecf20Sopenharmony_ci (struct octeon_cn6xxx *)oct->chip; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* disable interrupts for this droq */ 5418c2ecf20Sopenharmony_ci spin_lock 5428c2ecf20Sopenharmony_ci (&cn6xxx->lock_for_droq_int_enb_reg); 5438c2ecf20Sopenharmony_ci reg = CN6XXX_SLI_PKT_TIME_INT_ENB; 5448c2ecf20Sopenharmony_ci value = octeon_read_csr(oct, reg); 5458c2ecf20Sopenharmony_ci value &= ~(1 << oq_no); 5468c2ecf20Sopenharmony_ci octeon_write_csr(oct, reg, value); 5478c2ecf20Sopenharmony_ci reg = CN6XXX_SLI_PKT_CNT_INT_ENB; 5488c2ecf20Sopenharmony_ci value = octeon_read_csr(oct, reg); 5498c2ecf20Sopenharmony_ci value &= ~(1 << oq_no); 5508c2ecf20Sopenharmony_ci octeon_write_csr(oct, reg, value); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci spin_unlock(&cn6xxx->lock_for_droq_int_enb_reg); 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci droq_time_mask &= oct->io_qmask.oq; 5588c2ecf20Sopenharmony_ci droq_cnt_mask &= oct->io_qmask.oq; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Reset the PKT_CNT/TIME_INT registers. */ 5618c2ecf20Sopenharmony_ci if (droq_time_mask) 5628c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_TIME_INT, droq_time_mask); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (droq_cnt_mask) /* reset PKT_CNT register:66xx */ 5658c2ecf20Sopenharmony_ci octeon_write_csr(oct, CN6XXX_SLI_PKT_CNT_INT, droq_cnt_mask); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ciirqreturn_t lio_cn6xxx_process_interrupt_regs(void *dev) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)dev; 5738c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip; 5748c2ecf20Sopenharmony_ci u64 intr64; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci intr64 = readq(cn6xxx->intr_sum_reg64); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* If our device has interrupted, then proceed. 5798c2ecf20Sopenharmony_ci * Also check for all f's if interrupt was triggered on an error 5808c2ecf20Sopenharmony_ci * and the PCI read fails. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci if (!intr64 || (intr64 == 0xFFFFFFFFFFFFFFFFULL)) 5838c2ecf20Sopenharmony_ci return IRQ_NONE; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci oct->int_status = 0; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (intr64 & CN6XXX_INTR_ERR) 5888c2ecf20Sopenharmony_ci lio_cn6xxx_process_pcie_error_intr(oct, intr64); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (intr64 & CN6XXX_INTR_PKT_DATA) { 5918c2ecf20Sopenharmony_ci lio_cn6xxx_process_droq_intr_regs(oct); 5928c2ecf20Sopenharmony_ci oct->int_status |= OCT_DEV_INTR_PKT_DATA; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (intr64 & CN6XXX_INTR_DMA0_FORCE) 5968c2ecf20Sopenharmony_ci oct->int_status |= OCT_DEV_INTR_DMA0_FORCE; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (intr64 & CN6XXX_INTR_DMA1_FORCE) 5998c2ecf20Sopenharmony_ci oct->int_status |= OCT_DEV_INTR_DMA1_FORCE; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Clear the current interrupts */ 6028c2ecf20Sopenharmony_ci writeq(intr64, cn6xxx->intr_sum_reg64); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_civoid lio_cn6xxx_setup_reg_address(struct octeon_device *oct, 6088c2ecf20Sopenharmony_ci void *chip, 6098c2ecf20Sopenharmony_ci struct octeon_reg_list *reg_list) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci u8 __iomem *bar0_pciaddr = oct->mmio[0].hw_addr; 6128c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)chip; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci reg_list->pci_win_wr_addr_hi = 6158c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_ADDR_HI); 6168c2ecf20Sopenharmony_ci reg_list->pci_win_wr_addr_lo = 6178c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_ADDR_LO); 6188c2ecf20Sopenharmony_ci reg_list->pci_win_wr_addr = 6198c2ecf20Sopenharmony_ci (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_ADDR64); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci reg_list->pci_win_rd_addr_hi = 6228c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_ADDR_HI); 6238c2ecf20Sopenharmony_ci reg_list->pci_win_rd_addr_lo = 6248c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_ADDR_LO); 6258c2ecf20Sopenharmony_ci reg_list->pci_win_rd_addr = 6268c2ecf20Sopenharmony_ci (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_ADDR64); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci reg_list->pci_win_wr_data_hi = 6298c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_DATA_HI); 6308c2ecf20Sopenharmony_ci reg_list->pci_win_wr_data_lo = 6318c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_DATA_LO); 6328c2ecf20Sopenharmony_ci reg_list->pci_win_wr_data = 6338c2ecf20Sopenharmony_ci (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_WR_DATA64); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci reg_list->pci_win_rd_data_hi = 6368c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_DATA_HI); 6378c2ecf20Sopenharmony_ci reg_list->pci_win_rd_data_lo = 6388c2ecf20Sopenharmony_ci (u32 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_DATA_LO); 6398c2ecf20Sopenharmony_ci reg_list->pci_win_rd_data = 6408c2ecf20Sopenharmony_ci (u64 __iomem *)(bar0_pciaddr + CN6XXX_WIN_RD_DATA64); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci lio_cn6xxx_get_pcie_qlmport(oct); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci cn6xxx->intr_sum_reg64 = bar0_pciaddr + CN6XXX_SLI_INT_SUM64; 6458c2ecf20Sopenharmony_ci cn6xxx->intr_mask64 = CN6XXX_INTR_MASK; 6468c2ecf20Sopenharmony_ci cn6xxx->intr_enb_reg64 = 6478c2ecf20Sopenharmony_ci bar0_pciaddr + CN6XXX_SLI_INT_ENB64(oct->pcie_port); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ciint lio_setup_cn66xx_octeon_device(struct octeon_device *oct) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct octeon_cn6xxx *cn6xxx = (struct octeon_cn6xxx *)oct->chip; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (octeon_map_pci_barx(oct, 0, 0)) 6558c2ecf20Sopenharmony_ci return 1; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) { 6588c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s CN66XX BAR1 map failed\n", 6598c2ecf20Sopenharmony_ci __func__); 6608c2ecf20Sopenharmony_ci octeon_unmap_pci_barx(oct, 0); 6618c2ecf20Sopenharmony_ci return 1; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci spin_lock_init(&cn6xxx->lock_for_droq_int_enb_reg); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci oct->fn_list.setup_iq_regs = lio_cn66xx_setup_iq_regs; 6678c2ecf20Sopenharmony_ci oct->fn_list.setup_oq_regs = lio_cn6xxx_setup_oq_regs; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci oct->fn_list.soft_reset = lio_cn6xxx_soft_reset; 6708c2ecf20Sopenharmony_ci oct->fn_list.setup_device_regs = lio_cn6xxx_setup_device_regs; 6718c2ecf20Sopenharmony_ci oct->fn_list.update_iq_read_idx = lio_cn6xxx_update_read_index; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci oct->fn_list.bar1_idx_setup = lio_cn6xxx_bar1_idx_setup; 6748c2ecf20Sopenharmony_ci oct->fn_list.bar1_idx_write = lio_cn6xxx_bar1_idx_write; 6758c2ecf20Sopenharmony_ci oct->fn_list.bar1_idx_read = lio_cn6xxx_bar1_idx_read; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci oct->fn_list.process_interrupt_regs = lio_cn6xxx_process_interrupt_regs; 6788c2ecf20Sopenharmony_ci oct->fn_list.enable_interrupt = lio_cn6xxx_enable_interrupt; 6798c2ecf20Sopenharmony_ci oct->fn_list.disable_interrupt = lio_cn6xxx_disable_interrupt; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci oct->fn_list.enable_io_queues = lio_cn6xxx_enable_io_queues; 6828c2ecf20Sopenharmony_ci oct->fn_list.disable_io_queues = lio_cn6xxx_disable_io_queues; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci lio_cn6xxx_setup_reg_address(oct, oct->chip, &oct->reg_list); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci cn6xxx->conf = (struct octeon_config *) 6878c2ecf20Sopenharmony_ci oct_get_config_info(oct, LIO_210SV); 6888c2ecf20Sopenharmony_ci if (!cn6xxx->conf) { 6898c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s No Config found for CN66XX\n", 6908c2ecf20Sopenharmony_ci __func__); 6918c2ecf20Sopenharmony_ci octeon_unmap_pci_barx(oct, 0); 6928c2ecf20Sopenharmony_ci octeon_unmap_pci_barx(oct, 1); 6938c2ecf20Sopenharmony_ci return 1; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci oct->coproc_clock_rate = 1000000ULL * lio_cn6xxx_coprocessor_clock(oct); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ciint lio_validate_cn6xxx_config_info(struct octeon_device *oct, 7028c2ecf20Sopenharmony_ci struct octeon_config *conf6xxx) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci if (CFG_GET_IQ_MAX_Q(conf6xxx) > CN6XXX_MAX_INPUT_QUEUES) { 7058c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s: Num IQ (%d) exceeds Max (%d)\n", 7068c2ecf20Sopenharmony_ci __func__, CFG_GET_IQ_MAX_Q(conf6xxx), 7078c2ecf20Sopenharmony_ci CN6XXX_MAX_INPUT_QUEUES); 7088c2ecf20Sopenharmony_ci return 1; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (CFG_GET_OQ_MAX_Q(conf6xxx) > CN6XXX_MAX_OUTPUT_QUEUES) { 7128c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s: Num OQ (%d) exceeds Max (%d)\n", 7138c2ecf20Sopenharmony_ci __func__, CFG_GET_OQ_MAX_Q(conf6xxx), 7148c2ecf20Sopenharmony_ci CN6XXX_MAX_OUTPUT_QUEUES); 7158c2ecf20Sopenharmony_ci return 1; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (CFG_GET_IQ_INSTR_TYPE(conf6xxx) != OCTEON_32BYTE_INSTR && 7198c2ecf20Sopenharmony_ci CFG_GET_IQ_INSTR_TYPE(conf6xxx) != OCTEON_64BYTE_INSTR) { 7208c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s: Invalid instr type for IQ\n", 7218c2ecf20Sopenharmony_ci __func__); 7228c2ecf20Sopenharmony_ci return 1; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci if (!CFG_GET_OQ_REFILL_THRESHOLD(conf6xxx)) { 7258c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s: Invalid parameter for OQ\n", 7268c2ecf20Sopenharmony_ci __func__); 7278c2ecf20Sopenharmony_ci return 1; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (!(CFG_GET_OQ_INTR_TIME(conf6xxx))) { 7318c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s: No Time Interrupt for OQ\n", 7328c2ecf20Sopenharmony_ci __func__); 7338c2ecf20Sopenharmony_ci return 1; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci} 738