18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 38c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright(c) 2012 Intel Corporation. All rights reserved. 88c2ecf20Sopenharmony_ci * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 98c2ecf20Sopenharmony_ci * Copyright (C) 2016 T-Platforms. All Rights Reserved. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 138c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * BSD LICENSE 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Copyright(c) 2012 Intel Corporation. All rights reserved. 188c2ecf20Sopenharmony_ci * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 198c2ecf20Sopenharmony_ci * Copyright (C) 2016 T-Platforms. All Rights Reserved. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 228c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 238c2ecf20Sopenharmony_ci * are met: 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 268c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 278c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copy 288c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 298c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 308c2ecf20Sopenharmony_ci * distribution. 318c2ecf20Sopenharmony_ci * * Neither the name of Intel Corporation nor the names of its 328c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 338c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 368c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 378c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 388c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 398c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 408c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 418c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 428c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 438c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 448c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 458c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * Intel PCIe NTB Linux driver 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 518c2ecf20Sopenharmony_ci#include <linux/delay.h> 528c2ecf20Sopenharmony_ci#include <linux/init.h> 538c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 548c2ecf20Sopenharmony_ci#include <linux/module.h> 558c2ecf20Sopenharmony_ci#include <linux/pci.h> 568c2ecf20Sopenharmony_ci#include <linux/random.h> 578c2ecf20Sopenharmony_ci#include <linux/slab.h> 588c2ecf20Sopenharmony_ci#include <linux/ntb.h> 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#include "ntb_hw_intel.h" 618c2ecf20Sopenharmony_ci#include "ntb_hw_gen1.h" 628c2ecf20Sopenharmony_ci#include "ntb_hw_gen3.h" 638c2ecf20Sopenharmony_ci#include "ntb_hw_gen4.h" 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define NTB_NAME "ntb_hw_intel" 668c2ecf20Sopenharmony_ci#define NTB_DESC "Intel(R) PCI-E Non-Transparent Bridge Driver" 678c2ecf20Sopenharmony_ci#define NTB_VER "2.0" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(NTB_DESC); 708c2ecf20Sopenharmony_ciMODULE_VERSION(NTB_VER); 718c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Intel Corporation"); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define bar0_off(base, bar) ((base) + ((bar) << 2)) 758c2ecf20Sopenharmony_ci#define bar2_off(base, bar) bar0_off(base, (bar) - 2) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const struct intel_ntb_reg xeon_reg; 788c2ecf20Sopenharmony_cistatic const struct intel_ntb_alt_reg xeon_pri_reg; 798c2ecf20Sopenharmony_cistatic const struct intel_ntb_alt_reg xeon_sec_reg; 808c2ecf20Sopenharmony_cistatic const struct intel_ntb_alt_reg xeon_b2b_reg; 818c2ecf20Sopenharmony_cistatic const struct intel_ntb_xlat_reg xeon_pri_xlat; 828c2ecf20Sopenharmony_cistatic const struct intel_ntb_xlat_reg xeon_sec_xlat; 838c2ecf20Sopenharmony_cistatic const struct ntb_dev_ops intel_ntb_ops; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic const struct file_operations intel_ntb_debugfs_info; 868c2ecf20Sopenharmony_cistatic struct dentry *debugfs_dir; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int b2b_mw_idx = -1; 898c2ecf20Sopenharmony_cimodule_param(b2b_mw_idx, int, 0644); 908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb. A " 918c2ecf20Sopenharmony_ci "value of zero or positive starts from first mw idx, and a " 928c2ecf20Sopenharmony_ci "negative value starts from last mw idx. Both sides MUST " 938c2ecf20Sopenharmony_ci "set the same value here!"); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic unsigned int b2b_mw_share; 968c2ecf20Sopenharmony_cimodule_param(b2b_mw_share, uint, 0644); 978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the " 988c2ecf20Sopenharmony_ci "ntb so that the peer ntb only occupies the first half of " 998c2ecf20Sopenharmony_ci "the mw, so the second half can still be used as a mw. Both " 1008c2ecf20Sopenharmony_ci "sides MUST set the same value here!"); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_usd_bar2_addr64, 1038c2ecf20Sopenharmony_ci xeon_b2b_usd_addr.bar2_addr64, ullong, 0644); 1048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64, 1058c2ecf20Sopenharmony_ci "XEON B2B USD BAR 2 64-bit address"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_usd_bar4_addr64, 1088c2ecf20Sopenharmony_ci xeon_b2b_usd_addr.bar4_addr64, ullong, 0644); 1098c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_usd_bar4_addr64, 1108c2ecf20Sopenharmony_ci "XEON B2B USD BAR 4 64-bit address"); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_usd_bar4_addr32, 1138c2ecf20Sopenharmony_ci xeon_b2b_usd_addr.bar4_addr32, ullong, 0644); 1148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_usd_bar4_addr32, 1158c2ecf20Sopenharmony_ci "XEON B2B USD split-BAR 4 32-bit address"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_usd_bar5_addr32, 1188c2ecf20Sopenharmony_ci xeon_b2b_usd_addr.bar5_addr32, ullong, 0644); 1198c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_usd_bar5_addr32, 1208c2ecf20Sopenharmony_ci "XEON B2B USD split-BAR 5 32-bit address"); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_dsd_bar2_addr64, 1238c2ecf20Sopenharmony_ci xeon_b2b_dsd_addr.bar2_addr64, ullong, 0644); 1248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64, 1258c2ecf20Sopenharmony_ci "XEON B2B DSD BAR 2 64-bit address"); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_dsd_bar4_addr64, 1288c2ecf20Sopenharmony_ci xeon_b2b_dsd_addr.bar4_addr64, ullong, 0644); 1298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr64, 1308c2ecf20Sopenharmony_ci "XEON B2B DSD BAR 4 64-bit address"); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_dsd_bar4_addr32, 1338c2ecf20Sopenharmony_ci xeon_b2b_dsd_addr.bar4_addr32, ullong, 0644); 1348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr32, 1358c2ecf20Sopenharmony_ci "XEON B2B DSD split-BAR 4 32-bit address"); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cimodule_param_named(xeon_b2b_dsd_bar5_addr32, 1388c2ecf20Sopenharmony_ci xeon_b2b_dsd_addr.bar5_addr32, ullong, 0644); 1398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xeon_b2b_dsd_bar5_addr32, 1408c2ecf20Sopenharmony_ci "XEON B2B DSD split-BAR 5 32-bit address"); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int xeon_init_isr(struct intel_ntb_dev *ndev); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci ndev->unsafe_flags = 0; 1488c2ecf20Sopenharmony_ci ndev->unsafe_flags_ignore = 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Only B2B has a workaround to avoid SDOORBELL */ 1518c2ecf20Sopenharmony_ci if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) 1528c2ecf20Sopenharmony_ci if (!ntb_topo_is_b2b(ndev->ntb.topo)) 1538c2ecf20Sopenharmony_ci ndev->unsafe_flags |= NTB_UNSAFE_DB; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* No low level workaround to avoid SB01BASE */ 1568c2ecf20Sopenharmony_ci if (ndev->hwerr_flags & NTB_HWERR_SB01BASE_LOCKUP) { 1578c2ecf20Sopenharmony_ci ndev->unsafe_flags |= NTB_UNSAFE_DB; 1588c2ecf20Sopenharmony_ci ndev->unsafe_flags |= NTB_UNSAFE_SPAD; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic inline int ndev_is_unsafe(struct intel_ntb_dev *ndev, 1638c2ecf20Sopenharmony_ci unsigned long flag) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci return !!(flag & ndev->unsafe_flags & ~ndev->unsafe_flags_ignore); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev, 1698c2ecf20Sopenharmony_ci unsigned long flag) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci flag &= ndev->unsafe_flags; 1728c2ecf20Sopenharmony_ci ndev->unsafe_flags_ignore |= flag; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return !!flag; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciint ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci if (idx < 0 || idx >= ndev->mw_count) 1808c2ecf20Sopenharmony_ci return -EINVAL; 1818c2ecf20Sopenharmony_ci return ndev->reg->mw_bar[idx]; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_civoid ndev_db_addr(struct intel_ntb_dev *ndev, 1858c2ecf20Sopenharmony_ci phys_addr_t *db_addr, resource_size_t *db_size, 1868c2ecf20Sopenharmony_ci phys_addr_t reg_addr, unsigned long reg) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) 1898c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe doorbell access", __func__); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (db_addr) { 1928c2ecf20Sopenharmony_ci *db_addr = reg_addr + reg; 1938c2ecf20Sopenharmony_ci dev_dbg(&ndev->ntb.pdev->dev, "Peer db addr %llx\n", *db_addr); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (db_size) { 1978c2ecf20Sopenharmony_ci *db_size = ndev->reg->db_size; 1988c2ecf20Sopenharmony_ci dev_dbg(&ndev->ntb.pdev->dev, "Peer db size %llx\n", *db_size); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciu64 ndev_db_read(struct intel_ntb_dev *ndev, 2038c2ecf20Sopenharmony_ci void __iomem *mmio) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) 2068c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe doorbell access", __func__); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return ndev->reg->db_ioread(mmio); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciint ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits, 2128c2ecf20Sopenharmony_ci void __iomem *mmio) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) 2158c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe doorbell access", __func__); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (db_bits & ~ndev->db_valid_mask) 2188c2ecf20Sopenharmony_ci return -EINVAL; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ndev->reg->db_iowrite(db_bits, mmio); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic inline int ndev_db_set_mask(struct intel_ntb_dev *ndev, u64 db_bits, 2268c2ecf20Sopenharmony_ci void __iomem *mmio) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci unsigned long irqflags; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) 2318c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe doorbell access", __func__); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (db_bits & ~ndev->db_valid_mask) 2348c2ecf20Sopenharmony_ci return -EINVAL; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci spin_lock_irqsave(&ndev->db_mask_lock, irqflags); 2378c2ecf20Sopenharmony_ci { 2388c2ecf20Sopenharmony_ci ndev->db_mask |= db_bits; 2398c2ecf20Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_mask, mmio); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits, 2478c2ecf20Sopenharmony_ci void __iomem *mmio) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci unsigned long irqflags; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) 2528c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe doorbell access", __func__); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (db_bits & ~ndev->db_valid_mask) 2558c2ecf20Sopenharmony_ci return -EINVAL; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci spin_lock_irqsave(&ndev->db_mask_lock, irqflags); 2588c2ecf20Sopenharmony_ci { 2598c2ecf20Sopenharmony_ci ndev->db_mask &= ~db_bits; 2608c2ecf20Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_mask, mmio); 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic inline u64 ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci u64 shift, mask; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci shift = ndev->db_vec_shift; 2728c2ecf20Sopenharmony_ci mask = BIT_ULL(shift) - 1; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return mask << (shift * db_vector); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx, 2788c2ecf20Sopenharmony_ci phys_addr_t *spad_addr, phys_addr_t reg_addr, 2798c2ecf20Sopenharmony_ci unsigned long reg) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)) 2828c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe scratchpad access", __func__); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (idx < 0 || idx >= ndev->spad_count) 2858c2ecf20Sopenharmony_ci return -EINVAL; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (spad_addr) { 2888c2ecf20Sopenharmony_ci *spad_addr = reg_addr + reg + (idx << 2); 2898c2ecf20Sopenharmony_ci dev_dbg(&ndev->ntb.pdev->dev, "Peer spad addr %llx\n", 2908c2ecf20Sopenharmony_ci *spad_addr); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx, 2978c2ecf20Sopenharmony_ci void __iomem *mmio) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)) 3008c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe scratchpad access", __func__); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (idx < 0 || idx >= ndev->spad_count) 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return ioread32(mmio + (idx << 2)); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic inline int ndev_spad_write(struct intel_ntb_dev *ndev, int idx, u32 val, 3098c2ecf20Sopenharmony_ci void __iomem *mmio) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)) 3128c2ecf20Sopenharmony_ci pr_warn_once("%s: NTB unsafe scratchpad access", __func__); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (idx < 0 || idx >= ndev->spad_count) 3158c2ecf20Sopenharmony_ci return -EINVAL; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci iowrite32(val, mmio + (idx << 2)); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci u64 vec_mask; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci vec_mask = ndev_vec_mask(ndev, vec); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if ((ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) && (vec == 31)) 3298c2ecf20Sopenharmony_ci vec_mask |= ndev->db_link_mask; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci dev_dbg(&ndev->ntb.pdev->dev, "vec %d vec_mask %llx\n", vec, vec_mask); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ndev->last_ts = jiffies; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (vec_mask & ndev->db_link_mask) { 3368c2ecf20Sopenharmony_ci if (ndev->reg->poll_link(ndev)) 3378c2ecf20Sopenharmony_ci ntb_link_event(&ndev->ntb); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (vec_mask & ndev->db_valid_mask) 3418c2ecf20Sopenharmony_ci ntb_db_event(&ndev->ntb, vec); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic irqreturn_t ndev_vec_isr(int irq, void *dev) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct intel_ntb_vec *nvec = dev; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci dev_dbg(&nvec->ndev->ntb.pdev->dev, "irq: %d nvec->num: %d\n", 3518c2ecf20Sopenharmony_ci irq, nvec->num); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return ndev_interrupt(nvec->ndev, nvec->num); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic irqreturn_t ndev_irq_isr(int irq, void *dev) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = dev; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return ndev_interrupt(ndev, irq - ndev->ntb.pdev->irq); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciint ndev_init_isr(struct intel_ntb_dev *ndev, 3648c2ecf20Sopenharmony_ci int msix_min, int msix_max, 3658c2ecf20Sopenharmony_ci int msix_shift, int total_shift) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct pci_dev *pdev; 3688c2ecf20Sopenharmony_ci int rc, i, msix_count, node; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci pdev = ndev->ntb.pdev; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci node = dev_to_node(&pdev->dev); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Mask all doorbell interrupts */ 3758c2ecf20Sopenharmony_ci ndev->db_mask = ndev->db_valid_mask; 3768c2ecf20Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_mask, 3778c2ecf20Sopenharmony_ci ndev->self_mmio + 3788c2ecf20Sopenharmony_ci ndev->self_reg->db_mask); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Try to set up msix irq */ 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci ndev->vec = kcalloc_node(msix_max, sizeof(*ndev->vec), 3838c2ecf20Sopenharmony_ci GFP_KERNEL, node); 3848c2ecf20Sopenharmony_ci if (!ndev->vec) 3858c2ecf20Sopenharmony_ci goto err_msix_vec_alloc; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci ndev->msix = kcalloc_node(msix_max, sizeof(*ndev->msix), 3888c2ecf20Sopenharmony_ci GFP_KERNEL, node); 3898c2ecf20Sopenharmony_ci if (!ndev->msix) 3908c2ecf20Sopenharmony_ci goto err_msix_alloc; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci for (i = 0; i < msix_max; ++i) 3938c2ecf20Sopenharmony_ci ndev->msix[i].entry = i; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci msix_count = pci_enable_msix_range(pdev, ndev->msix, 3968c2ecf20Sopenharmony_ci msix_min, msix_max); 3978c2ecf20Sopenharmony_ci if (msix_count < 0) 3988c2ecf20Sopenharmony_ci goto err_msix_enable; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci for (i = 0; i < msix_count; ++i) { 4018c2ecf20Sopenharmony_ci ndev->vec[i].ndev = ndev; 4028c2ecf20Sopenharmony_ci ndev->vec[i].num = i; 4038c2ecf20Sopenharmony_ci rc = request_irq(ndev->msix[i].vector, ndev_vec_isr, 0, 4048c2ecf20Sopenharmony_ci "ndev_vec_isr", &ndev->vec[i]); 4058c2ecf20Sopenharmony_ci if (rc) 4068c2ecf20Sopenharmony_ci goto err_msix_request; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Using %d msix interrupts\n", msix_count); 4108c2ecf20Sopenharmony_ci ndev->db_vec_count = msix_count; 4118c2ecf20Sopenharmony_ci ndev->db_vec_shift = msix_shift; 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cierr_msix_request: 4158c2ecf20Sopenharmony_ci while (i-- > 0) 4168c2ecf20Sopenharmony_ci free_irq(ndev->msix[i].vector, &ndev->vec[i]); 4178c2ecf20Sopenharmony_ci pci_disable_msix(pdev); 4188c2ecf20Sopenharmony_cierr_msix_enable: 4198c2ecf20Sopenharmony_ci kfree(ndev->msix); 4208c2ecf20Sopenharmony_cierr_msix_alloc: 4218c2ecf20Sopenharmony_ci kfree(ndev->vec); 4228c2ecf20Sopenharmony_cierr_msix_vec_alloc: 4238c2ecf20Sopenharmony_ci ndev->msix = NULL; 4248c2ecf20Sopenharmony_ci ndev->vec = NULL; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Try to set up msi irq */ 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci rc = pci_enable_msi(pdev); 4298c2ecf20Sopenharmony_ci if (rc) 4308c2ecf20Sopenharmony_ci goto err_msi_enable; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci rc = request_irq(pdev->irq, ndev_irq_isr, 0, 4338c2ecf20Sopenharmony_ci "ndev_irq_isr", ndev); 4348c2ecf20Sopenharmony_ci if (rc) 4358c2ecf20Sopenharmony_ci goto err_msi_request; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Using msi interrupts\n"); 4388c2ecf20Sopenharmony_ci ndev->db_vec_count = 1; 4398c2ecf20Sopenharmony_ci ndev->db_vec_shift = total_shift; 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cierr_msi_request: 4438c2ecf20Sopenharmony_ci pci_disable_msi(pdev); 4448c2ecf20Sopenharmony_cierr_msi_enable: 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Try to set up intx irq */ 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci pci_intx(pdev, 1); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci rc = request_irq(pdev->irq, ndev_irq_isr, IRQF_SHARED, 4518c2ecf20Sopenharmony_ci "ndev_irq_isr", ndev); 4528c2ecf20Sopenharmony_ci if (rc) 4538c2ecf20Sopenharmony_ci goto err_intx_request; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Using intx interrupts\n"); 4568c2ecf20Sopenharmony_ci ndev->db_vec_count = 1; 4578c2ecf20Sopenharmony_ci ndev->db_vec_shift = total_shift; 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cierr_intx_request: 4618c2ecf20Sopenharmony_ci return rc; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic void ndev_deinit_isr(struct intel_ntb_dev *ndev) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci struct pci_dev *pdev; 4678c2ecf20Sopenharmony_ci int i; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci pdev = ndev->ntb.pdev; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Mask all doorbell interrupts */ 4728c2ecf20Sopenharmony_ci ndev->db_mask = ndev->db_valid_mask; 4738c2ecf20Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_mask, 4748c2ecf20Sopenharmony_ci ndev->self_mmio + 4758c2ecf20Sopenharmony_ci ndev->self_reg->db_mask); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (ndev->msix) { 4788c2ecf20Sopenharmony_ci i = ndev->db_vec_count; 4798c2ecf20Sopenharmony_ci while (i--) 4808c2ecf20Sopenharmony_ci free_irq(ndev->msix[i].vector, &ndev->vec[i]); 4818c2ecf20Sopenharmony_ci pci_disable_msix(pdev); 4828c2ecf20Sopenharmony_ci kfree(ndev->msix); 4838c2ecf20Sopenharmony_ci kfree(ndev->vec); 4848c2ecf20Sopenharmony_ci } else { 4858c2ecf20Sopenharmony_ci free_irq(pdev->irq, ndev); 4868c2ecf20Sopenharmony_ci if (pci_dev_msi_enabled(pdev)) 4878c2ecf20Sopenharmony_ci pci_disable_msi(pdev); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic ssize_t ndev_ntb_debugfs_read(struct file *filp, char __user *ubuf, 4928c2ecf20Sopenharmony_ci size_t count, loff_t *offp) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev; 4958c2ecf20Sopenharmony_ci struct pci_dev *pdev; 4968c2ecf20Sopenharmony_ci void __iomem *mmio; 4978c2ecf20Sopenharmony_ci char *buf; 4988c2ecf20Sopenharmony_ci size_t buf_size; 4998c2ecf20Sopenharmony_ci ssize_t ret, off; 5008c2ecf20Sopenharmony_ci union { u64 v64; u32 v32; u16 v16; u8 v8; } u; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci ndev = filp->private_data; 5038c2ecf20Sopenharmony_ci pdev = ndev->ntb.pdev; 5048c2ecf20Sopenharmony_ci mmio = ndev->self_mmio; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci buf_size = min(count, 0x800ul); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci buf = kmalloc(buf_size, GFP_KERNEL); 5098c2ecf20Sopenharmony_ci if (!buf) 5108c2ecf20Sopenharmony_ci return -ENOMEM; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci off = 0; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5158c2ecf20Sopenharmony_ci "NTB Device Information:\n"); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5188c2ecf20Sopenharmony_ci "Connection Topology -\t%s\n", 5198c2ecf20Sopenharmony_ci ntb_topo_string(ndev->ntb.topo)); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (ndev->b2b_idx != UINT_MAX) { 5228c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5238c2ecf20Sopenharmony_ci "B2B MW Idx -\t\t%u\n", ndev->b2b_idx); 5248c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5258c2ecf20Sopenharmony_ci "B2B Offset -\t\t%#lx\n", ndev->b2b_off); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5298c2ecf20Sopenharmony_ci "BAR4 Split -\t\t%s\n", 5308c2ecf20Sopenharmony_ci ndev->bar4_split ? "yes" : "no"); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5338c2ecf20Sopenharmony_ci "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl); 5348c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5358c2ecf20Sopenharmony_ci "LNK STA -\t\t%#06x\n", ndev->lnk_sta); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (!ndev->reg->link_is_up(ndev)) { 5388c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5398c2ecf20Sopenharmony_ci "Link Status -\t\tDown\n"); 5408c2ecf20Sopenharmony_ci } else { 5418c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5428c2ecf20Sopenharmony_ci "Link Status -\t\tUp\n"); 5438c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5448c2ecf20Sopenharmony_ci "Link Speed -\t\tPCI-E Gen %u\n", 5458c2ecf20Sopenharmony_ci NTB_LNK_STA_SPEED(ndev->lnk_sta)); 5468c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5478c2ecf20Sopenharmony_ci "Link Width -\t\tx%u\n", 5488c2ecf20Sopenharmony_ci NTB_LNK_STA_WIDTH(ndev->lnk_sta)); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5528c2ecf20Sopenharmony_ci "Memory Window Count -\t%u\n", ndev->mw_count); 5538c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5548c2ecf20Sopenharmony_ci "Scratchpad Count -\t%u\n", ndev->spad_count); 5558c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5568c2ecf20Sopenharmony_ci "Doorbell Count -\t%u\n", ndev->db_count); 5578c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5588c2ecf20Sopenharmony_ci "Doorbell Vector Count -\t%u\n", ndev->db_vec_count); 5598c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5608c2ecf20Sopenharmony_ci "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5638c2ecf20Sopenharmony_ci "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask); 5648c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5658c2ecf20Sopenharmony_ci "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask); 5668c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5678c2ecf20Sopenharmony_ci "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask); 5708c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5718c2ecf20Sopenharmony_ci "Doorbell Mask -\t\t%#llx\n", u.v64); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell); 5748c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5758c2ecf20Sopenharmony_ci "Doorbell Bell -\t\t%#llx\n", u.v64); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5788c2ecf20Sopenharmony_ci "\nNTB Window Size:\n"); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &u.v8); 5818c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5828c2ecf20Sopenharmony_ci "PBAR23SZ %hhu\n", u.v8); 5838c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 5848c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &u.v8); 5858c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5868c2ecf20Sopenharmony_ci "PBAR45SZ %hhu\n", u.v8); 5878c2ecf20Sopenharmony_ci } else { 5888c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &u.v8); 5898c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5908c2ecf20Sopenharmony_ci "PBAR4SZ %hhu\n", u.v8); 5918c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &u.v8); 5928c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5938c2ecf20Sopenharmony_ci "PBAR5SZ %hhu\n", u.v8); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &u.v8); 5978c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 5988c2ecf20Sopenharmony_ci "SBAR23SZ %hhu\n", u.v8); 5998c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 6008c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &u.v8); 6018c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6028c2ecf20Sopenharmony_ci "SBAR45SZ %hhu\n", u.v8); 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &u.v8); 6058c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6068c2ecf20Sopenharmony_ci "SBAR4SZ %hhu\n", u.v8); 6078c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &u.v8); 6088c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6098c2ecf20Sopenharmony_ci "SBAR5SZ %hhu\n", u.v8); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6138c2ecf20Sopenharmony_ci "\nNTB Incoming XLAT:\n"); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2)); 6168c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6178c2ecf20Sopenharmony_ci "XLAT23 -\t\t%#018llx\n", u.v64); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (ndev->bar4_split) { 6208c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4)); 6218c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6228c2ecf20Sopenharmony_ci "XLAT4 -\t\t\t%#06x\n", u.v32); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 5)); 6258c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6268c2ecf20Sopenharmony_ci "XLAT5 -\t\t\t%#06x\n", u.v32); 6278c2ecf20Sopenharmony_ci } else { 6288c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4)); 6298c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6308c2ecf20Sopenharmony_ci "XLAT45 -\t\t%#018llx\n", u.v64); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2)); 6348c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6358c2ecf20Sopenharmony_ci "LMT23 -\t\t\t%#018llx\n", u.v64); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (ndev->bar4_split) { 6388c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4)); 6398c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6408c2ecf20Sopenharmony_ci "LMT4 -\t\t\t%#06x\n", u.v32); 6418c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 5)); 6428c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6438c2ecf20Sopenharmony_ci "LMT5 -\t\t\t%#06x\n", u.v32); 6448c2ecf20Sopenharmony_ci } else { 6458c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4)); 6468c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6478c2ecf20Sopenharmony_ci "LMT45 -\t\t\t%#018llx\n", u.v64); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (pdev_is_gen1(pdev)) { 6518c2ecf20Sopenharmony_ci if (ntb_topo_is_b2b(ndev->ntb.topo)) { 6528c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6538c2ecf20Sopenharmony_ci "\nNTB Outgoing B2B XLAT:\n"); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + XEON_PBAR23XLAT_OFFSET); 6568c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6578c2ecf20Sopenharmony_ci "B2B XLAT23 -\t\t%#018llx\n", u.v64); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (ndev->bar4_split) { 6608c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + XEON_PBAR4XLAT_OFFSET); 6618c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6628c2ecf20Sopenharmony_ci "B2B XLAT4 -\t\t%#06x\n", 6638c2ecf20Sopenharmony_ci u.v32); 6648c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + XEON_PBAR5XLAT_OFFSET); 6658c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6668c2ecf20Sopenharmony_ci "B2B XLAT5 -\t\t%#06x\n", 6678c2ecf20Sopenharmony_ci u.v32); 6688c2ecf20Sopenharmony_ci } else { 6698c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + XEON_PBAR45XLAT_OFFSET); 6708c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6718c2ecf20Sopenharmony_ci "B2B XLAT45 -\t\t%#018llx\n", 6728c2ecf20Sopenharmony_ci u.v64); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + XEON_PBAR23LMT_OFFSET); 6768c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6778c2ecf20Sopenharmony_ci "B2B LMT23 -\t\t%#018llx\n", u.v64); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (ndev->bar4_split) { 6808c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + XEON_PBAR4LMT_OFFSET); 6818c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6828c2ecf20Sopenharmony_ci "B2B LMT4 -\t\t%#06x\n", 6838c2ecf20Sopenharmony_ci u.v32); 6848c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + XEON_PBAR5LMT_OFFSET); 6858c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6868c2ecf20Sopenharmony_ci "B2B LMT5 -\t\t%#06x\n", 6878c2ecf20Sopenharmony_ci u.v32); 6888c2ecf20Sopenharmony_ci } else { 6898c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + XEON_PBAR45LMT_OFFSET); 6908c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6918c2ecf20Sopenharmony_ci "B2B LMT45 -\t\t%#018llx\n", 6928c2ecf20Sopenharmony_ci u.v64); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 6968c2ecf20Sopenharmony_ci "\nNTB Secondary BAR:\n"); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + XEON_SBAR0BASE_OFFSET); 6998c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7008c2ecf20Sopenharmony_ci "SBAR01 -\t\t%#018llx\n", u.v64); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + XEON_SBAR23BASE_OFFSET); 7038c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7048c2ecf20Sopenharmony_ci "SBAR23 -\t\t%#018llx\n", u.v64); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (ndev->bar4_split) { 7078c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + XEON_SBAR4BASE_OFFSET); 7088c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7098c2ecf20Sopenharmony_ci "SBAR4 -\t\t\t%#06x\n", u.v32); 7108c2ecf20Sopenharmony_ci u.v32 = ioread32(mmio + XEON_SBAR5BASE_OFFSET); 7118c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7128c2ecf20Sopenharmony_ci "SBAR5 -\t\t\t%#06x\n", u.v32); 7138c2ecf20Sopenharmony_ci } else { 7148c2ecf20Sopenharmony_ci u.v64 = ioread64(mmio + XEON_SBAR45BASE_OFFSET); 7158c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7168c2ecf20Sopenharmony_ci "SBAR45 -\t\t%#018llx\n", 7178c2ecf20Sopenharmony_ci u.v64); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7228c2ecf20Sopenharmony_ci "\nXEON NTB Statistics:\n"); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci u.v16 = ioread16(mmio + XEON_USMEMMISS_OFFSET); 7258c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7268c2ecf20Sopenharmony_ci "Upstream Memory Miss -\t%u\n", u.v16); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7298c2ecf20Sopenharmony_ci "\nXEON NTB Hardware Errors:\n"); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (!pci_read_config_word(pdev, 7328c2ecf20Sopenharmony_ci XEON_DEVSTS_OFFSET, &u.v16)) 7338c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7348c2ecf20Sopenharmony_ci "DEVSTS -\t\t%#06x\n", u.v16); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (!pci_read_config_word(pdev, 7378c2ecf20Sopenharmony_ci XEON_LINK_STATUS_OFFSET, &u.v16)) 7388c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7398c2ecf20Sopenharmony_ci "LNKSTS -\t\t%#06x\n", u.v16); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!pci_read_config_dword(pdev, 7428c2ecf20Sopenharmony_ci XEON_UNCERRSTS_OFFSET, &u.v32)) 7438c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7448c2ecf20Sopenharmony_ci "UNCERRSTS -\t\t%#06x\n", u.v32); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!pci_read_config_dword(pdev, 7478c2ecf20Sopenharmony_ci XEON_CORERRSTS_OFFSET, &u.v32)) 7488c2ecf20Sopenharmony_ci off += scnprintf(buf + off, buf_size - off, 7498c2ecf20Sopenharmony_ci "CORERRSTS -\t\t%#06x\n", u.v32); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, offp, buf, off); 7538c2ecf20Sopenharmony_ci kfree(buf); 7548c2ecf20Sopenharmony_ci return ret; 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, 7588c2ecf20Sopenharmony_ci size_t count, loff_t *offp) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = filp->private_data; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (pdev_is_gen1(ndev->ntb.pdev)) 7638c2ecf20Sopenharmony_ci return ndev_ntb_debugfs_read(filp, ubuf, count, offp); 7648c2ecf20Sopenharmony_ci else if (pdev_is_gen3(ndev->ntb.pdev)) 7658c2ecf20Sopenharmony_ci return ndev_ntb3_debugfs_read(filp, ubuf, count, offp); 7668c2ecf20Sopenharmony_ci else if (pdev_is_gen4(ndev->ntb.pdev)) 7678c2ecf20Sopenharmony_ci return ndev_ntb4_debugfs_read(filp, ubuf, count, offp); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci return -ENXIO; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic void ndev_init_debugfs(struct intel_ntb_dev *ndev) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci if (!debugfs_dir) { 7758c2ecf20Sopenharmony_ci ndev->debugfs_dir = NULL; 7768c2ecf20Sopenharmony_ci ndev->debugfs_info = NULL; 7778c2ecf20Sopenharmony_ci } else { 7788c2ecf20Sopenharmony_ci ndev->debugfs_dir = 7798c2ecf20Sopenharmony_ci debugfs_create_dir(pci_name(ndev->ntb.pdev), 7808c2ecf20Sopenharmony_ci debugfs_dir); 7818c2ecf20Sopenharmony_ci if (!ndev->debugfs_dir) 7828c2ecf20Sopenharmony_ci ndev->debugfs_info = NULL; 7838c2ecf20Sopenharmony_ci else 7848c2ecf20Sopenharmony_ci ndev->debugfs_info = 7858c2ecf20Sopenharmony_ci debugfs_create_file("info", S_IRUSR, 7868c2ecf20Sopenharmony_ci ndev->debugfs_dir, ndev, 7878c2ecf20Sopenharmony_ci &intel_ntb_debugfs_info); 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic void ndev_deinit_debugfs(struct intel_ntb_dev *ndev) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci debugfs_remove_recursive(ndev->debugfs_dir); 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ciint intel_ntb_mw_count(struct ntb_dev *ntb, int pidx) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 7998c2ecf20Sopenharmony_ci return -EINVAL; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return ntb_ndev(ntb)->mw_count; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ciint intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx, 8058c2ecf20Sopenharmony_ci resource_size_t *addr_align, 8068c2ecf20Sopenharmony_ci resource_size_t *size_align, 8078c2ecf20Sopenharmony_ci resource_size_t *size_max) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 8108c2ecf20Sopenharmony_ci resource_size_t bar_size, mw_size; 8118c2ecf20Sopenharmony_ci int bar; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 8148c2ecf20Sopenharmony_ci return -EINVAL; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (idx >= ndev->b2b_idx && !ndev->b2b_off) 8178c2ecf20Sopenharmony_ci idx += 1; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci bar = ndev_mw_to_bar(ndev, idx); 8208c2ecf20Sopenharmony_ci if (bar < 0) 8218c2ecf20Sopenharmony_ci return bar; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci bar_size = pci_resource_len(ndev->ntb.pdev, bar); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (idx == ndev->b2b_idx) 8268c2ecf20Sopenharmony_ci mw_size = bar_size - ndev->b2b_off; 8278c2ecf20Sopenharmony_ci else 8288c2ecf20Sopenharmony_ci mw_size = bar_size; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (addr_align) 8318c2ecf20Sopenharmony_ci *addr_align = pci_resource_len(ndev->ntb.pdev, bar); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (size_align) 8348c2ecf20Sopenharmony_ci *size_align = 1; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (size_max) 8378c2ecf20Sopenharmony_ci *size_max = mw_size; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, 8438c2ecf20Sopenharmony_ci dma_addr_t addr, resource_size_t size) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 8468c2ecf20Sopenharmony_ci unsigned long base_reg, xlat_reg, limit_reg; 8478c2ecf20Sopenharmony_ci resource_size_t bar_size, mw_size; 8488c2ecf20Sopenharmony_ci void __iomem *mmio; 8498c2ecf20Sopenharmony_ci u64 base, limit, reg_val; 8508c2ecf20Sopenharmony_ci int bar; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 8538c2ecf20Sopenharmony_ci return -EINVAL; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (idx >= ndev->b2b_idx && !ndev->b2b_off) 8568c2ecf20Sopenharmony_ci idx += 1; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci bar = ndev_mw_to_bar(ndev, idx); 8598c2ecf20Sopenharmony_ci if (bar < 0) 8608c2ecf20Sopenharmony_ci return bar; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci bar_size = pci_resource_len(ndev->ntb.pdev, bar); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (idx == ndev->b2b_idx) 8658c2ecf20Sopenharmony_ci mw_size = bar_size - ndev->b2b_off; 8668c2ecf20Sopenharmony_ci else 8678c2ecf20Sopenharmony_ci mw_size = bar_size; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* hardware requires that addr is aligned to bar size */ 8708c2ecf20Sopenharmony_ci if (addr & (bar_size - 1)) 8718c2ecf20Sopenharmony_ci return -EINVAL; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* make sure the range fits in the usable mw size */ 8748c2ecf20Sopenharmony_ci if (size > mw_size) 8758c2ecf20Sopenharmony_ci return -EINVAL; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci mmio = ndev->self_mmio; 8788c2ecf20Sopenharmony_ci base_reg = bar0_off(ndev->xlat_reg->bar0_base, bar); 8798c2ecf20Sopenharmony_ci xlat_reg = bar2_off(ndev->xlat_reg->bar2_xlat, bar); 8808c2ecf20Sopenharmony_ci limit_reg = bar2_off(ndev->xlat_reg->bar2_limit, bar); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (bar < 4 || !ndev->bar4_split) { 8838c2ecf20Sopenharmony_ci base = ioread64(mmio + base_reg) & NTB_BAR_MASK_64; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* Set the limit if supported, if size is not mw_size */ 8868c2ecf20Sopenharmony_ci if (limit_reg && size != mw_size) 8878c2ecf20Sopenharmony_ci limit = base + size; 8888c2ecf20Sopenharmony_ci else 8898c2ecf20Sopenharmony_ci limit = 0; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* set and verify setting the translation address */ 8928c2ecf20Sopenharmony_ci iowrite64(addr, mmio + xlat_reg); 8938c2ecf20Sopenharmony_ci reg_val = ioread64(mmio + xlat_reg); 8948c2ecf20Sopenharmony_ci if (reg_val != addr) { 8958c2ecf20Sopenharmony_ci iowrite64(0, mmio + xlat_reg); 8968c2ecf20Sopenharmony_ci return -EIO; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci /* set and verify setting the limit */ 9008c2ecf20Sopenharmony_ci iowrite64(limit, mmio + limit_reg); 9018c2ecf20Sopenharmony_ci reg_val = ioread64(mmio + limit_reg); 9028c2ecf20Sopenharmony_ci if (reg_val != limit) { 9038c2ecf20Sopenharmony_ci iowrite64(base, mmio + limit_reg); 9048c2ecf20Sopenharmony_ci iowrite64(0, mmio + xlat_reg); 9058c2ecf20Sopenharmony_ci return -EIO; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci } else { 9088c2ecf20Sopenharmony_ci /* split bar addr range must all be 32 bit */ 9098c2ecf20Sopenharmony_ci if (addr & (~0ull << 32)) 9108c2ecf20Sopenharmony_ci return -EINVAL; 9118c2ecf20Sopenharmony_ci if ((addr + size) & (~0ull << 32)) 9128c2ecf20Sopenharmony_ci return -EINVAL; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci base = ioread32(mmio + base_reg) & NTB_BAR_MASK_32; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* Set the limit if supported, if size is not mw_size */ 9178c2ecf20Sopenharmony_ci if (limit_reg && size != mw_size) 9188c2ecf20Sopenharmony_ci limit = base + size; 9198c2ecf20Sopenharmony_ci else 9208c2ecf20Sopenharmony_ci limit = 0; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* set and verify setting the translation address */ 9238c2ecf20Sopenharmony_ci iowrite32(addr, mmio + xlat_reg); 9248c2ecf20Sopenharmony_ci reg_val = ioread32(mmio + xlat_reg); 9258c2ecf20Sopenharmony_ci if (reg_val != addr) { 9268c2ecf20Sopenharmony_ci iowrite32(0, mmio + xlat_reg); 9278c2ecf20Sopenharmony_ci return -EIO; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* set and verify setting the limit */ 9318c2ecf20Sopenharmony_ci iowrite32(limit, mmio + limit_reg); 9328c2ecf20Sopenharmony_ci reg_val = ioread32(mmio + limit_reg); 9338c2ecf20Sopenharmony_ci if (reg_val != limit) { 9348c2ecf20Sopenharmony_ci iowrite32(base, mmio + limit_reg); 9358c2ecf20Sopenharmony_ci iowrite32(0, mmio + xlat_reg); 9368c2ecf20Sopenharmony_ci return -EIO; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci return 0; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ciu64 intel_ntb_link_is_up(struct ntb_dev *ntb, enum ntb_speed *speed, 9448c2ecf20Sopenharmony_ci enum ntb_width *width) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (ndev->reg->link_is_up(ndev)) { 9498c2ecf20Sopenharmony_ci if (speed) 9508c2ecf20Sopenharmony_ci *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta); 9518c2ecf20Sopenharmony_ci if (width) 9528c2ecf20Sopenharmony_ci *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta); 9538c2ecf20Sopenharmony_ci return 1; 9548c2ecf20Sopenharmony_ci } else { 9558c2ecf20Sopenharmony_ci /* TODO MAYBE: is it possible to observe the link speed and 9568c2ecf20Sopenharmony_ci * width while link is training? */ 9578c2ecf20Sopenharmony_ci if (speed) 9588c2ecf20Sopenharmony_ci *speed = NTB_SPEED_NONE; 9598c2ecf20Sopenharmony_ci if (width) 9608c2ecf20Sopenharmony_ci *width = NTB_WIDTH_NONE; 9618c2ecf20Sopenharmony_ci return 0; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic int intel_ntb_link_enable(struct ntb_dev *ntb, 9668c2ecf20Sopenharmony_ci enum ntb_speed max_speed, 9678c2ecf20Sopenharmony_ci enum ntb_width max_width) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev; 9708c2ecf20Sopenharmony_ci u32 ntb_ctl; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci ndev = container_of(ntb, struct intel_ntb_dev, ntb); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (ndev->ntb.topo == NTB_TOPO_SEC) 9758c2ecf20Sopenharmony_ci return -EINVAL; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci dev_dbg(&ntb->pdev->dev, 9788c2ecf20Sopenharmony_ci "Enabling link with max_speed %d max_width %d\n", 9798c2ecf20Sopenharmony_ci max_speed, max_width); 9808c2ecf20Sopenharmony_ci if (max_speed != NTB_SPEED_AUTO) 9818c2ecf20Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed); 9828c2ecf20Sopenharmony_ci if (max_width != NTB_WIDTH_AUTO) 9838c2ecf20Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); 9868c2ecf20Sopenharmony_ci ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK); 9878c2ecf20Sopenharmony_ci ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP; 9888c2ecf20Sopenharmony_ci ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP; 9898c2ecf20Sopenharmony_ci if (ndev->bar4_split) 9908c2ecf20Sopenharmony_ci ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP; 9918c2ecf20Sopenharmony_ci iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci return 0; 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ciint intel_ntb_link_disable(struct ntb_dev *ntb) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev; 9998c2ecf20Sopenharmony_ci u32 ntb_cntl; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci ndev = container_of(ntb, struct intel_ntb_dev, ntb); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (ndev->ntb.topo == NTB_TOPO_SEC) 10048c2ecf20Sopenharmony_ci return -EINVAL; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci dev_dbg(&ntb->pdev->dev, "Disabling link\n"); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* Bring NTB link down */ 10098c2ecf20Sopenharmony_ci ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); 10108c2ecf20Sopenharmony_ci ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP); 10118c2ecf20Sopenharmony_ci ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP); 10128c2ecf20Sopenharmony_ci if (ndev->bar4_split) 10138c2ecf20Sopenharmony_ci ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP); 10148c2ecf20Sopenharmony_ci ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK; 10158c2ecf20Sopenharmony_ci iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci return 0; 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ciint intel_ntb_peer_mw_count(struct ntb_dev *ntb) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci /* Numbers of inbound and outbound memory windows match */ 10238c2ecf20Sopenharmony_ci return ntb_ndev(ntb)->mw_count; 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ciint intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, 10278c2ecf20Sopenharmony_ci phys_addr_t *base, resource_size_t *size) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 10308c2ecf20Sopenharmony_ci int bar; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (idx >= ndev->b2b_idx && !ndev->b2b_off) 10338c2ecf20Sopenharmony_ci idx += 1; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci bar = ndev_mw_to_bar(ndev, idx); 10368c2ecf20Sopenharmony_ci if (bar < 0) 10378c2ecf20Sopenharmony_ci return bar; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (base) 10408c2ecf20Sopenharmony_ci *base = pci_resource_start(ndev->ntb.pdev, bar) + 10418c2ecf20Sopenharmony_ci (idx == ndev->b2b_idx ? ndev->b2b_off : 0); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (size) 10448c2ecf20Sopenharmony_ci *size = pci_resource_len(ndev->ntb.pdev, bar) - 10458c2ecf20Sopenharmony_ci (idx == ndev->b2b_idx ? ndev->b2b_off : 0); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic int intel_ntb_db_is_unsafe(struct ntb_dev *ntb) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB); 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ciu64 intel_ntb_db_valid_mask(struct ntb_dev *ntb) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci return ntb_ndev(ntb)->db_valid_mask; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ciint intel_ntb_db_vector_count(struct ntb_dev *ntb) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci ndev = container_of(ntb, struct intel_ntb_dev, ntb); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci return ndev->db_vec_count; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ciu64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (db_vector < 0 || db_vector > ndev->db_vec_count) 10748c2ecf20Sopenharmony_ci return 0; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci return ndev->db_valid_mask & ndev_vec_mask(ndev, db_vector); 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic u64 intel_ntb_db_read(struct ntb_dev *ntb) 10808c2ecf20Sopenharmony_ci{ 10818c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci return ndev_db_read(ndev, 10848c2ecf20Sopenharmony_ci ndev->self_mmio + 10858c2ecf20Sopenharmony_ci ndev->self_reg->db_bell); 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic int intel_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return ndev_db_write(ndev, db_bits, 10938c2ecf20Sopenharmony_ci ndev->self_mmio + 10948c2ecf20Sopenharmony_ci ndev->self_reg->db_bell); 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ciint intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci return ndev_db_set_mask(ndev, db_bits, 11028c2ecf20Sopenharmony_ci ndev->self_mmio + 11038c2ecf20Sopenharmony_ci ndev->self_reg->db_mask); 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ciint intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci return ndev_db_clear_mask(ndev, db_bits, 11118c2ecf20Sopenharmony_ci ndev->self_mmio + 11128c2ecf20Sopenharmony_ci ndev->self_reg->db_mask); 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic int intel_ntb_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr, 11168c2ecf20Sopenharmony_ci resource_size_t *db_size, u64 *db_data, int db_bit) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci u64 db_bits; 11198c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (unlikely(db_bit >= BITS_PER_LONG_LONG)) 11228c2ecf20Sopenharmony_ci return -EINVAL; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci db_bits = BIT_ULL(db_bit); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (unlikely(db_bits & ~ntb_ndev(ntb)->db_valid_mask)) 11278c2ecf20Sopenharmony_ci return -EINVAL; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci ndev_db_addr(ndev, db_addr, db_size, ndev->peer_addr, 11308c2ecf20Sopenharmony_ci ndev->peer_reg->db_bell); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (db_data) 11338c2ecf20Sopenharmony_ci *db_data = db_bits; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return 0; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic int intel_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci return ndev_db_write(ndev, db_bits, 11448c2ecf20Sopenharmony_ci ndev->peer_mmio + 11458c2ecf20Sopenharmony_ci ndev->peer_reg->db_bell); 11468c2ecf20Sopenharmony_ci} 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ciint intel_ntb_spad_is_unsafe(struct ntb_dev *ntb) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_SPAD); 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ciint intel_ntb_spad_count(struct ntb_dev *ntb) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci ndev = container_of(ntb, struct intel_ntb_dev, ntb); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci return ndev->spad_count; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ciu32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci return ndev_spad_read(ndev, idx, 11678c2ecf20Sopenharmony_ci ndev->self_mmio + 11688c2ecf20Sopenharmony_ci ndev->self_reg->spad); 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ciint intel_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci return ndev_spad_write(ndev, idx, val, 11768c2ecf20Sopenharmony_ci ndev->self_mmio + 11778c2ecf20Sopenharmony_ci ndev->self_reg->spad); 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ciint intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx, 11818c2ecf20Sopenharmony_ci phys_addr_t *spad_addr) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr, 11868c2ecf20Sopenharmony_ci ndev->peer_reg->spad); 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ciu32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci return ndev_spad_read(ndev, sidx, 11948c2ecf20Sopenharmony_ci ndev->peer_mmio + 11958c2ecf20Sopenharmony_ci ndev->peer_reg->spad); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ciint intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx, 11998c2ecf20Sopenharmony_ci u32 val) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = ntb_ndev(ntb); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci return ndev_spad_write(ndev, sidx, val, 12048c2ecf20Sopenharmony_ci ndev->peer_mmio + 12058c2ecf20Sopenharmony_ci ndev->peer_reg->spad); 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_cistatic u64 xeon_db_ioread(const void __iomem *mmio) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci return (u64)ioread16(mmio); 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic void xeon_db_iowrite(u64 bits, void __iomem *mmio) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci iowrite16((u16)bits, mmio); 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_cistatic int xeon_poll_link(struct intel_ntb_dev *ndev) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci u16 reg_val; 12218c2ecf20Sopenharmony_ci int rc; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_link_mask, 12248c2ecf20Sopenharmony_ci ndev->self_mmio + 12258c2ecf20Sopenharmony_ci ndev->self_reg->db_bell); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci rc = pci_read_config_word(ndev->ntb.pdev, 12288c2ecf20Sopenharmony_ci XEON_LINK_STATUS_OFFSET, ®_val); 12298c2ecf20Sopenharmony_ci if (rc) 12308c2ecf20Sopenharmony_ci return 0; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (reg_val == ndev->lnk_sta) 12338c2ecf20Sopenharmony_ci return 0; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci ndev->lnk_sta = reg_val; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci return 1; 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ciint xeon_link_is_up(struct intel_ntb_dev *ndev) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci if (ndev->ntb.topo == NTB_TOPO_SEC) 12438c2ecf20Sopenharmony_ci return 1; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return NTB_LNK_STA_ACTIVE(ndev->lnk_sta); 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cienum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci switch (ppd & XEON_PPD_TOPO_MASK) { 12518c2ecf20Sopenharmony_ci case XEON_PPD_TOPO_B2B_USD: 12528c2ecf20Sopenharmony_ci return NTB_TOPO_B2B_USD; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci case XEON_PPD_TOPO_B2B_DSD: 12558c2ecf20Sopenharmony_ci return NTB_TOPO_B2B_DSD; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci case XEON_PPD_TOPO_PRI_USD: 12588c2ecf20Sopenharmony_ci case XEON_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ 12598c2ecf20Sopenharmony_ci return NTB_TOPO_PRI; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci case XEON_PPD_TOPO_SEC_USD: 12628c2ecf20Sopenharmony_ci case XEON_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ 12638c2ecf20Sopenharmony_ci return NTB_TOPO_SEC; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci return NTB_TOPO_NONE; 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic inline int xeon_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci if (ppd & XEON_PPD_SPLIT_BAR_MASK) { 12728c2ecf20Sopenharmony_ci dev_dbg(&ndev->ntb.pdev->dev, "PPD %d split bar\n", ppd); 12738c2ecf20Sopenharmony_ci return 1; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci return 0; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic int xeon_init_isr(struct intel_ntb_dev *ndev) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci return ndev_init_isr(ndev, XEON_DB_MSIX_VECTOR_COUNT, 12818c2ecf20Sopenharmony_ci XEON_DB_MSIX_VECTOR_COUNT, 12828c2ecf20Sopenharmony_ci XEON_DB_MSIX_VECTOR_SHIFT, 12838c2ecf20Sopenharmony_ci XEON_DB_TOTAL_SHIFT); 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic void xeon_deinit_isr(struct intel_ntb_dev *ndev) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci ndev_deinit_isr(ndev); 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev, 12928c2ecf20Sopenharmony_ci const struct intel_b2b_addr *addr, 12938c2ecf20Sopenharmony_ci const struct intel_b2b_addr *peer_addr) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci struct pci_dev *pdev; 12968c2ecf20Sopenharmony_ci void __iomem *mmio; 12978c2ecf20Sopenharmony_ci resource_size_t bar_size; 12988c2ecf20Sopenharmony_ci phys_addr_t bar_addr; 12998c2ecf20Sopenharmony_ci int b2b_bar; 13008c2ecf20Sopenharmony_ci u8 bar_sz; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci pdev = ndev->ntb.pdev; 13038c2ecf20Sopenharmony_ci mmio = ndev->self_mmio; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (ndev->b2b_idx == UINT_MAX) { 13068c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "not using b2b mw\n"); 13078c2ecf20Sopenharmony_ci b2b_bar = 0; 13088c2ecf20Sopenharmony_ci ndev->b2b_off = 0; 13098c2ecf20Sopenharmony_ci } else { 13108c2ecf20Sopenharmony_ci b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx); 13118c2ecf20Sopenharmony_ci if (b2b_bar < 0) 13128c2ecf20Sopenharmony_ci return -EIO; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "using b2b mw bar %d\n", b2b_bar); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "b2b bar size %#llx\n", bar_size); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (b2b_mw_share && XEON_B2B_MIN_SIZE <= bar_size >> 1) { 13218c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "b2b using first half of bar\n"); 13228c2ecf20Sopenharmony_ci ndev->b2b_off = bar_size >> 1; 13238c2ecf20Sopenharmony_ci } else if (XEON_B2B_MIN_SIZE <= bar_size) { 13248c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "b2b using whole bar\n"); 13258c2ecf20Sopenharmony_ci ndev->b2b_off = 0; 13268c2ecf20Sopenharmony_ci --ndev->mw_count; 13278c2ecf20Sopenharmony_ci } else { 13288c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "b2b bar size is too small\n"); 13298c2ecf20Sopenharmony_ci return -EIO; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci /* Reset the secondary bar sizes to match the primary bar sizes, 13348c2ecf20Sopenharmony_ci * except disable or halve the size of the b2b secondary bar. 13358c2ecf20Sopenharmony_ci * 13368c2ecf20Sopenharmony_ci * Note: code for each specific bar size register, because the register 13378c2ecf20Sopenharmony_ci * offsets are not in a consistent order (bar5sz comes after ppd, odd). 13388c2ecf20Sopenharmony_ci */ 13398c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &bar_sz); 13408c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR23SZ %#x\n", bar_sz); 13418c2ecf20Sopenharmony_ci if (b2b_bar == 2) { 13428c2ecf20Sopenharmony_ci if (ndev->b2b_off) 13438c2ecf20Sopenharmony_ci bar_sz -= 1; 13448c2ecf20Sopenharmony_ci else 13458c2ecf20Sopenharmony_ci bar_sz = 0; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, XEON_SBAR23SZ_OFFSET, bar_sz); 13488c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &bar_sz); 13498c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR23SZ %#x\n", bar_sz); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 13528c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &bar_sz); 13538c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR45SZ %#x\n", bar_sz); 13548c2ecf20Sopenharmony_ci if (b2b_bar == 4) { 13558c2ecf20Sopenharmony_ci if (ndev->b2b_off) 13568c2ecf20Sopenharmony_ci bar_sz -= 1; 13578c2ecf20Sopenharmony_ci else 13588c2ecf20Sopenharmony_ci bar_sz = 0; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, XEON_SBAR45SZ_OFFSET, bar_sz); 13618c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &bar_sz); 13628c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR45SZ %#x\n", bar_sz); 13638c2ecf20Sopenharmony_ci } else { 13648c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &bar_sz); 13658c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR4SZ %#x\n", bar_sz); 13668c2ecf20Sopenharmony_ci if (b2b_bar == 4) { 13678c2ecf20Sopenharmony_ci if (ndev->b2b_off) 13688c2ecf20Sopenharmony_ci bar_sz -= 1; 13698c2ecf20Sopenharmony_ci else 13708c2ecf20Sopenharmony_ci bar_sz = 0; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, XEON_SBAR4SZ_OFFSET, bar_sz); 13738c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &bar_sz); 13748c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR4SZ %#x\n", bar_sz); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &bar_sz); 13778c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR5SZ %#x\n", bar_sz); 13788c2ecf20Sopenharmony_ci if (b2b_bar == 5) { 13798c2ecf20Sopenharmony_ci if (ndev->b2b_off) 13808c2ecf20Sopenharmony_ci bar_sz -= 1; 13818c2ecf20Sopenharmony_ci else 13828c2ecf20Sopenharmony_ci bar_sz = 0; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, XEON_SBAR5SZ_OFFSET, bar_sz); 13858c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &bar_sz); 13868c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR5SZ %#x\n", bar_sz); 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* SBAR01 hit by first part of the b2b bar */ 13908c2ecf20Sopenharmony_ci if (b2b_bar == 0) 13918c2ecf20Sopenharmony_ci bar_addr = addr->bar0_addr; 13928c2ecf20Sopenharmony_ci else if (b2b_bar == 2) 13938c2ecf20Sopenharmony_ci bar_addr = addr->bar2_addr64; 13948c2ecf20Sopenharmony_ci else if (b2b_bar == 4 && !ndev->bar4_split) 13958c2ecf20Sopenharmony_ci bar_addr = addr->bar4_addr64; 13968c2ecf20Sopenharmony_ci else if (b2b_bar == 4) 13978c2ecf20Sopenharmony_ci bar_addr = addr->bar4_addr32; 13988c2ecf20Sopenharmony_ci else if (b2b_bar == 5) 13998c2ecf20Sopenharmony_ci bar_addr = addr->bar5_addr32; 14008c2ecf20Sopenharmony_ci else 14018c2ecf20Sopenharmony_ci return -EIO; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR01 %#018llx\n", bar_addr); 14048c2ecf20Sopenharmony_ci iowrite64(bar_addr, mmio + XEON_SBAR0BASE_OFFSET); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar. 14078c2ecf20Sopenharmony_ci * The b2b bar is either disabled above, or configured half-size, and 14088c2ecf20Sopenharmony_ci * it starts at the PBAR xlat + offset. 14098c2ecf20Sopenharmony_ci */ 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); 14128c2ecf20Sopenharmony_ci iowrite64(bar_addr, mmio + XEON_SBAR23BASE_OFFSET); 14138c2ecf20Sopenharmony_ci bar_addr = ioread64(mmio + XEON_SBAR23BASE_OFFSET); 14148c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR23 %#018llx\n", bar_addr); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 14178c2ecf20Sopenharmony_ci bar_addr = addr->bar4_addr64 + 14188c2ecf20Sopenharmony_ci (b2b_bar == 4 ? ndev->b2b_off : 0); 14198c2ecf20Sopenharmony_ci iowrite64(bar_addr, mmio + XEON_SBAR45BASE_OFFSET); 14208c2ecf20Sopenharmony_ci bar_addr = ioread64(mmio + XEON_SBAR45BASE_OFFSET); 14218c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR45 %#018llx\n", bar_addr); 14228c2ecf20Sopenharmony_ci } else { 14238c2ecf20Sopenharmony_ci bar_addr = addr->bar4_addr32 + 14248c2ecf20Sopenharmony_ci (b2b_bar == 4 ? ndev->b2b_off : 0); 14258c2ecf20Sopenharmony_ci iowrite32(bar_addr, mmio + XEON_SBAR4BASE_OFFSET); 14268c2ecf20Sopenharmony_ci bar_addr = ioread32(mmio + XEON_SBAR4BASE_OFFSET); 14278c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR4 %#010llx\n", bar_addr); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci bar_addr = addr->bar5_addr32 + 14308c2ecf20Sopenharmony_ci (b2b_bar == 5 ? ndev->b2b_off : 0); 14318c2ecf20Sopenharmony_ci iowrite32(bar_addr, mmio + XEON_SBAR5BASE_OFFSET); 14328c2ecf20Sopenharmony_ci bar_addr = ioread32(mmio + XEON_SBAR5BASE_OFFSET); 14338c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR5 %#010llx\n", bar_addr); 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci /* setup incoming bar limits == base addrs (zero length windows) */ 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); 14398c2ecf20Sopenharmony_ci iowrite64(bar_addr, mmio + XEON_SBAR23LMT_OFFSET); 14408c2ecf20Sopenharmony_ci bar_addr = ioread64(mmio + XEON_SBAR23LMT_OFFSET); 14418c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR23LMT %#018llx\n", bar_addr); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 14448c2ecf20Sopenharmony_ci bar_addr = addr->bar4_addr64 + 14458c2ecf20Sopenharmony_ci (b2b_bar == 4 ? ndev->b2b_off : 0); 14468c2ecf20Sopenharmony_ci iowrite64(bar_addr, mmio + XEON_SBAR45LMT_OFFSET); 14478c2ecf20Sopenharmony_ci bar_addr = ioread64(mmio + XEON_SBAR45LMT_OFFSET); 14488c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR45LMT %#018llx\n", bar_addr); 14498c2ecf20Sopenharmony_ci } else { 14508c2ecf20Sopenharmony_ci bar_addr = addr->bar4_addr32 + 14518c2ecf20Sopenharmony_ci (b2b_bar == 4 ? ndev->b2b_off : 0); 14528c2ecf20Sopenharmony_ci iowrite32(bar_addr, mmio + XEON_SBAR4LMT_OFFSET); 14538c2ecf20Sopenharmony_ci bar_addr = ioread32(mmio + XEON_SBAR4LMT_OFFSET); 14548c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR4LMT %#010llx\n", bar_addr); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci bar_addr = addr->bar5_addr32 + 14578c2ecf20Sopenharmony_ci (b2b_bar == 5 ? ndev->b2b_off : 0); 14588c2ecf20Sopenharmony_ci iowrite32(bar_addr, mmio + XEON_SBAR5LMT_OFFSET); 14598c2ecf20Sopenharmony_ci bar_addr = ioread32(mmio + XEON_SBAR5LMT_OFFSET); 14608c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SBAR5LMT %#05llx\n", bar_addr); 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* zero incoming translation addrs */ 14648c2ecf20Sopenharmony_ci iowrite64(0, mmio + XEON_SBAR23XLAT_OFFSET); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 14678c2ecf20Sopenharmony_ci iowrite64(0, mmio + XEON_SBAR45XLAT_OFFSET); 14688c2ecf20Sopenharmony_ci } else { 14698c2ecf20Sopenharmony_ci iowrite32(0, mmio + XEON_SBAR4XLAT_OFFSET); 14708c2ecf20Sopenharmony_ci iowrite32(0, mmio + XEON_SBAR5XLAT_OFFSET); 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci /* zero outgoing translation limits (whole bar size windows) */ 14748c2ecf20Sopenharmony_ci iowrite64(0, mmio + XEON_PBAR23LMT_OFFSET); 14758c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 14768c2ecf20Sopenharmony_ci iowrite64(0, mmio + XEON_PBAR45LMT_OFFSET); 14778c2ecf20Sopenharmony_ci } else { 14788c2ecf20Sopenharmony_ci iowrite32(0, mmio + XEON_PBAR4LMT_OFFSET); 14798c2ecf20Sopenharmony_ci iowrite32(0, mmio + XEON_PBAR5LMT_OFFSET); 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* set outgoing translation offsets */ 14838c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar2_addr64; 14848c2ecf20Sopenharmony_ci iowrite64(bar_addr, mmio + XEON_PBAR23XLAT_OFFSET); 14858c2ecf20Sopenharmony_ci bar_addr = ioread64(mmio + XEON_PBAR23XLAT_OFFSET); 14868c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR23XLAT %#018llx\n", bar_addr); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (!ndev->bar4_split) { 14898c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar4_addr64; 14908c2ecf20Sopenharmony_ci iowrite64(bar_addr, mmio + XEON_PBAR45XLAT_OFFSET); 14918c2ecf20Sopenharmony_ci bar_addr = ioread64(mmio + XEON_PBAR45XLAT_OFFSET); 14928c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR45XLAT %#018llx\n", bar_addr); 14938c2ecf20Sopenharmony_ci } else { 14948c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar4_addr32; 14958c2ecf20Sopenharmony_ci iowrite32(bar_addr, mmio + XEON_PBAR4XLAT_OFFSET); 14968c2ecf20Sopenharmony_ci bar_addr = ioread32(mmio + XEON_PBAR4XLAT_OFFSET); 14978c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR4XLAT %#010llx\n", bar_addr); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar5_addr32; 15008c2ecf20Sopenharmony_ci iowrite32(bar_addr, mmio + XEON_PBAR5XLAT_OFFSET); 15018c2ecf20Sopenharmony_ci bar_addr = ioread32(mmio + XEON_PBAR5XLAT_OFFSET); 15028c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "PBAR5XLAT %#010llx\n", bar_addr); 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci /* set the translation offset for b2b registers */ 15068c2ecf20Sopenharmony_ci if (b2b_bar == 0) 15078c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar0_addr; 15088c2ecf20Sopenharmony_ci else if (b2b_bar == 2) 15098c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar2_addr64; 15108c2ecf20Sopenharmony_ci else if (b2b_bar == 4 && !ndev->bar4_split) 15118c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar4_addr64; 15128c2ecf20Sopenharmony_ci else if (b2b_bar == 4) 15138c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar4_addr32; 15148c2ecf20Sopenharmony_ci else if (b2b_bar == 5) 15158c2ecf20Sopenharmony_ci bar_addr = peer_addr->bar5_addr32; 15168c2ecf20Sopenharmony_ci else 15178c2ecf20Sopenharmony_ci return -EIO; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */ 15208c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "B2BXLAT %#018llx\n", bar_addr); 15218c2ecf20Sopenharmony_ci iowrite32(bar_addr, mmio + XEON_B2B_XLAT_OFFSETL); 15228c2ecf20Sopenharmony_ci iowrite32(bar_addr >> 32, mmio + XEON_B2B_XLAT_OFFSETU); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (b2b_bar) { 15258c2ecf20Sopenharmony_ci /* map peer ntb mmio config space registers */ 15268c2ecf20Sopenharmony_ci ndev->peer_mmio = pci_iomap(pdev, b2b_bar, 15278c2ecf20Sopenharmony_ci XEON_B2B_MIN_SIZE); 15288c2ecf20Sopenharmony_ci if (!ndev->peer_mmio) 15298c2ecf20Sopenharmony_ci return -EIO; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci ndev->peer_addr = pci_resource_start(pdev, b2b_bar); 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci return 0; 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_cistatic int xeon_init_ntb(struct intel_ntb_dev *ndev) 15388c2ecf20Sopenharmony_ci{ 15398c2ecf20Sopenharmony_ci struct device *dev = &ndev->ntb.pdev->dev; 15408c2ecf20Sopenharmony_ci int rc; 15418c2ecf20Sopenharmony_ci u32 ntb_ctl; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (ndev->bar4_split) 15448c2ecf20Sopenharmony_ci ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT; 15458c2ecf20Sopenharmony_ci else 15468c2ecf20Sopenharmony_ci ndev->mw_count = XEON_MW_COUNT; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci ndev->spad_count = XEON_SPAD_COUNT; 15498c2ecf20Sopenharmony_ci ndev->db_count = XEON_DB_COUNT; 15508c2ecf20Sopenharmony_ci ndev->db_link_mask = XEON_DB_LINK_BIT; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci switch (ndev->ntb.topo) { 15538c2ecf20Sopenharmony_ci case NTB_TOPO_PRI: 15548c2ecf20Sopenharmony_ci if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { 15558c2ecf20Sopenharmony_ci dev_err(dev, "NTB Primary config disabled\n"); 15568c2ecf20Sopenharmony_ci return -EINVAL; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci /* enable link to allow secondary side device to appear */ 15608c2ecf20Sopenharmony_ci ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); 15618c2ecf20Sopenharmony_ci ntb_ctl &= ~NTB_CTL_DISABLE; 15628c2ecf20Sopenharmony_ci iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci /* use half the spads for the peer */ 15658c2ecf20Sopenharmony_ci ndev->spad_count >>= 1; 15668c2ecf20Sopenharmony_ci ndev->self_reg = &xeon_pri_reg; 15678c2ecf20Sopenharmony_ci ndev->peer_reg = &xeon_sec_reg; 15688c2ecf20Sopenharmony_ci ndev->xlat_reg = &xeon_sec_xlat; 15698c2ecf20Sopenharmony_ci break; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci case NTB_TOPO_SEC: 15728c2ecf20Sopenharmony_ci if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { 15738c2ecf20Sopenharmony_ci dev_err(dev, "NTB Secondary config disabled\n"); 15748c2ecf20Sopenharmony_ci return -EINVAL; 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci /* use half the spads for the peer */ 15778c2ecf20Sopenharmony_ci ndev->spad_count >>= 1; 15788c2ecf20Sopenharmony_ci ndev->self_reg = &xeon_sec_reg; 15798c2ecf20Sopenharmony_ci ndev->peer_reg = &xeon_pri_reg; 15808c2ecf20Sopenharmony_ci ndev->xlat_reg = &xeon_pri_xlat; 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci case NTB_TOPO_B2B_USD: 15848c2ecf20Sopenharmony_ci case NTB_TOPO_B2B_DSD: 15858c2ecf20Sopenharmony_ci ndev->self_reg = &xeon_pri_reg; 15868c2ecf20Sopenharmony_ci ndev->peer_reg = &xeon_b2b_reg; 15878c2ecf20Sopenharmony_ci ndev->xlat_reg = &xeon_sec_xlat; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { 15908c2ecf20Sopenharmony_ci ndev->peer_reg = &xeon_pri_reg; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (b2b_mw_idx < 0) 15938c2ecf20Sopenharmony_ci ndev->b2b_idx = b2b_mw_idx + ndev->mw_count; 15948c2ecf20Sopenharmony_ci else 15958c2ecf20Sopenharmony_ci ndev->b2b_idx = b2b_mw_idx; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (ndev->b2b_idx >= ndev->mw_count) { 15988c2ecf20Sopenharmony_ci dev_dbg(dev, 15998c2ecf20Sopenharmony_ci "b2b_mw_idx %d invalid for mw_count %u\n", 16008c2ecf20Sopenharmony_ci b2b_mw_idx, ndev->mw_count); 16018c2ecf20Sopenharmony_ci return -EINVAL; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci dev_dbg(dev, "setting up b2b mw idx %d means %d\n", 16058c2ecf20Sopenharmony_ci b2b_mw_idx, ndev->b2b_idx); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci } else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) { 16088c2ecf20Sopenharmony_ci dev_warn(dev, "Reduce doorbell count by 1\n"); 16098c2ecf20Sopenharmony_ci ndev->db_count -= 1; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { 16138c2ecf20Sopenharmony_ci rc = xeon_setup_b2b_mw(ndev, 16148c2ecf20Sopenharmony_ci &xeon_b2b_dsd_addr, 16158c2ecf20Sopenharmony_ci &xeon_b2b_usd_addr); 16168c2ecf20Sopenharmony_ci } else { 16178c2ecf20Sopenharmony_ci rc = xeon_setup_b2b_mw(ndev, 16188c2ecf20Sopenharmony_ci &xeon_b2b_usd_addr, 16198c2ecf20Sopenharmony_ci &xeon_b2b_dsd_addr); 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci if (rc) 16228c2ecf20Sopenharmony_ci return rc; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci /* Enable Bus Master and Memory Space on the secondary side */ 16258c2ecf20Sopenharmony_ci iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, 16268c2ecf20Sopenharmony_ci ndev->self_mmio + XEON_SPCICMD_OFFSET); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci break; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci default: 16318c2ecf20Sopenharmony_ci return -EINVAL; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci ndev->reg->db_iowrite(ndev->db_valid_mask, 16378c2ecf20Sopenharmony_ci ndev->self_mmio + 16388c2ecf20Sopenharmony_ci ndev->self_reg->db_mask); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci return 0; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic int xeon_init_dev(struct intel_ntb_dev *ndev) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci struct pci_dev *pdev; 16468c2ecf20Sopenharmony_ci u8 ppd; 16478c2ecf20Sopenharmony_ci int rc, mem; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci pdev = ndev->ntb.pdev; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci switch (pdev->device) { 16528c2ecf20Sopenharmony_ci /* There is a Xeon hardware errata related to writes to SDOORBELL or 16538c2ecf20Sopenharmony_ci * B2BDOORBELL in conjunction with inbound access to NTB MMIO Space, 16548c2ecf20Sopenharmony_ci * which may hang the system. To workaround this use the second memory 16558c2ecf20Sopenharmony_ci * window to access the interrupt and scratch pad registers on the 16568c2ecf20Sopenharmony_ci * remote system. 16578c2ecf20Sopenharmony_ci */ 16588c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: 16598c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: 16608c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: 16618c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: 16628c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: 16638c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: 16648c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: 16658c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: 16668c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: 16678c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: 16688c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: 16698c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: 16708c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: 16718c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: 16728c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: 16738c2ecf20Sopenharmony_ci ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP; 16748c2ecf20Sopenharmony_ci break; 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci switch (pdev->device) { 16788c2ecf20Sopenharmony_ci /* There is a hardware errata related to accessing any register in 16798c2ecf20Sopenharmony_ci * SB01BASE in the presence of bidirectional traffic crossing the NTB. 16808c2ecf20Sopenharmony_ci */ 16818c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: 16828c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: 16838c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: 16848c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: 16858c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: 16868c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: 16878c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: 16888c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: 16898c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: 16908c2ecf20Sopenharmony_ci ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP; 16918c2ecf20Sopenharmony_ci break; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci switch (pdev->device) { 16958c2ecf20Sopenharmony_ci /* HW Errata on bit 14 of b2bdoorbell register. Writes will not be 16968c2ecf20Sopenharmony_ci * mirrored to the remote system. Shrink the number of bits by one, 16978c2ecf20Sopenharmony_ci * since bit 14 is the last bit. 16988c2ecf20Sopenharmony_ci */ 16998c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: 17008c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: 17018c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: 17028c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: 17038c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: 17048c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: 17058c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: 17068c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: 17078c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: 17088c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: 17098c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: 17108c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: 17118c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: 17128c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: 17138c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: 17148c2ecf20Sopenharmony_ci ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14; 17158c2ecf20Sopenharmony_ci break; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci ndev->reg = &xeon_reg; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd); 17218c2ecf20Sopenharmony_ci if (rc) 17228c2ecf20Sopenharmony_ci return -EIO; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci ndev->ntb.topo = xeon_ppd_topo(ndev, ppd); 17258c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd, 17268c2ecf20Sopenharmony_ci ntb_topo_string(ndev->ntb.topo)); 17278c2ecf20Sopenharmony_ci if (ndev->ntb.topo == NTB_TOPO_NONE) 17288c2ecf20Sopenharmony_ci return -EINVAL; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (ndev->ntb.topo != NTB_TOPO_SEC) { 17318c2ecf20Sopenharmony_ci ndev->bar4_split = xeon_ppd_bar4_split(ndev, ppd); 17328c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "ppd %#x bar4_split %d\n", 17338c2ecf20Sopenharmony_ci ppd, ndev->bar4_split); 17348c2ecf20Sopenharmony_ci } else { 17358c2ecf20Sopenharmony_ci /* This is a way for transparent BAR to figure out if we are 17368c2ecf20Sopenharmony_ci * doing split BAR or not. There is no way for the hw on the 17378c2ecf20Sopenharmony_ci * transparent side to know and set the PPD. 17388c2ecf20Sopenharmony_ci */ 17398c2ecf20Sopenharmony_ci mem = pci_select_bars(pdev, IORESOURCE_MEM); 17408c2ecf20Sopenharmony_ci ndev->bar4_split = hweight32(mem) == 17418c2ecf20Sopenharmony_ci HSX_SPLIT_BAR_MW_COUNT + 1; 17428c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "mem %#x bar4_split %d\n", 17438c2ecf20Sopenharmony_ci mem, ndev->bar4_split); 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci rc = xeon_init_ntb(ndev); 17478c2ecf20Sopenharmony_ci if (rc) 17488c2ecf20Sopenharmony_ci return rc; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci return xeon_init_isr(ndev); 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cistatic void xeon_deinit_dev(struct intel_ntb_dev *ndev) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci xeon_deinit_isr(ndev); 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_cistatic int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci int rc; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, ndev); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 17658c2ecf20Sopenharmony_ci if (rc) 17668c2ecf20Sopenharmony_ci goto err_pci_enable; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, NTB_NAME); 17698c2ecf20Sopenharmony_ci if (rc) 17708c2ecf20Sopenharmony_ci goto err_pci_regions; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci pci_set_master(pdev); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); 17758c2ecf20Sopenharmony_ci if (rc) { 17768c2ecf20Sopenharmony_ci rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 17778c2ecf20Sopenharmony_ci if (rc) 17788c2ecf20Sopenharmony_ci goto err_dma_mask; 17798c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Cannot DMA highmem\n"); 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 17838c2ecf20Sopenharmony_ci if (rc) { 17848c2ecf20Sopenharmony_ci rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 17858c2ecf20Sopenharmony_ci if (rc) 17868c2ecf20Sopenharmony_ci goto err_dma_mask; 17878c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci ndev->self_mmio = pci_iomap(pdev, 0, 0); 17918c2ecf20Sopenharmony_ci if (!ndev->self_mmio) { 17928c2ecf20Sopenharmony_ci rc = -EIO; 17938c2ecf20Sopenharmony_ci goto err_mmio; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci ndev->peer_mmio = ndev->self_mmio; 17968c2ecf20Sopenharmony_ci ndev->peer_addr = pci_resource_start(pdev, 0); 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci return 0; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_cierr_mmio: 18018c2ecf20Sopenharmony_cierr_dma_mask: 18028c2ecf20Sopenharmony_ci pci_clear_master(pdev); 18038c2ecf20Sopenharmony_ci pci_release_regions(pdev); 18048c2ecf20Sopenharmony_cierr_pci_regions: 18058c2ecf20Sopenharmony_ci pci_disable_device(pdev); 18068c2ecf20Sopenharmony_cierr_pci_enable: 18078c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 18088c2ecf20Sopenharmony_ci return rc; 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic void intel_ntb_deinit_pci(struct intel_ntb_dev *ndev) 18128c2ecf20Sopenharmony_ci{ 18138c2ecf20Sopenharmony_ci struct pci_dev *pdev = ndev->ntb.pdev; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (ndev->peer_mmio && ndev->peer_mmio != ndev->self_mmio) 18168c2ecf20Sopenharmony_ci pci_iounmap(pdev, ndev->peer_mmio); 18178c2ecf20Sopenharmony_ci pci_iounmap(pdev, ndev->self_mmio); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci pci_clear_master(pdev); 18208c2ecf20Sopenharmony_ci pci_release_regions(pdev); 18218c2ecf20Sopenharmony_ci pci_disable_device(pdev); 18228c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 18238c2ecf20Sopenharmony_ci} 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_cistatic inline void ndev_init_struct(struct intel_ntb_dev *ndev, 18268c2ecf20Sopenharmony_ci struct pci_dev *pdev) 18278c2ecf20Sopenharmony_ci{ 18288c2ecf20Sopenharmony_ci ndev->ntb.pdev = pdev; 18298c2ecf20Sopenharmony_ci ndev->ntb.topo = NTB_TOPO_NONE; 18308c2ecf20Sopenharmony_ci ndev->ntb.ops = &intel_ntb_ops; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci ndev->b2b_off = 0; 18338c2ecf20Sopenharmony_ci ndev->b2b_idx = UINT_MAX; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci ndev->bar4_split = 0; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci ndev->mw_count = 0; 18388c2ecf20Sopenharmony_ci ndev->spad_count = 0; 18398c2ecf20Sopenharmony_ci ndev->db_count = 0; 18408c2ecf20Sopenharmony_ci ndev->db_vec_count = 0; 18418c2ecf20Sopenharmony_ci ndev->db_vec_shift = 0; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci ndev->ntb_ctl = 0; 18448c2ecf20Sopenharmony_ci ndev->lnk_sta = 0; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci ndev->db_valid_mask = 0; 18478c2ecf20Sopenharmony_ci ndev->db_link_mask = 0; 18488c2ecf20Sopenharmony_ci ndev->db_mask = 0; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci spin_lock_init(&ndev->db_mask_lock); 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic int intel_ntb_pci_probe(struct pci_dev *pdev, 18548c2ecf20Sopenharmony_ci const struct pci_device_id *id) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev; 18578c2ecf20Sopenharmony_ci int rc, node; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci node = dev_to_node(&pdev->dev); 18608c2ecf20Sopenharmony_ci ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); 18618c2ecf20Sopenharmony_ci if (!ndev) { 18628c2ecf20Sopenharmony_ci rc = -ENOMEM; 18638c2ecf20Sopenharmony_ci goto err_ndev; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci ndev_init_struct(ndev, pdev); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (pdev_is_gen1(pdev)) { 18698c2ecf20Sopenharmony_ci rc = intel_ntb_init_pci(ndev, pdev); 18708c2ecf20Sopenharmony_ci if (rc) 18718c2ecf20Sopenharmony_ci goto err_init_pci; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci rc = xeon_init_dev(ndev); 18748c2ecf20Sopenharmony_ci if (rc) 18758c2ecf20Sopenharmony_ci goto err_init_dev; 18768c2ecf20Sopenharmony_ci } else if (pdev_is_gen3(pdev)) { 18778c2ecf20Sopenharmony_ci ndev->ntb.ops = &intel_ntb3_ops; 18788c2ecf20Sopenharmony_ci rc = intel_ntb_init_pci(ndev, pdev); 18798c2ecf20Sopenharmony_ci if (rc) 18808c2ecf20Sopenharmony_ci goto err_init_pci; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci rc = gen3_init_dev(ndev); 18838c2ecf20Sopenharmony_ci if (rc) 18848c2ecf20Sopenharmony_ci goto err_init_dev; 18858c2ecf20Sopenharmony_ci } else if (pdev_is_gen4(pdev)) { 18868c2ecf20Sopenharmony_ci ndev->ntb.ops = &intel_ntb4_ops; 18878c2ecf20Sopenharmony_ci rc = intel_ntb_init_pci(ndev, pdev); 18888c2ecf20Sopenharmony_ci if (rc) 18898c2ecf20Sopenharmony_ci goto err_init_pci; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci rc = gen4_init_dev(ndev); 18928c2ecf20Sopenharmony_ci if (rc) 18938c2ecf20Sopenharmony_ci goto err_init_dev; 18948c2ecf20Sopenharmony_ci } else { 18958c2ecf20Sopenharmony_ci rc = -EINVAL; 18968c2ecf20Sopenharmony_ci goto err_init_pci; 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci ndev_reset_unsafe_flags(ndev); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci ndev->reg->poll_link(ndev); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci ndev_init_debugfs(ndev); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci rc = ntb_register_device(&ndev->ntb); 19068c2ecf20Sopenharmony_ci if (rc) 19078c2ecf20Sopenharmony_ci goto err_register; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "NTB device registered.\n"); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci return 0; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_cierr_register: 19148c2ecf20Sopenharmony_ci ndev_deinit_debugfs(ndev); 19158c2ecf20Sopenharmony_ci if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev) || pdev_is_gen4(pdev)) 19168c2ecf20Sopenharmony_ci xeon_deinit_dev(ndev); 19178c2ecf20Sopenharmony_cierr_init_dev: 19188c2ecf20Sopenharmony_ci intel_ntb_deinit_pci(ndev); 19198c2ecf20Sopenharmony_cierr_init_pci: 19208c2ecf20Sopenharmony_ci kfree(ndev); 19218c2ecf20Sopenharmony_cierr_ndev: 19228c2ecf20Sopenharmony_ci return rc; 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic void intel_ntb_pci_remove(struct pci_dev *pdev) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci struct intel_ntb_dev *ndev = pci_get_drvdata(pdev); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci ntb_unregister_device(&ndev->ntb); 19308c2ecf20Sopenharmony_ci ndev_deinit_debugfs(ndev); 19318c2ecf20Sopenharmony_ci if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev) || pdev_is_gen4(pdev)) 19328c2ecf20Sopenharmony_ci xeon_deinit_dev(ndev); 19338c2ecf20Sopenharmony_ci intel_ntb_deinit_pci(ndev); 19348c2ecf20Sopenharmony_ci kfree(ndev); 19358c2ecf20Sopenharmony_ci} 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_cistatic const struct intel_ntb_reg xeon_reg = { 19388c2ecf20Sopenharmony_ci .poll_link = xeon_poll_link, 19398c2ecf20Sopenharmony_ci .link_is_up = xeon_link_is_up, 19408c2ecf20Sopenharmony_ci .db_ioread = xeon_db_ioread, 19418c2ecf20Sopenharmony_ci .db_iowrite = xeon_db_iowrite, 19428c2ecf20Sopenharmony_ci .db_size = sizeof(u32), 19438c2ecf20Sopenharmony_ci .ntb_ctl = XEON_NTBCNTL_OFFSET, 19448c2ecf20Sopenharmony_ci .mw_bar = {2, 4, 5}, 19458c2ecf20Sopenharmony_ci}; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_cistatic const struct intel_ntb_alt_reg xeon_pri_reg = { 19488c2ecf20Sopenharmony_ci .db_bell = XEON_PDOORBELL_OFFSET, 19498c2ecf20Sopenharmony_ci .db_mask = XEON_PDBMSK_OFFSET, 19508c2ecf20Sopenharmony_ci .spad = XEON_SPAD_OFFSET, 19518c2ecf20Sopenharmony_ci}; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic const struct intel_ntb_alt_reg xeon_sec_reg = { 19548c2ecf20Sopenharmony_ci .db_bell = XEON_SDOORBELL_OFFSET, 19558c2ecf20Sopenharmony_ci .db_mask = XEON_SDBMSK_OFFSET, 19568c2ecf20Sopenharmony_ci /* second half of the scratchpads */ 19578c2ecf20Sopenharmony_ci .spad = XEON_SPAD_OFFSET + (XEON_SPAD_COUNT << 1), 19588c2ecf20Sopenharmony_ci}; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_cistatic const struct intel_ntb_alt_reg xeon_b2b_reg = { 19618c2ecf20Sopenharmony_ci .db_bell = XEON_B2B_DOORBELL_OFFSET, 19628c2ecf20Sopenharmony_ci .spad = XEON_B2B_SPAD_OFFSET, 19638c2ecf20Sopenharmony_ci}; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_cistatic const struct intel_ntb_xlat_reg xeon_pri_xlat = { 19668c2ecf20Sopenharmony_ci /* Note: no primary .bar0_base visible to the secondary side. 19678c2ecf20Sopenharmony_ci * 19688c2ecf20Sopenharmony_ci * The secondary side cannot get the base address stored in primary 19698c2ecf20Sopenharmony_ci * bars. The base address is necessary to set the limit register to 19708c2ecf20Sopenharmony_ci * any value other than zero, or unlimited. 19718c2ecf20Sopenharmony_ci * 19728c2ecf20Sopenharmony_ci * WITHOUT THE BASE ADDRESS, THE SECONDARY SIDE CANNOT DISABLE the 19738c2ecf20Sopenharmony_ci * window by setting the limit equal to base, nor can it limit the size 19748c2ecf20Sopenharmony_ci * of the memory window by setting the limit to base + size. 19758c2ecf20Sopenharmony_ci */ 19768c2ecf20Sopenharmony_ci .bar2_limit = XEON_PBAR23LMT_OFFSET, 19778c2ecf20Sopenharmony_ci .bar2_xlat = XEON_PBAR23XLAT_OFFSET, 19788c2ecf20Sopenharmony_ci}; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic const struct intel_ntb_xlat_reg xeon_sec_xlat = { 19818c2ecf20Sopenharmony_ci .bar0_base = XEON_SBAR0BASE_OFFSET, 19828c2ecf20Sopenharmony_ci .bar2_limit = XEON_SBAR23LMT_OFFSET, 19838c2ecf20Sopenharmony_ci .bar2_xlat = XEON_SBAR23XLAT_OFFSET, 19848c2ecf20Sopenharmony_ci}; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_cistruct intel_b2b_addr xeon_b2b_usd_addr = { 19878c2ecf20Sopenharmony_ci .bar2_addr64 = XEON_B2B_BAR2_ADDR64, 19888c2ecf20Sopenharmony_ci .bar4_addr64 = XEON_B2B_BAR4_ADDR64, 19898c2ecf20Sopenharmony_ci .bar4_addr32 = XEON_B2B_BAR4_ADDR32, 19908c2ecf20Sopenharmony_ci .bar5_addr32 = XEON_B2B_BAR5_ADDR32, 19918c2ecf20Sopenharmony_ci}; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_cistruct intel_b2b_addr xeon_b2b_dsd_addr = { 19948c2ecf20Sopenharmony_ci .bar2_addr64 = XEON_B2B_BAR2_ADDR64, 19958c2ecf20Sopenharmony_ci .bar4_addr64 = XEON_B2B_BAR4_ADDR64, 19968c2ecf20Sopenharmony_ci .bar4_addr32 = XEON_B2B_BAR4_ADDR32, 19978c2ecf20Sopenharmony_ci .bar5_addr32 = XEON_B2B_BAR5_ADDR32, 19988c2ecf20Sopenharmony_ci}; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci/* operations for primary side of local ntb */ 20018c2ecf20Sopenharmony_cistatic const struct ntb_dev_ops intel_ntb_ops = { 20028c2ecf20Sopenharmony_ci .mw_count = intel_ntb_mw_count, 20038c2ecf20Sopenharmony_ci .mw_get_align = intel_ntb_mw_get_align, 20048c2ecf20Sopenharmony_ci .mw_set_trans = intel_ntb_mw_set_trans, 20058c2ecf20Sopenharmony_ci .peer_mw_count = intel_ntb_peer_mw_count, 20068c2ecf20Sopenharmony_ci .peer_mw_get_addr = intel_ntb_peer_mw_get_addr, 20078c2ecf20Sopenharmony_ci .link_is_up = intel_ntb_link_is_up, 20088c2ecf20Sopenharmony_ci .link_enable = intel_ntb_link_enable, 20098c2ecf20Sopenharmony_ci .link_disable = intel_ntb_link_disable, 20108c2ecf20Sopenharmony_ci .db_is_unsafe = intel_ntb_db_is_unsafe, 20118c2ecf20Sopenharmony_ci .db_valid_mask = intel_ntb_db_valid_mask, 20128c2ecf20Sopenharmony_ci .db_vector_count = intel_ntb_db_vector_count, 20138c2ecf20Sopenharmony_ci .db_vector_mask = intel_ntb_db_vector_mask, 20148c2ecf20Sopenharmony_ci .db_read = intel_ntb_db_read, 20158c2ecf20Sopenharmony_ci .db_clear = intel_ntb_db_clear, 20168c2ecf20Sopenharmony_ci .db_set_mask = intel_ntb_db_set_mask, 20178c2ecf20Sopenharmony_ci .db_clear_mask = intel_ntb_db_clear_mask, 20188c2ecf20Sopenharmony_ci .peer_db_addr = intel_ntb_peer_db_addr, 20198c2ecf20Sopenharmony_ci .peer_db_set = intel_ntb_peer_db_set, 20208c2ecf20Sopenharmony_ci .spad_is_unsafe = intel_ntb_spad_is_unsafe, 20218c2ecf20Sopenharmony_ci .spad_count = intel_ntb_spad_count, 20228c2ecf20Sopenharmony_ci .spad_read = intel_ntb_spad_read, 20238c2ecf20Sopenharmony_ci .spad_write = intel_ntb_spad_write, 20248c2ecf20Sopenharmony_ci .peer_spad_addr = intel_ntb_peer_spad_addr, 20258c2ecf20Sopenharmony_ci .peer_spad_read = intel_ntb_peer_spad_read, 20268c2ecf20Sopenharmony_ci .peer_spad_write = intel_ntb_peer_spad_write, 20278c2ecf20Sopenharmony_ci}; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_cistatic const struct file_operations intel_ntb_debugfs_info = { 20308c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 20318c2ecf20Sopenharmony_ci .open = simple_open, 20328c2ecf20Sopenharmony_ci .read = ndev_debugfs_read, 20338c2ecf20Sopenharmony_ci}; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_cistatic const struct pci_device_id intel_ntb_pci_tbl[] = { 20368c2ecf20Sopenharmony_ci /* GEN1 */ 20378c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, 20388c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, 20398c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, 20408c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, 20418c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BDX)}, 20428c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, 20438c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, 20448c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, 20458c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, 20468c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_BDX)}, 20478c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, 20488c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, 20498c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, 20508c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, 20518c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_BDX)}, 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* GEN3 */ 20548c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SKX)}, 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci /* GEN4 */ 20578c2ecf20Sopenharmony_ci {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_ICX)}, 20588c2ecf20Sopenharmony_ci {0} 20598c2ecf20Sopenharmony_ci}; 20608c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_cistatic struct pci_driver intel_ntb_pci_driver = { 20638c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 20648c2ecf20Sopenharmony_ci .id_table = intel_ntb_pci_tbl, 20658c2ecf20Sopenharmony_ci .probe = intel_ntb_pci_probe, 20668c2ecf20Sopenharmony_ci .remove = intel_ntb_pci_remove, 20678c2ecf20Sopenharmony_ci}; 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_cistatic int __init intel_ntb_pci_driver_init(void) 20708c2ecf20Sopenharmony_ci{ 20718c2ecf20Sopenharmony_ci int ret; 20728c2ecf20Sopenharmony_ci pr_info("%s %s\n", NTB_DESC, NTB_VER); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (debugfs_initialized()) 20758c2ecf20Sopenharmony_ci debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci ret = pci_register_driver(&intel_ntb_pci_driver); 20788c2ecf20Sopenharmony_ci if (ret) 20798c2ecf20Sopenharmony_ci debugfs_remove_recursive(debugfs_dir); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci return ret; 20828c2ecf20Sopenharmony_ci} 20838c2ecf20Sopenharmony_cimodule_init(intel_ntb_pci_driver_init); 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_cistatic void __exit intel_ntb_pci_driver_exit(void) 20868c2ecf20Sopenharmony_ci{ 20878c2ecf20Sopenharmony_ci pci_unregister_driver(&intel_ntb_pci_driver); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci debugfs_remove_recursive(debugfs_dir); 20908c2ecf20Sopenharmony_ci} 20918c2ecf20Sopenharmony_cimodule_exit(intel_ntb_pci_driver_exit); 2092