162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 362306a36Sopenharmony_ci * redistributing this file, you may do so under either license. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * GPL LICENSE SUMMARY 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright(c) 2017 Intel Corporation. All rights reserved. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1062306a36Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 1162306a36Sopenharmony_ci * published by the Free Software Foundation. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * BSD LICENSE 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Copyright(c) 2017 Intel Corporation. All rights reserved. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1862306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1962306a36Sopenharmony_ci * are met: 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 2262306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 2362306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above copy 2462306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 2562306a36Sopenharmony_ci * the documentation and/or other materials provided with the 2662306a36Sopenharmony_ci * distribution. 2762306a36Sopenharmony_ci * * Neither the name of Intel Corporation nor the names of its 2862306a36Sopenharmony_ci * contributors may be used to endorse or promote products derived 2962306a36Sopenharmony_ci * from this software without specific prior written permission. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3262306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3362306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3462306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3562306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3662306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3762306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3862306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3962306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 4062306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 4162306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * Intel PCIe GEN3 NTB Linux driver 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <linux/debugfs.h> 4862306a36Sopenharmony_ci#include <linux/delay.h> 4962306a36Sopenharmony_ci#include <linux/init.h> 5062306a36Sopenharmony_ci#include <linux/interrupt.h> 5162306a36Sopenharmony_ci#include <linux/module.h> 5262306a36Sopenharmony_ci#include <linux/pci.h> 5362306a36Sopenharmony_ci#include <linux/random.h> 5462306a36Sopenharmony_ci#include <linux/slab.h> 5562306a36Sopenharmony_ci#include <linux/ntb.h> 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#include "ntb_hw_intel.h" 5862306a36Sopenharmony_ci#include "ntb_hw_gen1.h" 5962306a36Sopenharmony_ci#include "ntb_hw_gen3.h" 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int gen3_poll_link(struct intel_ntb_dev *ndev); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const struct intel_ntb_reg gen3_reg = { 6462306a36Sopenharmony_ci .poll_link = gen3_poll_link, 6562306a36Sopenharmony_ci .link_is_up = xeon_link_is_up, 6662306a36Sopenharmony_ci .db_ioread = gen3_db_ioread, 6762306a36Sopenharmony_ci .db_iowrite = gen3_db_iowrite, 6862306a36Sopenharmony_ci .db_size = sizeof(u32), 6962306a36Sopenharmony_ci .ntb_ctl = GEN3_NTBCNTL_OFFSET, 7062306a36Sopenharmony_ci .mw_bar = {2, 4}, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const struct intel_ntb_alt_reg gen3_pri_reg = { 7462306a36Sopenharmony_ci .db_bell = GEN3_EM_DOORBELL_OFFSET, 7562306a36Sopenharmony_ci .db_clear = GEN3_IM_INT_STATUS_OFFSET, 7662306a36Sopenharmony_ci .db_mask = GEN3_IM_INT_DISABLE_OFFSET, 7762306a36Sopenharmony_ci .spad = GEN3_IM_SPAD_OFFSET, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic const struct intel_ntb_alt_reg gen3_b2b_reg = { 8162306a36Sopenharmony_ci .db_bell = GEN3_IM_DOORBELL_OFFSET, 8262306a36Sopenharmony_ci .db_clear = GEN3_EM_INT_STATUS_OFFSET, 8362306a36Sopenharmony_ci .db_mask = GEN3_EM_INT_DISABLE_OFFSET, 8462306a36Sopenharmony_ci .spad = GEN3_B2B_SPAD_OFFSET, 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic const struct intel_ntb_xlat_reg gen3_sec_xlat = { 8862306a36Sopenharmony_ci/* .bar0_base = GEN3_EMBAR0_OFFSET, */ 8962306a36Sopenharmony_ci .bar2_limit = GEN3_IMBAR1XLMT_OFFSET, 9062306a36Sopenharmony_ci .bar2_xlat = GEN3_IMBAR1XBASE_OFFSET, 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int gen3_poll_link(struct intel_ntb_dev *ndev) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci u16 reg_val; 9662306a36Sopenharmony_ci int rc; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_link_mask, 9962306a36Sopenharmony_ci ndev->self_mmio + 10062306a36Sopenharmony_ci ndev->self_reg->db_clear); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci rc = pci_read_config_word(ndev->ntb.pdev, 10362306a36Sopenharmony_ci GEN3_LINK_STATUS_OFFSET, ®_val); 10462306a36Sopenharmony_ci if (rc) 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (reg_val == ndev->lnk_sta) 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci ndev->lnk_sta = reg_val; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 1; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int gen3_init_isr(struct intel_ntb_dev *ndev) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int i; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * The MSIX vectors and the interrupt status bits are not lined up 12162306a36Sopenharmony_ci * on Skylake. By default the link status bit is bit 32, however it 12262306a36Sopenharmony_ci * is by default MSIX vector0. We need to fixup to line them up. 12362306a36Sopenharmony_ci * The vectors at reset is 1-32,0. We need to reprogram to 0-32. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci for (i = 0; i < GEN3_DB_MSIX_VECTOR_COUNT; i++) 12762306a36Sopenharmony_ci iowrite8(i, ndev->self_mmio + GEN3_INTVEC_OFFSET + i); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* move link status down one as workaround */ 13062306a36Sopenharmony_ci if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) { 13162306a36Sopenharmony_ci iowrite8(GEN3_DB_MSIX_VECTOR_COUNT - 2, 13262306a36Sopenharmony_ci ndev->self_mmio + GEN3_INTVEC_OFFSET + 13362306a36Sopenharmony_ci (GEN3_DB_MSIX_VECTOR_COUNT - 1)); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return ndev_init_isr(ndev, GEN3_DB_MSIX_VECTOR_COUNT, 13762306a36Sopenharmony_ci GEN3_DB_MSIX_VECTOR_COUNT, 13862306a36Sopenharmony_ci GEN3_DB_MSIX_VECTOR_SHIFT, 13962306a36Sopenharmony_ci GEN3_DB_TOTAL_SHIFT); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int gen3_setup_b2b_mw(struct intel_ntb_dev *ndev, 14362306a36Sopenharmony_ci const struct intel_b2b_addr *addr, 14462306a36Sopenharmony_ci const struct intel_b2b_addr *peer_addr) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct pci_dev *pdev; 14762306a36Sopenharmony_ci void __iomem *mmio; 14862306a36Sopenharmony_ci phys_addr_t bar_addr; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci pdev = ndev->ntb.pdev; 15162306a36Sopenharmony_ci mmio = ndev->self_mmio; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* setup incoming bar limits == base addrs (zero length windows) */ 15462306a36Sopenharmony_ci bar_addr = addr->bar2_addr64; 15562306a36Sopenharmony_ci iowrite64(bar_addr, mmio + GEN3_IMBAR1XLMT_OFFSET); 15662306a36Sopenharmony_ci bar_addr = ioread64(mmio + GEN3_IMBAR1XLMT_OFFSET); 15762306a36Sopenharmony_ci dev_dbg(&pdev->dev, "IMBAR1XLMT %#018llx\n", bar_addr); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci bar_addr = addr->bar4_addr64; 16062306a36Sopenharmony_ci iowrite64(bar_addr, mmio + GEN3_IMBAR2XLMT_OFFSET); 16162306a36Sopenharmony_ci bar_addr = ioread64(mmio + GEN3_IMBAR2XLMT_OFFSET); 16262306a36Sopenharmony_ci dev_dbg(&pdev->dev, "IMBAR2XLMT %#018llx\n", bar_addr); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* zero incoming translation addrs */ 16562306a36Sopenharmony_ci iowrite64(0, mmio + GEN3_IMBAR1XBASE_OFFSET); 16662306a36Sopenharmony_ci iowrite64(0, mmio + GEN3_IMBAR2XBASE_OFFSET); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci ndev->peer_mmio = ndev->self_mmio; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int gen3_init_ntb(struct intel_ntb_dev *ndev) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci int rc; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci ndev->mw_count = XEON_MW_COUNT; 17962306a36Sopenharmony_ci ndev->spad_count = GEN3_SPAD_COUNT; 18062306a36Sopenharmony_ci ndev->db_count = GEN3_DB_COUNT; 18162306a36Sopenharmony_ci ndev->db_link_mask = GEN3_DB_LINK_BIT; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* DB fixup for using 31 right now */ 18462306a36Sopenharmony_ci if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) 18562306a36Sopenharmony_ci ndev->db_link_mask |= BIT_ULL(31); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci switch (ndev->ntb.topo) { 18862306a36Sopenharmony_ci case NTB_TOPO_B2B_USD: 18962306a36Sopenharmony_ci case NTB_TOPO_B2B_DSD: 19062306a36Sopenharmony_ci ndev->self_reg = &gen3_pri_reg; 19162306a36Sopenharmony_ci ndev->peer_reg = &gen3_b2b_reg; 19262306a36Sopenharmony_ci ndev->xlat_reg = &gen3_sec_xlat; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { 19562306a36Sopenharmony_ci rc = gen3_setup_b2b_mw(ndev, 19662306a36Sopenharmony_ci &xeon_b2b_dsd_addr, 19762306a36Sopenharmony_ci &xeon_b2b_usd_addr); 19862306a36Sopenharmony_ci } else { 19962306a36Sopenharmony_ci rc = gen3_setup_b2b_mw(ndev, 20062306a36Sopenharmony_ci &xeon_b2b_usd_addr, 20162306a36Sopenharmony_ci &xeon_b2b_dsd_addr); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (rc) 20562306a36Sopenharmony_ci return rc; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Enable Bus Master and Memory Space on the secondary side */ 20862306a36Sopenharmony_ci iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, 20962306a36Sopenharmony_ci ndev->self_mmio + GEN3_SPCICMD_OFFSET); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci default: 21462306a36Sopenharmony_ci return -EINVAL; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_valid_mask, 22062306a36Sopenharmony_ci ndev->self_mmio + 22162306a36Sopenharmony_ci ndev->self_reg->db_mask); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciint gen3_init_dev(struct intel_ntb_dev *ndev) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct pci_dev *pdev; 22962306a36Sopenharmony_ci u8 ppd; 23062306a36Sopenharmony_ci int rc; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci pdev = ndev->ntb.pdev; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci ndev->reg = &gen3_reg; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd); 23762306a36Sopenharmony_ci if (rc) 23862306a36Sopenharmony_ci return -EIO; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ndev->ntb.topo = xeon_ppd_topo(ndev, ppd); 24162306a36Sopenharmony_ci dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd, 24262306a36Sopenharmony_ci ntb_topo_string(ndev->ntb.topo)); 24362306a36Sopenharmony_ci if (ndev->ntb.topo == NTB_TOPO_NONE) 24462306a36Sopenharmony_ci return -EINVAL; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci ndev->hwerr_flags |= NTB_HWERR_MSIX_VECTOR32_BAD; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci rc = gen3_init_ntb(ndev); 24962306a36Sopenharmony_ci if (rc) 25062306a36Sopenharmony_ci return rc; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return gen3_init_isr(ndev); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cissize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf, 25662306a36Sopenharmony_ci size_t count, loff_t *offp) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct intel_ntb_dev *ndev; 25962306a36Sopenharmony_ci void __iomem *mmio; 26062306a36Sopenharmony_ci char *buf; 26162306a36Sopenharmony_ci size_t buf_size; 26262306a36Sopenharmony_ci ssize_t ret, off; 26362306a36Sopenharmony_ci union { u64 v64; u32 v32; u16 v16; } u; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci ndev = filp->private_data; 26662306a36Sopenharmony_ci mmio = ndev->self_mmio; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci buf_size = min(count, 0x800ul); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci buf = kmalloc(buf_size, GFP_KERNEL); 27162306a36Sopenharmony_ci if (!buf) 27262306a36Sopenharmony_ci return -ENOMEM; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci off = 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 27762306a36Sopenharmony_ci "NTB Device Information:\n"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 28062306a36Sopenharmony_ci "Connection Topology -\t%s\n", 28162306a36Sopenharmony_ci ntb_topo_string(ndev->ntb.topo)); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 28462306a36Sopenharmony_ci "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl); 28562306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 28662306a36Sopenharmony_ci "LNK STA -\t\t%#06x\n", ndev->lnk_sta); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!ndev->reg->link_is_up(ndev)) 28962306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 29062306a36Sopenharmony_ci "Link Status -\t\tDown\n"); 29162306a36Sopenharmony_ci else { 29262306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 29362306a36Sopenharmony_ci "Link Status -\t\tUp\n"); 29462306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 29562306a36Sopenharmony_ci "Link Speed -\t\tPCI-E Gen %u\n", 29662306a36Sopenharmony_ci NTB_LNK_STA_SPEED(ndev->lnk_sta)); 29762306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 29862306a36Sopenharmony_ci "Link Width -\t\tx%u\n", 29962306a36Sopenharmony_ci NTB_LNK_STA_WIDTH(ndev->lnk_sta)); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 30362306a36Sopenharmony_ci "Memory Window Count -\t%u\n", ndev->mw_count); 30462306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 30562306a36Sopenharmony_ci "Scratchpad Count -\t%u\n", ndev->spad_count); 30662306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 30762306a36Sopenharmony_ci "Doorbell Count -\t%u\n", ndev->db_count); 30862306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 30962306a36Sopenharmony_ci "Doorbell Vector Count -\t%u\n", ndev->db_vec_count); 31062306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 31162306a36Sopenharmony_ci "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 31462306a36Sopenharmony_ci "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask); 31562306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 31662306a36Sopenharmony_ci "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask); 31762306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 31862306a36Sopenharmony_ci "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask); 32162306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 32262306a36Sopenharmony_ci "Doorbell Mask -\t\t%#llx\n", u.v64); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell); 32562306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 32662306a36Sopenharmony_ci "Doorbell Bell -\t\t%#llx\n", u.v64); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 32962306a36Sopenharmony_ci "\nNTB Incoming XLAT:\n"); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_IMBAR1XBASE_OFFSET); 33262306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 33362306a36Sopenharmony_ci "IMBAR1XBASE -\t\t%#018llx\n", u.v64); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_IMBAR2XBASE_OFFSET); 33662306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 33762306a36Sopenharmony_ci "IMBAR2XBASE -\t\t%#018llx\n", u.v64); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_IMBAR1XLMT_OFFSET); 34062306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 34162306a36Sopenharmony_ci "IMBAR1XLMT -\t\t\t%#018llx\n", u.v64); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_IMBAR2XLMT_OFFSET); 34462306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 34562306a36Sopenharmony_ci "IMBAR2XLMT -\t\t\t%#018llx\n", u.v64); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (ntb_topo_is_b2b(ndev->ntb.topo)) { 34862306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 34962306a36Sopenharmony_ci "\nNTB Outgoing B2B XLAT:\n"); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_EMBAR1XBASE_OFFSET); 35262306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 35362306a36Sopenharmony_ci "EMBAR1XBASE -\t\t%#018llx\n", u.v64); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_EMBAR2XBASE_OFFSET); 35662306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 35762306a36Sopenharmony_ci "EMBAR2XBASE -\t\t%#018llx\n", u.v64); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_EMBAR1XLMT_OFFSET); 36062306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 36162306a36Sopenharmony_ci "EMBAR1XLMT -\t\t%#018llx\n", u.v64); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_EMBAR2XLMT_OFFSET); 36462306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 36562306a36Sopenharmony_ci "EMBAR2XLMT -\t\t%#018llx\n", u.v64); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 36862306a36Sopenharmony_ci "\nNTB Secondary BAR:\n"); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_EMBAR0_OFFSET); 37162306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 37262306a36Sopenharmony_ci "EMBAR0 -\t\t%#018llx\n", u.v64); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_EMBAR1_OFFSET); 37562306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 37662306a36Sopenharmony_ci "EMBAR1 -\t\t%#018llx\n", u.v64); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci u.v64 = ioread64(mmio + GEN3_EMBAR2_OFFSET); 37962306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 38062306a36Sopenharmony_ci "EMBAR2 -\t\t%#018llx\n", u.v64); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 38462306a36Sopenharmony_ci "\nNTB Statistics:\n"); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci u.v16 = ioread16(mmio + GEN3_USMEMMISS_OFFSET); 38762306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 38862306a36Sopenharmony_ci "Upstream Memory Miss -\t%u\n", u.v16); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 39162306a36Sopenharmony_ci "\nNTB Hardware Errors:\n"); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (!pci_read_config_word(ndev->ntb.pdev, 39462306a36Sopenharmony_ci GEN3_DEVSTS_OFFSET, &u.v16)) 39562306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 39662306a36Sopenharmony_ci "DEVSTS -\t\t%#06x\n", u.v16); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (!pci_read_config_word(ndev->ntb.pdev, 39962306a36Sopenharmony_ci GEN3_LINK_STATUS_OFFSET, &u.v16)) 40062306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 40162306a36Sopenharmony_ci "LNKSTS -\t\t%#06x\n", u.v16); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (!pci_read_config_dword(ndev->ntb.pdev, 40462306a36Sopenharmony_ci GEN3_UNCERRSTS_OFFSET, &u.v32)) 40562306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 40662306a36Sopenharmony_ci "UNCERRSTS -\t\t%#06x\n", u.v32); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (!pci_read_config_dword(ndev->ntb.pdev, 40962306a36Sopenharmony_ci GEN3_CORERRSTS_OFFSET, &u.v32)) 41062306a36Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 41162306a36Sopenharmony_ci "CORERRSTS -\t\t%#06x\n", u.v32); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, offp, buf, off); 41462306a36Sopenharmony_ci kfree(buf); 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ciint intel_ntb3_link_enable(struct ntb_dev *ntb, enum ntb_speed max_speed, 41962306a36Sopenharmony_ci enum ntb_width max_width) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct intel_ntb_dev *ndev; 42262306a36Sopenharmony_ci u32 ntb_ctl; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ndev = container_of(ntb, struct intel_ntb_dev, ntb); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci dev_dbg(&ntb->pdev->dev, 42762306a36Sopenharmony_ci "Enabling link with max_speed %d max_width %d\n", 42862306a36Sopenharmony_ci max_speed, max_width); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (max_speed != NTB_SPEED_AUTO) 43162306a36Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed); 43262306a36Sopenharmony_ci if (max_width != NTB_WIDTH_AUTO) 43362306a36Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); 43662306a36Sopenharmony_ci ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK); 43762306a36Sopenharmony_ci ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP; 43862306a36Sopenharmony_ci ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP; 43962306a36Sopenharmony_ci iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_cistatic int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, 44462306a36Sopenharmony_ci dma_addr_t addr, resource_size_t size) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 44762306a36Sopenharmony_ci unsigned long xlat_reg, limit_reg; 44862306a36Sopenharmony_ci resource_size_t bar_size, mw_size; 44962306a36Sopenharmony_ci void __iomem *mmio; 45062306a36Sopenharmony_ci u64 base, limit, reg_val; 45162306a36Sopenharmony_ci int bar; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (idx >= ndev->b2b_idx && !ndev->b2b_off) 45762306a36Sopenharmony_ci idx += 1; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci bar = ndev_mw_to_bar(ndev, idx); 46062306a36Sopenharmony_ci if (bar < 0) 46162306a36Sopenharmony_ci return bar; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci bar_size = pci_resource_len(ndev->ntb.pdev, bar); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (idx == ndev->b2b_idx) 46662306a36Sopenharmony_ci mw_size = bar_size - ndev->b2b_off; 46762306a36Sopenharmony_ci else 46862306a36Sopenharmony_ci mw_size = bar_size; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* hardware requires that addr is aligned to bar size */ 47162306a36Sopenharmony_ci if (addr & (bar_size - 1)) 47262306a36Sopenharmony_ci return -EINVAL; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* make sure the range fits in the usable mw size */ 47562306a36Sopenharmony_ci if (size > mw_size) 47662306a36Sopenharmony_ci return -EINVAL; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mmio = ndev->self_mmio; 47962306a36Sopenharmony_ci xlat_reg = ndev->xlat_reg->bar2_xlat + (idx * 0x10); 48062306a36Sopenharmony_ci limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10); 48162306a36Sopenharmony_ci base = pci_resource_start(ndev->ntb.pdev, bar); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Set the limit if supported, if size is not mw_size */ 48462306a36Sopenharmony_ci if (limit_reg && size != mw_size) 48562306a36Sopenharmony_ci limit = base + size; 48662306a36Sopenharmony_ci else 48762306a36Sopenharmony_ci limit = base + mw_size; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* set and verify setting the translation address */ 49062306a36Sopenharmony_ci iowrite64(addr, mmio + xlat_reg); 49162306a36Sopenharmony_ci reg_val = ioread64(mmio + xlat_reg); 49262306a36Sopenharmony_ci if (reg_val != addr) { 49362306a36Sopenharmony_ci iowrite64(0, mmio + xlat_reg); 49462306a36Sopenharmony_ci return -EIO; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* set and verify setting the limit */ 50062306a36Sopenharmony_ci iowrite64(limit, mmio + limit_reg); 50162306a36Sopenharmony_ci reg_val = ioread64(mmio + limit_reg); 50262306a36Sopenharmony_ci if (reg_val != limit) { 50362306a36Sopenharmony_ci iowrite64(base, mmio + limit_reg); 50462306a36Sopenharmony_ci iowrite64(0, mmio + xlat_reg); 50562306a36Sopenharmony_ci return -EIO; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* setup the EP */ 51162306a36Sopenharmony_ci limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10) + 0x4000; 51262306a36Sopenharmony_ci base = ioread64(mmio + GEN3_EMBAR1_OFFSET + (8 * idx)); 51362306a36Sopenharmony_ci base &= ~0xf; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (limit_reg && size != mw_size) 51662306a36Sopenharmony_ci limit = base + size; 51762306a36Sopenharmony_ci else 51862306a36Sopenharmony_ci limit = base + mw_size; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* set and verify setting the limit */ 52162306a36Sopenharmony_ci iowrite64(limit, mmio + limit_reg); 52262306a36Sopenharmony_ci reg_val = ioread64(mmio + limit_reg); 52362306a36Sopenharmony_ci if (reg_val != limit) { 52462306a36Sopenharmony_ci iowrite64(base, mmio + limit_reg); 52562306a36Sopenharmony_ci iowrite64(0, mmio + xlat_reg); 52662306a36Sopenharmony_ci return -EIO; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciint intel_ntb3_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr, 53562306a36Sopenharmony_ci resource_size_t *db_size, 53662306a36Sopenharmony_ci u64 *db_data, int db_bit) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci phys_addr_t db_addr_base; 53962306a36Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (unlikely(db_bit >= BITS_PER_LONG_LONG)) 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (unlikely(BIT_ULL(db_bit) & ~ntb_ndev(ntb)->db_valid_mask)) 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ndev_db_addr(ndev, &db_addr_base, db_size, ndev->peer_addr, 54862306a36Sopenharmony_ci ndev->peer_reg->db_bell); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (db_addr) { 55162306a36Sopenharmony_ci *db_addr = db_addr_base + (db_bit * 4); 55262306a36Sopenharmony_ci dev_dbg(&ndev->ntb.pdev->dev, "Peer db addr %llx db bit %d\n", 55362306a36Sopenharmony_ci *db_addr, db_bit); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (db_data) { 55762306a36Sopenharmony_ci *db_data = 1; 55862306a36Sopenharmony_ci dev_dbg(&ndev->ntb.pdev->dev, "Peer db data %llx db bit %d\n", 55962306a36Sopenharmony_ci *db_data, db_bit); 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ciint intel_ntb3_peer_db_set(struct ntb_dev *ntb, u64 db_bits) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 56862306a36Sopenharmony_ci int bit; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (db_bits & ~ndev->db_valid_mask) 57162306a36Sopenharmony_ci return -EINVAL; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci while (db_bits) { 57462306a36Sopenharmony_ci bit = __ffs(db_bits); 57562306a36Sopenharmony_ci iowrite32(1, ndev->peer_mmio + 57662306a36Sopenharmony_ci ndev->peer_reg->db_bell + (bit * 4)); 57762306a36Sopenharmony_ci db_bits &= db_bits - 1; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci return 0; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ciu64 intel_ntb3_db_read(struct ntb_dev *ntb) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return ndev_db_read(ndev, 58862306a36Sopenharmony_ci ndev->self_mmio + 58962306a36Sopenharmony_ci ndev->self_reg->db_clear); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ciint intel_ntb3_db_clear(struct ntb_dev *ntb, u64 db_bits) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return ndev_db_write(ndev, db_bits, 59762306a36Sopenharmony_ci ndev->self_mmio + 59862306a36Sopenharmony_ci ndev->self_reg->db_clear); 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciconst struct ntb_dev_ops intel_ntb3_ops = { 60262306a36Sopenharmony_ci .mw_count = intel_ntb_mw_count, 60362306a36Sopenharmony_ci .mw_get_align = intel_ntb_mw_get_align, 60462306a36Sopenharmony_ci .mw_set_trans = intel_ntb3_mw_set_trans, 60562306a36Sopenharmony_ci .peer_mw_count = intel_ntb_peer_mw_count, 60662306a36Sopenharmony_ci .peer_mw_get_addr = intel_ntb_peer_mw_get_addr, 60762306a36Sopenharmony_ci .link_is_up = intel_ntb_link_is_up, 60862306a36Sopenharmony_ci .link_enable = intel_ntb3_link_enable, 60962306a36Sopenharmony_ci .link_disable = intel_ntb_link_disable, 61062306a36Sopenharmony_ci .db_valid_mask = intel_ntb_db_valid_mask, 61162306a36Sopenharmony_ci .db_vector_count = intel_ntb_db_vector_count, 61262306a36Sopenharmony_ci .db_vector_mask = intel_ntb_db_vector_mask, 61362306a36Sopenharmony_ci .db_read = intel_ntb3_db_read, 61462306a36Sopenharmony_ci .db_clear = intel_ntb3_db_clear, 61562306a36Sopenharmony_ci .db_set_mask = intel_ntb_db_set_mask, 61662306a36Sopenharmony_ci .db_clear_mask = intel_ntb_db_clear_mask, 61762306a36Sopenharmony_ci .peer_db_addr = intel_ntb3_peer_db_addr, 61862306a36Sopenharmony_ci .peer_db_set = intel_ntb3_peer_db_set, 61962306a36Sopenharmony_ci .spad_is_unsafe = intel_ntb_spad_is_unsafe, 62062306a36Sopenharmony_ci .spad_count = intel_ntb_spad_count, 62162306a36Sopenharmony_ci .spad_read = intel_ntb_spad_read, 62262306a36Sopenharmony_ci .spad_write = intel_ntb_spad_write, 62362306a36Sopenharmony_ci .peer_spad_addr = intel_ntb_peer_spad_addr, 62462306a36Sopenharmony_ci .peer_spad_read = intel_ntb_peer_spad_read, 62562306a36Sopenharmony_ci .peer_spad_write = intel_ntb_peer_spad_write, 62662306a36Sopenharmony_ci}; 62762306a36Sopenharmony_ci 628