1bf2a952dSSerge Semin /* 2bf2a952dSSerge Semin * This file is provided under a GPLv2 license. When using or 3bf2a952dSSerge Semin * redistributing this file, you may do so under that license. 4bf2a952dSSerge Semin * 5bf2a952dSSerge Semin * GPL LICENSE SUMMARY 6bf2a952dSSerge Semin * 7a662315dSSerge Semin * Copyright (C) 2016-2018 T-Platforms JSC All Rights Reserved. 8bf2a952dSSerge Semin * 9bf2a952dSSerge Semin * This program is free software; you can redistribute it and/or modify it 10bf2a952dSSerge Semin * under the terms and conditions of the GNU General Public License, 11bf2a952dSSerge Semin * version 2, as published by the Free Software Foundation. 12bf2a952dSSerge Semin * 13bf2a952dSSerge Semin * This program is distributed in the hope that it will be useful, but 14bf2a952dSSerge Semin * WITHOUT ANY WARRANTY; without even the implied warranty of 15bf2a952dSSerge Semin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 16bf2a952dSSerge Semin * Public License for more details. 17bf2a952dSSerge Semin * 18bf2a952dSSerge Semin * You should have received a copy of the GNU General Public License along 19bf2a952dSSerge Semin * with this program; if not, one can be found http://www.gnu.org/licenses/. 20bf2a952dSSerge Semin * 21bf2a952dSSerge Semin * The full GNU General Public License is included in this distribution in 22bf2a952dSSerge Semin * the file called "COPYING". 23bf2a952dSSerge Semin * 24bf2a952dSSerge Semin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25bf2a952dSSerge Semin * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26bf2a952dSSerge Semin * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27bf2a952dSSerge Semin * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28bf2a952dSSerge Semin * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29bf2a952dSSerge Semin * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30bf2a952dSSerge Semin * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31bf2a952dSSerge Semin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32bf2a952dSSerge Semin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33bf2a952dSSerge Semin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34bf2a952dSSerge Semin * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35bf2a952dSSerge Semin * 36bf2a952dSSerge Semin * IDT PCIe-switch NTB Linux driver 37bf2a952dSSerge Semin * 38bf2a952dSSerge Semin * Contact Information: 39bf2a952dSSerge Semin * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru> 40bf2a952dSSerge Semin */ 41bf2a952dSSerge Semin 42bf2a952dSSerge Semin #include <linux/stddef.h> 43bf2a952dSSerge Semin #include <linux/types.h> 44bf2a952dSSerge Semin #include <linux/kernel.h> 45bf2a952dSSerge Semin #include <linux/bitops.h> 46bf2a952dSSerge Semin #include <linux/sizes.h> 47bf2a952dSSerge Semin #include <linux/module.h> 48bf2a952dSSerge Semin #include <linux/moduleparam.h> 49bf2a952dSSerge Semin #include <linux/init.h> 50bf2a952dSSerge Semin #include <linux/interrupt.h> 51bf2a952dSSerge Semin #include <linux/spinlock.h> 52aed1b7b3SSerge Semin #include <linux/mutex.h> 53bf2a952dSSerge Semin #include <linux/pci.h> 54bf2a952dSSerge Semin #include <linux/aer.h> 55bf2a952dSSerge Semin #include <linux/slab.h> 56bf2a952dSSerge Semin #include <linux/list.h> 57bf2a952dSSerge Semin #include <linux/debugfs.h> 58aed1b7b3SSerge Semin #include <linux/hwmon.h> 59aed1b7b3SSerge Semin #include <linux/hwmon-sysfs.h> 60bf2a952dSSerge Semin #include <linux/ntb.h> 61bf2a952dSSerge Semin 62bf2a952dSSerge Semin #include "ntb_hw_idt.h" 63bf2a952dSSerge Semin 64bf2a952dSSerge Semin #define NTB_NAME "ntb_hw_idt" 65bf2a952dSSerge Semin #define NTB_DESC "IDT PCI-E Non-Transparent Bridge Driver" 66bf2a952dSSerge Semin #define NTB_VER "2.0" 67bf2a952dSSerge Semin #define NTB_IRQNAME "ntb_irq_idt" 68bf2a952dSSerge Semin 69bf2a952dSSerge Semin MODULE_DESCRIPTION(NTB_DESC); 70bf2a952dSSerge Semin MODULE_VERSION(NTB_VER); 71bf2a952dSSerge Semin MODULE_LICENSE("GPL v2"); 72bf2a952dSSerge Semin MODULE_AUTHOR("T-platforms"); 73bf2a952dSSerge Semin 74bf2a952dSSerge Semin /* 75bf2a952dSSerge Semin * NT Endpoint registers table simplifying a loop access to the functionally 76bf2a952dSSerge Semin * related registers 77bf2a952dSSerge Semin */ 78bf2a952dSSerge Semin static const struct idt_ntb_regs ntdata_tbl = { 79bf2a952dSSerge Semin { {IDT_NT_BARSETUP0, IDT_NT_BARLIMIT0, 80bf2a952dSSerge Semin IDT_NT_BARLTBASE0, IDT_NT_BARUTBASE0}, 81bf2a952dSSerge Semin {IDT_NT_BARSETUP1, IDT_NT_BARLIMIT1, 82bf2a952dSSerge Semin IDT_NT_BARLTBASE1, IDT_NT_BARUTBASE1}, 83bf2a952dSSerge Semin {IDT_NT_BARSETUP2, IDT_NT_BARLIMIT2, 84bf2a952dSSerge Semin IDT_NT_BARLTBASE2, IDT_NT_BARUTBASE2}, 85bf2a952dSSerge Semin {IDT_NT_BARSETUP3, IDT_NT_BARLIMIT3, 86bf2a952dSSerge Semin IDT_NT_BARLTBASE3, IDT_NT_BARUTBASE3}, 87bf2a952dSSerge Semin {IDT_NT_BARSETUP4, IDT_NT_BARLIMIT4, 88bf2a952dSSerge Semin IDT_NT_BARLTBASE4, IDT_NT_BARUTBASE4}, 89bf2a952dSSerge Semin {IDT_NT_BARSETUP5, IDT_NT_BARLIMIT5, 90bf2a952dSSerge Semin IDT_NT_BARLTBASE5, IDT_NT_BARUTBASE5} }, 91bf2a952dSSerge Semin { {IDT_NT_INMSG0, IDT_NT_OUTMSG0, IDT_NT_INMSGSRC0}, 92bf2a952dSSerge Semin {IDT_NT_INMSG1, IDT_NT_OUTMSG1, IDT_NT_INMSGSRC1}, 93bf2a952dSSerge Semin {IDT_NT_INMSG2, IDT_NT_OUTMSG2, IDT_NT_INMSGSRC2}, 94bf2a952dSSerge Semin {IDT_NT_INMSG3, IDT_NT_OUTMSG3, IDT_NT_INMSGSRC3} } 95bf2a952dSSerge Semin }; 96bf2a952dSSerge Semin 97bf2a952dSSerge Semin /* 98bf2a952dSSerge Semin * NT Endpoint ports data table with the corresponding pcie command, link 99bf2a952dSSerge Semin * status, control and BAR-related registers 100bf2a952dSSerge Semin */ 101bf2a952dSSerge Semin static const struct idt_ntb_port portdata_tbl[IDT_MAX_NR_PORTS] = { 102bf2a952dSSerge Semin /*0*/ { IDT_SW_NTP0_PCIECMDSTS, IDT_SW_NTP0_PCIELCTLSTS, 103bf2a952dSSerge Semin IDT_SW_NTP0_NTCTL, 104bf2a952dSSerge Semin IDT_SW_SWPORT0CTL, IDT_SW_SWPORT0STS, 105bf2a952dSSerge Semin { {IDT_SW_NTP0_BARSETUP0, IDT_SW_NTP0_BARLIMIT0, 106bf2a952dSSerge Semin IDT_SW_NTP0_BARLTBASE0, IDT_SW_NTP0_BARUTBASE0}, 107bf2a952dSSerge Semin {IDT_SW_NTP0_BARSETUP1, IDT_SW_NTP0_BARLIMIT1, 108bf2a952dSSerge Semin IDT_SW_NTP0_BARLTBASE1, IDT_SW_NTP0_BARUTBASE1}, 109bf2a952dSSerge Semin {IDT_SW_NTP0_BARSETUP2, IDT_SW_NTP0_BARLIMIT2, 110bf2a952dSSerge Semin IDT_SW_NTP0_BARLTBASE2, IDT_SW_NTP0_BARUTBASE2}, 111bf2a952dSSerge Semin {IDT_SW_NTP0_BARSETUP3, IDT_SW_NTP0_BARLIMIT3, 112bf2a952dSSerge Semin IDT_SW_NTP0_BARLTBASE3, IDT_SW_NTP0_BARUTBASE3}, 113bf2a952dSSerge Semin {IDT_SW_NTP0_BARSETUP4, IDT_SW_NTP0_BARLIMIT4, 114bf2a952dSSerge Semin IDT_SW_NTP0_BARLTBASE4, IDT_SW_NTP0_BARUTBASE4}, 115bf2a952dSSerge Semin {IDT_SW_NTP0_BARSETUP5, IDT_SW_NTP0_BARLIMIT5, 116bf2a952dSSerge Semin IDT_SW_NTP0_BARLTBASE5, IDT_SW_NTP0_BARUTBASE5} } }, 117bf2a952dSSerge Semin /*1*/ {0}, 118bf2a952dSSerge Semin /*2*/ { IDT_SW_NTP2_PCIECMDSTS, IDT_SW_NTP2_PCIELCTLSTS, 119bf2a952dSSerge Semin IDT_SW_NTP2_NTCTL, 120bf2a952dSSerge Semin IDT_SW_SWPORT2CTL, IDT_SW_SWPORT2STS, 121bf2a952dSSerge Semin { {IDT_SW_NTP2_BARSETUP0, IDT_SW_NTP2_BARLIMIT0, 122bf2a952dSSerge Semin IDT_SW_NTP2_BARLTBASE0, IDT_SW_NTP2_BARUTBASE0}, 123bf2a952dSSerge Semin {IDT_SW_NTP2_BARSETUP1, IDT_SW_NTP2_BARLIMIT1, 124bf2a952dSSerge Semin IDT_SW_NTP2_BARLTBASE1, IDT_SW_NTP2_BARUTBASE1}, 125bf2a952dSSerge Semin {IDT_SW_NTP2_BARSETUP2, IDT_SW_NTP2_BARLIMIT2, 126bf2a952dSSerge Semin IDT_SW_NTP2_BARLTBASE2, IDT_SW_NTP2_BARUTBASE2}, 127bf2a952dSSerge Semin {IDT_SW_NTP2_BARSETUP3, IDT_SW_NTP2_BARLIMIT3, 128bf2a952dSSerge Semin IDT_SW_NTP2_BARLTBASE3, IDT_SW_NTP2_BARUTBASE3}, 129bf2a952dSSerge Semin {IDT_SW_NTP2_BARSETUP4, IDT_SW_NTP2_BARLIMIT4, 130bf2a952dSSerge Semin IDT_SW_NTP2_BARLTBASE4, IDT_SW_NTP2_BARUTBASE4}, 131bf2a952dSSerge Semin {IDT_SW_NTP2_BARSETUP5, IDT_SW_NTP2_BARLIMIT5, 132bf2a952dSSerge Semin IDT_SW_NTP2_BARLTBASE5, IDT_SW_NTP2_BARUTBASE5} } }, 133bf2a952dSSerge Semin /*3*/ {0}, 134bf2a952dSSerge Semin /*4*/ { IDT_SW_NTP4_PCIECMDSTS, IDT_SW_NTP4_PCIELCTLSTS, 135bf2a952dSSerge Semin IDT_SW_NTP4_NTCTL, 136bf2a952dSSerge Semin IDT_SW_SWPORT4CTL, IDT_SW_SWPORT4STS, 137bf2a952dSSerge Semin { {IDT_SW_NTP4_BARSETUP0, IDT_SW_NTP4_BARLIMIT0, 138bf2a952dSSerge Semin IDT_SW_NTP4_BARLTBASE0, IDT_SW_NTP4_BARUTBASE0}, 139bf2a952dSSerge Semin {IDT_SW_NTP4_BARSETUP1, IDT_SW_NTP4_BARLIMIT1, 140bf2a952dSSerge Semin IDT_SW_NTP4_BARLTBASE1, IDT_SW_NTP4_BARUTBASE1}, 141bf2a952dSSerge Semin {IDT_SW_NTP4_BARSETUP2, IDT_SW_NTP4_BARLIMIT2, 142bf2a952dSSerge Semin IDT_SW_NTP4_BARLTBASE2, IDT_SW_NTP4_BARUTBASE2}, 143bf2a952dSSerge Semin {IDT_SW_NTP4_BARSETUP3, IDT_SW_NTP4_BARLIMIT3, 144bf2a952dSSerge Semin IDT_SW_NTP4_BARLTBASE3, IDT_SW_NTP4_BARUTBASE3}, 145bf2a952dSSerge Semin {IDT_SW_NTP4_BARSETUP4, IDT_SW_NTP4_BARLIMIT4, 146bf2a952dSSerge Semin IDT_SW_NTP4_BARLTBASE4, IDT_SW_NTP4_BARUTBASE4}, 147bf2a952dSSerge Semin {IDT_SW_NTP4_BARSETUP5, IDT_SW_NTP4_BARLIMIT5, 148bf2a952dSSerge Semin IDT_SW_NTP4_BARLTBASE5, IDT_SW_NTP4_BARUTBASE5} } }, 149bf2a952dSSerge Semin /*5*/ {0}, 150bf2a952dSSerge Semin /*6*/ { IDT_SW_NTP6_PCIECMDSTS, IDT_SW_NTP6_PCIELCTLSTS, 151bf2a952dSSerge Semin IDT_SW_NTP6_NTCTL, 152bf2a952dSSerge Semin IDT_SW_SWPORT6CTL, IDT_SW_SWPORT6STS, 153bf2a952dSSerge Semin { {IDT_SW_NTP6_BARSETUP0, IDT_SW_NTP6_BARLIMIT0, 154bf2a952dSSerge Semin IDT_SW_NTP6_BARLTBASE0, IDT_SW_NTP6_BARUTBASE0}, 155bf2a952dSSerge Semin {IDT_SW_NTP6_BARSETUP1, IDT_SW_NTP6_BARLIMIT1, 156bf2a952dSSerge Semin IDT_SW_NTP6_BARLTBASE1, IDT_SW_NTP6_BARUTBASE1}, 157bf2a952dSSerge Semin {IDT_SW_NTP6_BARSETUP2, IDT_SW_NTP6_BARLIMIT2, 158bf2a952dSSerge Semin IDT_SW_NTP6_BARLTBASE2, IDT_SW_NTP6_BARUTBASE2}, 159bf2a952dSSerge Semin {IDT_SW_NTP6_BARSETUP3, IDT_SW_NTP6_BARLIMIT3, 160bf2a952dSSerge Semin IDT_SW_NTP6_BARLTBASE3, IDT_SW_NTP6_BARUTBASE3}, 161bf2a952dSSerge Semin {IDT_SW_NTP6_BARSETUP4, IDT_SW_NTP6_BARLIMIT4, 162bf2a952dSSerge Semin IDT_SW_NTP6_BARLTBASE4, IDT_SW_NTP6_BARUTBASE4}, 163bf2a952dSSerge Semin {IDT_SW_NTP6_BARSETUP5, IDT_SW_NTP6_BARLIMIT5, 164bf2a952dSSerge Semin IDT_SW_NTP6_BARLTBASE5, IDT_SW_NTP6_BARUTBASE5} } }, 165bf2a952dSSerge Semin /*7*/ {0}, 166bf2a952dSSerge Semin /*8*/ { IDT_SW_NTP8_PCIECMDSTS, IDT_SW_NTP8_PCIELCTLSTS, 167bf2a952dSSerge Semin IDT_SW_NTP8_NTCTL, 168bf2a952dSSerge Semin IDT_SW_SWPORT8CTL, IDT_SW_SWPORT8STS, 169bf2a952dSSerge Semin { {IDT_SW_NTP8_BARSETUP0, IDT_SW_NTP8_BARLIMIT0, 170bf2a952dSSerge Semin IDT_SW_NTP8_BARLTBASE0, IDT_SW_NTP8_BARUTBASE0}, 171bf2a952dSSerge Semin {IDT_SW_NTP8_BARSETUP1, IDT_SW_NTP8_BARLIMIT1, 172bf2a952dSSerge Semin IDT_SW_NTP8_BARLTBASE1, IDT_SW_NTP8_BARUTBASE1}, 173bf2a952dSSerge Semin {IDT_SW_NTP8_BARSETUP2, IDT_SW_NTP8_BARLIMIT2, 174bf2a952dSSerge Semin IDT_SW_NTP8_BARLTBASE2, IDT_SW_NTP8_BARUTBASE2}, 175bf2a952dSSerge Semin {IDT_SW_NTP8_BARSETUP3, IDT_SW_NTP8_BARLIMIT3, 176bf2a952dSSerge Semin IDT_SW_NTP8_BARLTBASE3, IDT_SW_NTP8_BARUTBASE3}, 177bf2a952dSSerge Semin {IDT_SW_NTP8_BARSETUP4, IDT_SW_NTP8_BARLIMIT4, 178bf2a952dSSerge Semin IDT_SW_NTP8_BARLTBASE4, IDT_SW_NTP8_BARUTBASE4}, 179bf2a952dSSerge Semin {IDT_SW_NTP8_BARSETUP5, IDT_SW_NTP8_BARLIMIT5, 180bf2a952dSSerge Semin IDT_SW_NTP8_BARLTBASE5, IDT_SW_NTP8_BARUTBASE5} } }, 181bf2a952dSSerge Semin /*9*/ {0}, 182bf2a952dSSerge Semin /*10*/ {0}, 183bf2a952dSSerge Semin /*11*/ {0}, 184bf2a952dSSerge Semin /*12*/ { IDT_SW_NTP12_PCIECMDSTS, IDT_SW_NTP12_PCIELCTLSTS, 185bf2a952dSSerge Semin IDT_SW_NTP12_NTCTL, 186bf2a952dSSerge Semin IDT_SW_SWPORT12CTL, IDT_SW_SWPORT12STS, 187bf2a952dSSerge Semin { {IDT_SW_NTP12_BARSETUP0, IDT_SW_NTP12_BARLIMIT0, 188bf2a952dSSerge Semin IDT_SW_NTP12_BARLTBASE0, IDT_SW_NTP12_BARUTBASE0}, 189bf2a952dSSerge Semin {IDT_SW_NTP12_BARSETUP1, IDT_SW_NTP12_BARLIMIT1, 190bf2a952dSSerge Semin IDT_SW_NTP12_BARLTBASE1, IDT_SW_NTP12_BARUTBASE1}, 191bf2a952dSSerge Semin {IDT_SW_NTP12_BARSETUP2, IDT_SW_NTP12_BARLIMIT2, 192bf2a952dSSerge Semin IDT_SW_NTP12_BARLTBASE2, IDT_SW_NTP12_BARUTBASE2}, 193bf2a952dSSerge Semin {IDT_SW_NTP12_BARSETUP3, IDT_SW_NTP12_BARLIMIT3, 194bf2a952dSSerge Semin IDT_SW_NTP12_BARLTBASE3, IDT_SW_NTP12_BARUTBASE3}, 195bf2a952dSSerge Semin {IDT_SW_NTP12_BARSETUP4, IDT_SW_NTP12_BARLIMIT4, 196bf2a952dSSerge Semin IDT_SW_NTP12_BARLTBASE4, IDT_SW_NTP12_BARUTBASE4}, 197bf2a952dSSerge Semin {IDT_SW_NTP12_BARSETUP5, IDT_SW_NTP12_BARLIMIT5, 198bf2a952dSSerge Semin IDT_SW_NTP12_BARLTBASE5, IDT_SW_NTP12_BARUTBASE5} } }, 199bf2a952dSSerge Semin /*13*/ {0}, 200bf2a952dSSerge Semin /*14*/ {0}, 201bf2a952dSSerge Semin /*15*/ {0}, 202bf2a952dSSerge Semin /*16*/ { IDT_SW_NTP16_PCIECMDSTS, IDT_SW_NTP16_PCIELCTLSTS, 203bf2a952dSSerge Semin IDT_SW_NTP16_NTCTL, 204bf2a952dSSerge Semin IDT_SW_SWPORT16CTL, IDT_SW_SWPORT16STS, 205bf2a952dSSerge Semin { {IDT_SW_NTP16_BARSETUP0, IDT_SW_NTP16_BARLIMIT0, 206bf2a952dSSerge Semin IDT_SW_NTP16_BARLTBASE0, IDT_SW_NTP16_BARUTBASE0}, 207bf2a952dSSerge Semin {IDT_SW_NTP16_BARSETUP1, IDT_SW_NTP16_BARLIMIT1, 208bf2a952dSSerge Semin IDT_SW_NTP16_BARLTBASE1, IDT_SW_NTP16_BARUTBASE1}, 209bf2a952dSSerge Semin {IDT_SW_NTP16_BARSETUP2, IDT_SW_NTP16_BARLIMIT2, 210bf2a952dSSerge Semin IDT_SW_NTP16_BARLTBASE2, IDT_SW_NTP16_BARUTBASE2}, 211bf2a952dSSerge Semin {IDT_SW_NTP16_BARSETUP3, IDT_SW_NTP16_BARLIMIT3, 212bf2a952dSSerge Semin IDT_SW_NTP16_BARLTBASE3, IDT_SW_NTP16_BARUTBASE3}, 213bf2a952dSSerge Semin {IDT_SW_NTP16_BARSETUP4, IDT_SW_NTP16_BARLIMIT4, 214bf2a952dSSerge Semin IDT_SW_NTP16_BARLTBASE4, IDT_SW_NTP16_BARUTBASE4}, 215bf2a952dSSerge Semin {IDT_SW_NTP16_BARSETUP5, IDT_SW_NTP16_BARLIMIT5, 216bf2a952dSSerge Semin IDT_SW_NTP16_BARLTBASE5, IDT_SW_NTP16_BARUTBASE5} } }, 217bf2a952dSSerge Semin /*17*/ {0}, 218bf2a952dSSerge Semin /*18*/ {0}, 219bf2a952dSSerge Semin /*19*/ {0}, 220bf2a952dSSerge Semin /*20*/ { IDT_SW_NTP20_PCIECMDSTS, IDT_SW_NTP20_PCIELCTLSTS, 221bf2a952dSSerge Semin IDT_SW_NTP20_NTCTL, 222bf2a952dSSerge Semin IDT_SW_SWPORT20CTL, IDT_SW_SWPORT20STS, 223bf2a952dSSerge Semin { {IDT_SW_NTP20_BARSETUP0, IDT_SW_NTP20_BARLIMIT0, 224bf2a952dSSerge Semin IDT_SW_NTP20_BARLTBASE0, IDT_SW_NTP20_BARUTBASE0}, 225bf2a952dSSerge Semin {IDT_SW_NTP20_BARSETUP1, IDT_SW_NTP20_BARLIMIT1, 226bf2a952dSSerge Semin IDT_SW_NTP20_BARLTBASE1, IDT_SW_NTP20_BARUTBASE1}, 227bf2a952dSSerge Semin {IDT_SW_NTP20_BARSETUP2, IDT_SW_NTP20_BARLIMIT2, 228bf2a952dSSerge Semin IDT_SW_NTP20_BARLTBASE2, IDT_SW_NTP20_BARUTBASE2}, 229bf2a952dSSerge Semin {IDT_SW_NTP20_BARSETUP3, IDT_SW_NTP20_BARLIMIT3, 230bf2a952dSSerge Semin IDT_SW_NTP20_BARLTBASE3, IDT_SW_NTP20_BARUTBASE3}, 231bf2a952dSSerge Semin {IDT_SW_NTP20_BARSETUP4, IDT_SW_NTP20_BARLIMIT4, 232bf2a952dSSerge Semin IDT_SW_NTP20_BARLTBASE4, IDT_SW_NTP20_BARUTBASE4}, 233bf2a952dSSerge Semin {IDT_SW_NTP20_BARSETUP5, IDT_SW_NTP20_BARLIMIT5, 234bf2a952dSSerge Semin IDT_SW_NTP20_BARLTBASE5, IDT_SW_NTP20_BARUTBASE5} } }, 235bf2a952dSSerge Semin /*21*/ {0}, 236bf2a952dSSerge Semin /*22*/ {0}, 237bf2a952dSSerge Semin /*23*/ {0} 238bf2a952dSSerge Semin }; 239bf2a952dSSerge Semin 240bf2a952dSSerge Semin /* 241bf2a952dSSerge Semin * IDT PCIe-switch partitions table with the corresponding control, status 242bf2a952dSSerge Semin * and messages control registers 243bf2a952dSSerge Semin */ 244bf2a952dSSerge Semin static const struct idt_ntb_part partdata_tbl[IDT_MAX_NR_PARTS] = { 245bf2a952dSSerge Semin /*0*/ { IDT_SW_SWPART0CTL, IDT_SW_SWPART0STS, 246bf2a952dSSerge Semin {IDT_SW_SWP0MSGCTL0, IDT_SW_SWP0MSGCTL1, 247bf2a952dSSerge Semin IDT_SW_SWP0MSGCTL2, IDT_SW_SWP0MSGCTL3} }, 248bf2a952dSSerge Semin /*1*/ { IDT_SW_SWPART1CTL, IDT_SW_SWPART1STS, 249bf2a952dSSerge Semin {IDT_SW_SWP1MSGCTL0, IDT_SW_SWP1MSGCTL1, 250bf2a952dSSerge Semin IDT_SW_SWP1MSGCTL2, IDT_SW_SWP1MSGCTL3} }, 251bf2a952dSSerge Semin /*2*/ { IDT_SW_SWPART2CTL, IDT_SW_SWPART2STS, 252bf2a952dSSerge Semin {IDT_SW_SWP2MSGCTL0, IDT_SW_SWP2MSGCTL1, 253bf2a952dSSerge Semin IDT_SW_SWP2MSGCTL2, IDT_SW_SWP2MSGCTL3} }, 254bf2a952dSSerge Semin /*3*/ { IDT_SW_SWPART3CTL, IDT_SW_SWPART3STS, 255bf2a952dSSerge Semin {IDT_SW_SWP3MSGCTL0, IDT_SW_SWP3MSGCTL1, 256bf2a952dSSerge Semin IDT_SW_SWP3MSGCTL2, IDT_SW_SWP3MSGCTL3} }, 257bf2a952dSSerge Semin /*4*/ { IDT_SW_SWPART4CTL, IDT_SW_SWPART4STS, 258bf2a952dSSerge Semin {IDT_SW_SWP4MSGCTL0, IDT_SW_SWP4MSGCTL1, 259bf2a952dSSerge Semin IDT_SW_SWP4MSGCTL2, IDT_SW_SWP4MSGCTL3} }, 260bf2a952dSSerge Semin /*5*/ { IDT_SW_SWPART5CTL, IDT_SW_SWPART5STS, 261bf2a952dSSerge Semin {IDT_SW_SWP5MSGCTL0, IDT_SW_SWP5MSGCTL1, 262bf2a952dSSerge Semin IDT_SW_SWP5MSGCTL2, IDT_SW_SWP5MSGCTL3} }, 263bf2a952dSSerge Semin /*6*/ { IDT_SW_SWPART6CTL, IDT_SW_SWPART6STS, 264bf2a952dSSerge Semin {IDT_SW_SWP6MSGCTL0, IDT_SW_SWP6MSGCTL1, 265bf2a952dSSerge Semin IDT_SW_SWP6MSGCTL2, IDT_SW_SWP6MSGCTL3} }, 266bf2a952dSSerge Semin /*7*/ { IDT_SW_SWPART7CTL, IDT_SW_SWPART7STS, 267bf2a952dSSerge Semin {IDT_SW_SWP7MSGCTL0, IDT_SW_SWP7MSGCTL1, 268bf2a952dSSerge Semin IDT_SW_SWP7MSGCTL2, IDT_SW_SWP7MSGCTL3} } 269bf2a952dSSerge Semin }; 270bf2a952dSSerge Semin 271bf2a952dSSerge Semin /* 272bf2a952dSSerge Semin * DebugFS directory to place the driver debug file 273bf2a952dSSerge Semin */ 274bf2a952dSSerge Semin static struct dentry *dbgfs_topdir; 275bf2a952dSSerge Semin 276bf2a952dSSerge Semin /*============================================================================= 277bf2a952dSSerge Semin * 1. IDT PCIe-switch registers IO-functions 278bf2a952dSSerge Semin * 279bf2a952dSSerge Semin * Beside ordinary configuration space registers IDT PCIe-switch expose 280bf2a952dSSerge Semin * global configuration registers, which are used to determine state of other 281bf2a952dSSerge Semin * device ports as well as being notified of some switch-related events. 282bf2a952dSSerge Semin * Additionally all the configuration space registers of all the IDT 283bf2a952dSSerge Semin * PCIe-switch functions are mapped to the Global Address space, so each 284bf2a952dSSerge Semin * function can determine a configuration of any other PCI-function. 285bf2a952dSSerge Semin * Functions declared in this chapter are created to encapsulate access 286bf2a952dSSerge Semin * to configuration and global registers, so the driver code just need to 287bf2a952dSSerge Semin * provide IDT NTB hardware descriptor and a register address. 288bf2a952dSSerge Semin *============================================================================= 289bf2a952dSSerge Semin */ 290bf2a952dSSerge Semin 291bf2a952dSSerge Semin /* 292bf2a952dSSerge Semin * idt_nt_write() - PCI configuration space registers write method 293bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 294bf2a952dSSerge Semin * @reg: Register to write data to 295bf2a952dSSerge Semin * @data: Value to write to the register 296bf2a952dSSerge Semin * 297bf2a952dSSerge Semin * IDT PCIe-switch registers are all Little endian. 298bf2a952dSSerge Semin */ 299bf2a952dSSerge Semin static void idt_nt_write(struct idt_ntb_dev *ndev, 300bf2a952dSSerge Semin const unsigned int reg, const u32 data) 301bf2a952dSSerge Semin { 302bf2a952dSSerge Semin /* 303bf2a952dSSerge Semin * It's obvious bug to request a register exceeding the maximum possible 304bf2a952dSSerge Semin * value as well as to have it unaligned. 305bf2a952dSSerge Semin */ 306bf2a952dSSerge Semin if (WARN_ON(reg > IDT_REG_PCI_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN))) 307bf2a952dSSerge Semin return; 308bf2a952dSSerge Semin 309bf2a952dSSerge Semin /* Just write the value to the specified register */ 310bf2a952dSSerge Semin iowrite32(data, ndev->cfgspc + (ptrdiff_t)reg); 311bf2a952dSSerge Semin } 312bf2a952dSSerge Semin 313bf2a952dSSerge Semin /* 314bf2a952dSSerge Semin * idt_nt_read() - PCI configuration space registers read method 315bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 316bf2a952dSSerge Semin * @reg: Register to write data to 317bf2a952dSSerge Semin * 318bf2a952dSSerge Semin * IDT PCIe-switch Global configuration registers are all Little endian. 319bf2a952dSSerge Semin * 320bf2a952dSSerge Semin * Return: register value 321bf2a952dSSerge Semin */ 322bf2a952dSSerge Semin static u32 idt_nt_read(struct idt_ntb_dev *ndev, const unsigned int reg) 323bf2a952dSSerge Semin { 324bf2a952dSSerge Semin /* 325bf2a952dSSerge Semin * It's obvious bug to request a register exceeding the maximum possible 326bf2a952dSSerge Semin * value as well as to have it unaligned. 327bf2a952dSSerge Semin */ 328bf2a952dSSerge Semin if (WARN_ON(reg > IDT_REG_PCI_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN))) 329bf2a952dSSerge Semin return ~0; 330bf2a952dSSerge Semin 331bf2a952dSSerge Semin /* Just read the value from the specified register */ 332bf2a952dSSerge Semin return ioread32(ndev->cfgspc + (ptrdiff_t)reg); 333bf2a952dSSerge Semin } 334bf2a952dSSerge Semin 335bf2a952dSSerge Semin /* 336bf2a952dSSerge Semin * idt_sw_write() - Global registers write method 337bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 338bf2a952dSSerge Semin * @reg: Register to write data to 339bf2a952dSSerge Semin * @data: Value to write to the register 340bf2a952dSSerge Semin * 341bf2a952dSSerge Semin * IDT PCIe-switch Global configuration registers are all Little endian. 342bf2a952dSSerge Semin */ 343bf2a952dSSerge Semin static void idt_sw_write(struct idt_ntb_dev *ndev, 344bf2a952dSSerge Semin const unsigned int reg, const u32 data) 345bf2a952dSSerge Semin { 346bf2a952dSSerge Semin unsigned long irqflags; 347bf2a952dSSerge Semin 348bf2a952dSSerge Semin /* 349bf2a952dSSerge Semin * It's obvious bug to request a register exceeding the maximum possible 350bf2a952dSSerge Semin * value as well as to have it unaligned. 351bf2a952dSSerge Semin */ 352bf2a952dSSerge Semin if (WARN_ON(reg > IDT_REG_SW_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN))) 353bf2a952dSSerge Semin return; 354bf2a952dSSerge Semin 355bf2a952dSSerge Semin /* Lock GASA registers operations */ 356bf2a952dSSerge Semin spin_lock_irqsave(&ndev->gasa_lock, irqflags); 357bf2a952dSSerge Semin /* Set the global register address */ 358bf2a952dSSerge Semin iowrite32((u32)reg, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASAADDR); 359bf2a952dSSerge Semin /* Put the new value of the register */ 360bf2a952dSSerge Semin iowrite32(data, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASADATA); 361bf2a952dSSerge Semin /* Unlock GASA registers operations */ 362bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->gasa_lock, irqflags); 363bf2a952dSSerge Semin } 364bf2a952dSSerge Semin 365bf2a952dSSerge Semin /* 366bf2a952dSSerge Semin * idt_sw_read() - Global registers read method 367bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 368bf2a952dSSerge Semin * @reg: Register to write data to 369bf2a952dSSerge Semin * 370bf2a952dSSerge Semin * IDT PCIe-switch Global configuration registers are all Little endian. 371bf2a952dSSerge Semin * 372bf2a952dSSerge Semin * Return: register value 373bf2a952dSSerge Semin */ 374bf2a952dSSerge Semin static u32 idt_sw_read(struct idt_ntb_dev *ndev, const unsigned int reg) 375bf2a952dSSerge Semin { 376bf2a952dSSerge Semin unsigned long irqflags; 377bf2a952dSSerge Semin u32 data; 378bf2a952dSSerge Semin 379bf2a952dSSerge Semin /* 380bf2a952dSSerge Semin * It's obvious bug to request a register exceeding the maximum possible 381bf2a952dSSerge Semin * value as well as to have it unaligned. 382bf2a952dSSerge Semin */ 383bf2a952dSSerge Semin if (WARN_ON(reg > IDT_REG_SW_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN))) 384bf2a952dSSerge Semin return ~0; 385bf2a952dSSerge Semin 386bf2a952dSSerge Semin /* Lock GASA registers operations */ 387bf2a952dSSerge Semin spin_lock_irqsave(&ndev->gasa_lock, irqflags); 388bf2a952dSSerge Semin /* Set the global register address */ 389bf2a952dSSerge Semin iowrite32((u32)reg, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASAADDR); 390bf2a952dSSerge Semin /* Get the data of the register (read ops acts as MMIO barrier) */ 391bf2a952dSSerge Semin data = ioread32(ndev->cfgspc + (ptrdiff_t)IDT_NT_GASADATA); 392bf2a952dSSerge Semin /* Unlock GASA registers operations */ 393bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->gasa_lock, irqflags); 394bf2a952dSSerge Semin 395bf2a952dSSerge Semin return data; 396bf2a952dSSerge Semin } 397bf2a952dSSerge Semin 398bf2a952dSSerge Semin /* 399bf2a952dSSerge Semin * idt_reg_set_bits() - set bits of a passed register 400bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 401bf2a952dSSerge Semin * @reg: Register to change bits of 402bf2a952dSSerge Semin * @reg_lock: Register access spin lock 403bf2a952dSSerge Semin * @valid_mask: Mask of valid bits 404bf2a952dSSerge Semin * @set_bits: Bitmask to set 405bf2a952dSSerge Semin * 406bf2a952dSSerge Semin * Helper method to check whether a passed bitfield is valid and set 407bf2a952dSSerge Semin * corresponding bits of a register. 408bf2a952dSSerge Semin * 409bf2a952dSSerge Semin * WARNING! Make sure the passed register isn't accessed over plane 410bf2a952dSSerge Semin * idt_nt_write() method (read method is ok to be used concurrently). 411bf2a952dSSerge Semin * 412bf2a952dSSerge Semin * Return: zero on success, negative error on invalid bitmask. 413bf2a952dSSerge Semin */ 414bf2a952dSSerge Semin static inline int idt_reg_set_bits(struct idt_ntb_dev *ndev, unsigned int reg, 415bf2a952dSSerge Semin spinlock_t *reg_lock, 416bf2a952dSSerge Semin u64 valid_mask, u64 set_bits) 417bf2a952dSSerge Semin { 418bf2a952dSSerge Semin unsigned long irqflags; 419bf2a952dSSerge Semin u32 data; 420bf2a952dSSerge Semin 421bf2a952dSSerge Semin if (set_bits & ~(u64)valid_mask) 422bf2a952dSSerge Semin return -EINVAL; 423bf2a952dSSerge Semin 424bf2a952dSSerge Semin /* Lock access to the register unless the change is written back */ 425bf2a952dSSerge Semin spin_lock_irqsave(reg_lock, irqflags); 426bf2a952dSSerge Semin data = idt_nt_read(ndev, reg) | (u32)set_bits; 427bf2a952dSSerge Semin idt_nt_write(ndev, reg, data); 428bf2a952dSSerge Semin /* Unlock the register */ 429bf2a952dSSerge Semin spin_unlock_irqrestore(reg_lock, irqflags); 430bf2a952dSSerge Semin 431bf2a952dSSerge Semin return 0; 432bf2a952dSSerge Semin } 433bf2a952dSSerge Semin 434bf2a952dSSerge Semin /* 435bf2a952dSSerge Semin * idt_reg_clear_bits() - clear bits of a passed register 436bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 437bf2a952dSSerge Semin * @reg: Register to change bits of 438bf2a952dSSerge Semin * @reg_lock: Register access spin lock 439bf2a952dSSerge Semin * @set_bits: Bitmask to clear 440bf2a952dSSerge Semin * 441bf2a952dSSerge Semin * Helper method to check whether a passed bitfield is valid and clear 442bf2a952dSSerge Semin * corresponding bits of a register. 443bf2a952dSSerge Semin * 444bf2a952dSSerge Semin * NOTE! Invalid bits are always considered cleared so it's not an error 445bf2a952dSSerge Semin * to clear them over. 446bf2a952dSSerge Semin * 447bf2a952dSSerge Semin * WARNING! Make sure the passed register isn't accessed over plane 448bf2a952dSSerge Semin * idt_nt_write() method (read method is ok to use concurrently). 449bf2a952dSSerge Semin */ 450bf2a952dSSerge Semin static inline void idt_reg_clear_bits(struct idt_ntb_dev *ndev, 451bf2a952dSSerge Semin unsigned int reg, spinlock_t *reg_lock, 452bf2a952dSSerge Semin u64 clear_bits) 453bf2a952dSSerge Semin { 454bf2a952dSSerge Semin unsigned long irqflags; 455bf2a952dSSerge Semin u32 data; 456bf2a952dSSerge Semin 457bf2a952dSSerge Semin /* Lock access to the register unless the change is written back */ 458bf2a952dSSerge Semin spin_lock_irqsave(reg_lock, irqflags); 459bf2a952dSSerge Semin data = idt_nt_read(ndev, reg) & ~(u32)clear_bits; 460bf2a952dSSerge Semin idt_nt_write(ndev, reg, data); 461bf2a952dSSerge Semin /* Unlock the register */ 462bf2a952dSSerge Semin spin_unlock_irqrestore(reg_lock, irqflags); 463bf2a952dSSerge Semin } 464bf2a952dSSerge Semin 465bf2a952dSSerge Semin /*=========================================================================== 466bf2a952dSSerge Semin * 2. Ports operations 467bf2a952dSSerge Semin * 468bf2a952dSSerge Semin * IDT PCIe-switches can have from 3 up to 8 ports with possible 469bf2a952dSSerge Semin * NT-functions enabled. So all the possible ports need to be scanned looking 470bf2a952dSSerge Semin * for NTB activated. NTB API will have enumerated only the ports with NTB. 471bf2a952dSSerge Semin *=========================================================================== 472bf2a952dSSerge Semin */ 473bf2a952dSSerge Semin 474bf2a952dSSerge Semin /* 475bf2a952dSSerge Semin * idt_scan_ports() - scan IDT PCIe-switch ports collecting info in the tables 476bf2a952dSSerge Semin * @ndev: Pointer to the PCI device descriptor 477bf2a952dSSerge Semin * 478bf2a952dSSerge Semin * Return: zero on success, otherwise a negative error number. 479bf2a952dSSerge Semin */ 480bf2a952dSSerge Semin static int idt_scan_ports(struct idt_ntb_dev *ndev) 481bf2a952dSSerge Semin { 482bf2a952dSSerge Semin unsigned char pidx, port, part; 483bf2a952dSSerge Semin u32 data, portsts, partsts; 484bf2a952dSSerge Semin 485bf2a952dSSerge Semin /* Retrieve the local port number */ 486bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_PCIELCAP); 487bf2a952dSSerge Semin ndev->port = GET_FIELD(PCIELCAP_PORTNUM, data); 488bf2a952dSSerge Semin 489bf2a952dSSerge Semin /* Retrieve the local partition number */ 490bf2a952dSSerge Semin portsts = idt_sw_read(ndev, portdata_tbl[ndev->port].sts); 491bf2a952dSSerge Semin ndev->part = GET_FIELD(SWPORTxSTS_SWPART, portsts); 492bf2a952dSSerge Semin 493bf2a952dSSerge Semin /* Initialize port/partition -> index tables with invalid values */ 494bf2a952dSSerge Semin memset(ndev->port_idx_map, -EINVAL, sizeof(ndev->port_idx_map)); 495bf2a952dSSerge Semin memset(ndev->part_idx_map, -EINVAL, sizeof(ndev->part_idx_map)); 496bf2a952dSSerge Semin 497bf2a952dSSerge Semin /* 498bf2a952dSSerge Semin * Walk over all the possible ports checking whether any of them has 499bf2a952dSSerge Semin * NT-function activated 500bf2a952dSSerge Semin */ 501bf2a952dSSerge Semin ndev->peer_cnt = 0; 502bf2a952dSSerge Semin for (pidx = 0; pidx < ndev->swcfg->port_cnt; pidx++) { 503bf2a952dSSerge Semin port = ndev->swcfg->ports[pidx]; 504bf2a952dSSerge Semin /* Skip local port */ 505bf2a952dSSerge Semin if (port == ndev->port) 506bf2a952dSSerge Semin continue; 507bf2a952dSSerge Semin 508bf2a952dSSerge Semin /* Read the port status register to get it partition */ 509bf2a952dSSerge Semin portsts = idt_sw_read(ndev, portdata_tbl[port].sts); 510bf2a952dSSerge Semin part = GET_FIELD(SWPORTxSTS_SWPART, portsts); 511bf2a952dSSerge Semin 512bf2a952dSSerge Semin /* Retrieve the partition status */ 513bf2a952dSSerge Semin partsts = idt_sw_read(ndev, partdata_tbl[part].sts); 514bf2a952dSSerge Semin /* Check if partition state is active and port has NTB */ 515bf2a952dSSerge Semin if (IS_FLD_SET(SWPARTxSTS_STATE, partsts, ACT) && 516bf2a952dSSerge Semin (IS_FLD_SET(SWPORTxSTS_MODE, portsts, NT) || 517bf2a952dSSerge Semin IS_FLD_SET(SWPORTxSTS_MODE, portsts, USNT) || 518bf2a952dSSerge Semin IS_FLD_SET(SWPORTxSTS_MODE, portsts, USNTDMA) || 519bf2a952dSSerge Semin IS_FLD_SET(SWPORTxSTS_MODE, portsts, NTDMA))) { 520bf2a952dSSerge Semin /* Save the port and partition numbers */ 521bf2a952dSSerge Semin ndev->peers[ndev->peer_cnt].port = port; 522bf2a952dSSerge Semin ndev->peers[ndev->peer_cnt].part = part; 523bf2a952dSSerge Semin /* Fill in the port/partition -> index tables */ 524bf2a952dSSerge Semin ndev->port_idx_map[port] = ndev->peer_cnt; 525bf2a952dSSerge Semin ndev->part_idx_map[part] = ndev->peer_cnt; 526bf2a952dSSerge Semin ndev->peer_cnt++; 527bf2a952dSSerge Semin } 528bf2a952dSSerge Semin } 529bf2a952dSSerge Semin 530bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "Local port: %hhu, num of peers: %hhu\n", 531bf2a952dSSerge Semin ndev->port, ndev->peer_cnt); 532bf2a952dSSerge Semin 533bf2a952dSSerge Semin /* It's useless to have this driver loaded if there is no any peer */ 534bf2a952dSSerge Semin if (ndev->peer_cnt == 0) { 535bf2a952dSSerge Semin dev_warn(&ndev->ntb.pdev->dev, "No active peer found\n"); 536bf2a952dSSerge Semin return -ENODEV; 537bf2a952dSSerge Semin } 538bf2a952dSSerge Semin 539bf2a952dSSerge Semin return 0; 540bf2a952dSSerge Semin } 541bf2a952dSSerge Semin 542bf2a952dSSerge Semin /* 543bf2a952dSSerge Semin * idt_ntb_port_number() - get the local port number 544bf2a952dSSerge Semin * @ntb: NTB device context. 545bf2a952dSSerge Semin * 546bf2a952dSSerge Semin * Return: the local port number 547bf2a952dSSerge Semin */ 548bf2a952dSSerge Semin static int idt_ntb_port_number(struct ntb_dev *ntb) 549bf2a952dSSerge Semin { 550bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 551bf2a952dSSerge Semin 552bf2a952dSSerge Semin return ndev->port; 553bf2a952dSSerge Semin } 554bf2a952dSSerge Semin 555bf2a952dSSerge Semin /* 556bf2a952dSSerge Semin * idt_ntb_peer_port_count() - get the number of peer ports 557bf2a952dSSerge Semin * @ntb: NTB device context. 558bf2a952dSSerge Semin * 559bf2a952dSSerge Semin * Return the count of detected peer NT-functions. 560bf2a952dSSerge Semin * 561bf2a952dSSerge Semin * Return: number of peer ports 562bf2a952dSSerge Semin */ 563bf2a952dSSerge Semin static int idt_ntb_peer_port_count(struct ntb_dev *ntb) 564bf2a952dSSerge Semin { 565bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 566bf2a952dSSerge Semin 567bf2a952dSSerge Semin return ndev->peer_cnt; 568bf2a952dSSerge Semin } 569bf2a952dSSerge Semin 570bf2a952dSSerge Semin /* 571bf2a952dSSerge Semin * idt_ntb_peer_port_number() - get peer port by given index 572bf2a952dSSerge Semin * @ntb: NTB device context. 573bf2a952dSSerge Semin * @pidx: Peer port index. 574bf2a952dSSerge Semin * 575bf2a952dSSerge Semin * Return: peer port or negative error 576bf2a952dSSerge Semin */ 577bf2a952dSSerge Semin static int idt_ntb_peer_port_number(struct ntb_dev *ntb, int pidx) 578bf2a952dSSerge Semin { 579bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 580bf2a952dSSerge Semin 581bf2a952dSSerge Semin if (pidx < 0 || ndev->peer_cnt <= pidx) 582bf2a952dSSerge Semin return -EINVAL; 583bf2a952dSSerge Semin 584bf2a952dSSerge Semin /* Return the detected NT-function port number */ 585bf2a952dSSerge Semin return ndev->peers[pidx].port; 586bf2a952dSSerge Semin } 587bf2a952dSSerge Semin 588bf2a952dSSerge Semin /* 589bf2a952dSSerge Semin * idt_ntb_peer_port_idx() - get peer port index by given port number 590bf2a952dSSerge Semin * @ntb: NTB device context. 591bf2a952dSSerge Semin * @port: Peer port number. 592bf2a952dSSerge Semin * 593bf2a952dSSerge Semin * Internal port -> index table is pre-initialized with -EINVAL values, 594bf2a952dSSerge Semin * so we just need to return it value 595bf2a952dSSerge Semin * 596bf2a952dSSerge Semin * Return: peer NT-function port index or negative error 597bf2a952dSSerge Semin */ 598bf2a952dSSerge Semin static int idt_ntb_peer_port_idx(struct ntb_dev *ntb, int port) 599bf2a952dSSerge Semin { 600bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 601bf2a952dSSerge Semin 602bf2a952dSSerge Semin if (port < 0 || IDT_MAX_NR_PORTS <= port) 603bf2a952dSSerge Semin return -EINVAL; 604bf2a952dSSerge Semin 605bf2a952dSSerge Semin return ndev->port_idx_map[port]; 606bf2a952dSSerge Semin } 607bf2a952dSSerge Semin 608bf2a952dSSerge Semin /*=========================================================================== 609bf2a952dSSerge Semin * 3. Link status operations 610bf2a952dSSerge Semin * There is no any ready-to-use method to have peer ports notified if NTB 611bf2a952dSSerge Semin * link is set up or got down. Instead global signal can be used instead. 612bf2a952dSSerge Semin * In case if any one of ports changes local NTB link state, it sends 613bf2a952dSSerge Semin * global signal and clears corresponding global state bit. Then all the ports 614bf2a952dSSerge Semin * receive a notification of that, so to make client driver being aware of 615bf2a952dSSerge Semin * possible NTB link change. 616bf2a952dSSerge Semin * Additionally each of active NT-functions is subscribed to PCIe-link 617bf2a952dSSerge Semin * state changes of peer ports. 618bf2a952dSSerge Semin *=========================================================================== 619bf2a952dSSerge Semin */ 620bf2a952dSSerge Semin 621bf2a952dSSerge Semin static void idt_ntb_local_link_disable(struct idt_ntb_dev *ndev); 622bf2a952dSSerge Semin 623bf2a952dSSerge Semin /* 624bf2a952dSSerge Semin * idt_init_link() - Initialize NTB link state notification subsystem 625bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 626bf2a952dSSerge Semin * 627bf2a952dSSerge Semin * Function performs the basic initialization of some global registers 628bf2a952dSSerge Semin * needed to enable IRQ-based notifications of PCIe Link Up/Down and 629bf2a952dSSerge Semin * Global Signal events. 630bf2a952dSSerge Semin * NOTE Since it's not possible to determine when all the NTB peer drivers are 631bf2a952dSSerge Semin * unloaded as well as have those registers accessed concurrently, we must 632bf2a952dSSerge Semin * preinitialize them with the same value and leave it uncleared on local 633bf2a952dSSerge Semin * driver unload. 634bf2a952dSSerge Semin */ 635bf2a952dSSerge Semin static void idt_init_link(struct idt_ntb_dev *ndev) 636bf2a952dSSerge Semin { 637bf2a952dSSerge Semin u32 part_mask, port_mask, se_mask; 638bf2a952dSSerge Semin unsigned char pidx; 639bf2a952dSSerge Semin 640bf2a952dSSerge Semin /* Initialize spin locker of Mapping Table access registers */ 641bf2a952dSSerge Semin spin_lock_init(&ndev->mtbl_lock); 642bf2a952dSSerge Semin 643bf2a952dSSerge Semin /* Walk over all detected peers collecting port and partition masks */ 644bf2a952dSSerge Semin port_mask = ~BIT(ndev->port); 645bf2a952dSSerge Semin part_mask = ~BIT(ndev->part); 646bf2a952dSSerge Semin for (pidx = 0; pidx < ndev->peer_cnt; pidx++) { 647bf2a952dSSerge Semin port_mask &= ~BIT(ndev->peers[pidx].port); 648bf2a952dSSerge Semin part_mask &= ~BIT(ndev->peers[pidx].part); 649bf2a952dSSerge Semin } 650bf2a952dSSerge Semin 651bf2a952dSSerge Semin /* Clean the Link Up/Down and GLobal Signal status registers */ 652bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SELINKUPSTS, (u32)-1); 653bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SELINKDNSTS, (u32)-1); 654bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)-1); 655bf2a952dSSerge Semin 656bf2a952dSSerge Semin /* Unmask NT-activated partitions to receive Global Switch events */ 657bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SEPMSK, part_mask); 658bf2a952dSSerge Semin 659bf2a952dSSerge Semin /* Enable PCIe Link Up events of NT-activated ports */ 660bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SELINKUPMSK, port_mask); 661bf2a952dSSerge Semin 662bf2a952dSSerge Semin /* Enable PCIe Link Down events of NT-activated ports */ 663bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SELINKDNMSK, port_mask); 664bf2a952dSSerge Semin 665bf2a952dSSerge Semin /* Unmask NT-activated partitions to receive Global Signal events */ 666bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SEGSIGMSK, part_mask); 667bf2a952dSSerge Semin 668bf2a952dSSerge Semin /* Unmask Link Up/Down and Global Switch Events */ 669bf2a952dSSerge Semin se_mask = ~(IDT_SEMSK_LINKUP | IDT_SEMSK_LINKDN | IDT_SEMSK_GSIGNAL); 670bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SEMSK, se_mask); 671bf2a952dSSerge Semin 672bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "NTB link status events initialized"); 673bf2a952dSSerge Semin } 674bf2a952dSSerge Semin 675bf2a952dSSerge Semin /* 676bf2a952dSSerge Semin * idt_deinit_link() - deinitialize link subsystem 677bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 678bf2a952dSSerge Semin * 679bf2a952dSSerge Semin * Just disable the link back. 680bf2a952dSSerge Semin */ 681bf2a952dSSerge Semin static void idt_deinit_link(struct idt_ntb_dev *ndev) 682bf2a952dSSerge Semin { 683bf2a952dSSerge Semin /* Disable the link */ 684bf2a952dSSerge Semin idt_ntb_local_link_disable(ndev); 685bf2a952dSSerge Semin 686bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "NTB link status events deinitialized"); 687bf2a952dSSerge Semin } 688bf2a952dSSerge Semin 689bf2a952dSSerge Semin /* 690bf2a952dSSerge Semin * idt_se_isr() - switch events ISR 691bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 692bf2a952dSSerge Semin * @ntint_sts: NT-function interrupt status 693bf2a952dSSerge Semin * 694bf2a952dSSerge Semin * This driver doesn't support IDT PCIe-switch dynamic reconfigurations, 695bf2a952dSSerge Semin * Failover capability, etc, so switch events are utilized to notify of 696bf2a952dSSerge Semin * PCIe and NTB link events. 697bf2a952dSSerge Semin * The method is called from PCIe ISR bottom-half routine. 698bf2a952dSSerge Semin */ 699bf2a952dSSerge Semin static void idt_se_isr(struct idt_ntb_dev *ndev, u32 ntint_sts) 700bf2a952dSSerge Semin { 701bf2a952dSSerge Semin u32 sests; 702bf2a952dSSerge Semin 703bf2a952dSSerge Semin /* Read Switch Events status */ 704bf2a952dSSerge Semin sests = idt_sw_read(ndev, IDT_SW_SESTS); 705bf2a952dSSerge Semin 706bf2a952dSSerge Semin /* Clean the Link Up/Down and Global Signal status registers */ 707bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SELINKUPSTS, (u32)-1); 708bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SELINKDNSTS, (u32)-1); 709bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)-1); 710bf2a952dSSerge Semin 711bf2a952dSSerge Semin /* Clean the corresponding interrupt bit */ 712bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_SEVENT); 713bf2a952dSSerge Semin 714bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "SE IRQ detected %#08x (SESTS %#08x)", 715bf2a952dSSerge Semin ntint_sts, sests); 716bf2a952dSSerge Semin 717bf2a952dSSerge Semin /* Notify the client driver of possible link state change */ 718bf2a952dSSerge Semin ntb_link_event(&ndev->ntb); 719bf2a952dSSerge Semin } 720bf2a952dSSerge Semin 721bf2a952dSSerge Semin /* 722bf2a952dSSerge Semin * idt_ntb_local_link_enable() - enable the local NTB link. 723bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 724bf2a952dSSerge Semin * 725bf2a952dSSerge Semin * In order to enable the NTB link we need: 726bf2a952dSSerge Semin * - enable Completion TLPs translation 727bf2a952dSSerge Semin * - initialize mapping table to enable the Request ID translation 728bf2a952dSSerge Semin * - notify peers of NTB link state change 729bf2a952dSSerge Semin */ 730bf2a952dSSerge Semin static void idt_ntb_local_link_enable(struct idt_ntb_dev *ndev) 731bf2a952dSSerge Semin { 732bf2a952dSSerge Semin u32 reqid, mtbldata = 0; 733bf2a952dSSerge Semin unsigned long irqflags; 734bf2a952dSSerge Semin 735bf2a952dSSerge Semin /* Enable the ID protection and Completion TLPs translation */ 736bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTCTL, IDT_NTCTL_CPEN); 737bf2a952dSSerge Semin 738bf2a952dSSerge Semin /* Retrieve the current Requester ID (Bus:Device:Function) */ 739bf2a952dSSerge Semin reqid = idt_nt_read(ndev, IDT_NT_REQIDCAP); 740bf2a952dSSerge Semin 741bf2a952dSSerge Semin /* 742bf2a952dSSerge Semin * Set the corresponding NT Mapping table entry of port partition index 743bf2a952dSSerge Semin * with the data to perform the Request ID translation 744bf2a952dSSerge Semin */ 745bf2a952dSSerge Semin mtbldata = SET_FIELD(NTMTBLDATA_REQID, 0, reqid) | 746bf2a952dSSerge Semin SET_FIELD(NTMTBLDATA_PART, 0, ndev->part) | 747bf2a952dSSerge Semin IDT_NTMTBLDATA_VALID; 748bf2a952dSSerge Semin spin_lock_irqsave(&ndev->mtbl_lock, irqflags); 749bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part); 750bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTMTBLDATA, mtbldata); 751bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags); 752bf2a952dSSerge Semin 753bf2a952dSSerge Semin /* Notify the peers by setting and clearing the global signal bit */ 754bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTGSIGNAL, IDT_NTGSIGNAL_SET); 755bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)1 << ndev->part); 756bf2a952dSSerge Semin } 757bf2a952dSSerge Semin 758bf2a952dSSerge Semin /* 759bf2a952dSSerge Semin * idt_ntb_local_link_disable() - disable the local NTB link. 760bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 761bf2a952dSSerge Semin * 762bf2a952dSSerge Semin * In order to enable the NTB link we need: 763bf2a952dSSerge Semin * - disable Completion TLPs translation 764bf2a952dSSerge Semin * - clear corresponding mapping table entry 765bf2a952dSSerge Semin * - notify peers of NTB link state change 766bf2a952dSSerge Semin */ 767bf2a952dSSerge Semin static void idt_ntb_local_link_disable(struct idt_ntb_dev *ndev) 768bf2a952dSSerge Semin { 769bf2a952dSSerge Semin unsigned long irqflags; 770bf2a952dSSerge Semin 771bf2a952dSSerge Semin /* Disable Completion TLPs translation */ 772bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTCTL, 0); 773bf2a952dSSerge Semin 774bf2a952dSSerge Semin /* Clear the corresponding NT Mapping table entry */ 775bf2a952dSSerge Semin spin_lock_irqsave(&ndev->mtbl_lock, irqflags); 776bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part); 777bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTMTBLDATA, 0); 778bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags); 779bf2a952dSSerge Semin 780bf2a952dSSerge Semin /* Notify the peers by setting and clearing the global signal bit */ 781bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTGSIGNAL, IDT_NTGSIGNAL_SET); 782bf2a952dSSerge Semin idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)1 << ndev->part); 783bf2a952dSSerge Semin } 784bf2a952dSSerge Semin 785bf2a952dSSerge Semin /* 786bf2a952dSSerge Semin * idt_ntb_local_link_is_up() - test wethter local NTB link is up 787bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 788bf2a952dSSerge Semin * 789bf2a952dSSerge Semin * Local link is up under the following conditions: 790bf2a952dSSerge Semin * - Bus mastering is enabled 791bf2a952dSSerge Semin * - NTCTL has Completion TLPs translation enabled 792bf2a952dSSerge Semin * - Mapping table permits Request TLPs translation 793bf2a952dSSerge Semin * NOTE: We don't need to check PCIe link state since it's obviously 794bf2a952dSSerge Semin * up while we are able to communicate with IDT PCIe-switch 795bf2a952dSSerge Semin * 796bf2a952dSSerge Semin * Return: true if link is up, otherwise false 797bf2a952dSSerge Semin */ 798bf2a952dSSerge Semin static bool idt_ntb_local_link_is_up(struct idt_ntb_dev *ndev) 799bf2a952dSSerge Semin { 800bf2a952dSSerge Semin unsigned long irqflags; 801bf2a952dSSerge Semin u32 data; 802bf2a952dSSerge Semin 803bf2a952dSSerge Semin /* Read the local Bus Master Enable status */ 804bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_PCICMDSTS); 805bf2a952dSSerge Semin if (!(data & IDT_PCICMDSTS_BME)) 806bf2a952dSSerge Semin return false; 807bf2a952dSSerge Semin 808bf2a952dSSerge Semin /* Read the local Completion TLPs translation enable status */ 809bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_NTCTL); 810bf2a952dSSerge Semin if (!(data & IDT_NTCTL_CPEN)) 811bf2a952dSSerge Semin return false; 812bf2a952dSSerge Semin 813bf2a952dSSerge Semin /* Read Mapping table entry corresponding to the local partition */ 814bf2a952dSSerge Semin spin_lock_irqsave(&ndev->mtbl_lock, irqflags); 815bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part); 816bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA); 817bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags); 818bf2a952dSSerge Semin 819bf2a952dSSerge Semin return !!(data & IDT_NTMTBLDATA_VALID); 820bf2a952dSSerge Semin } 821bf2a952dSSerge Semin 822bf2a952dSSerge Semin /* 823bf2a952dSSerge Semin * idt_ntb_peer_link_is_up() - test whether peer NTB link is up 824bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 825bf2a952dSSerge Semin * @pidx: Peer port index 826bf2a952dSSerge Semin * 827bf2a952dSSerge Semin * Peer link is up under the following conditions: 828bf2a952dSSerge Semin * - PCIe link is up 829bf2a952dSSerge Semin * - Bus mastering is enabled 830bf2a952dSSerge Semin * - NTCTL has Completion TLPs translation enabled 831bf2a952dSSerge Semin * - Mapping table permits Request TLPs translation 832bf2a952dSSerge Semin * 833bf2a952dSSerge Semin * Return: true if link is up, otherwise false 834bf2a952dSSerge Semin */ 835bf2a952dSSerge Semin static bool idt_ntb_peer_link_is_up(struct idt_ntb_dev *ndev, int pidx) 836bf2a952dSSerge Semin { 837bf2a952dSSerge Semin unsigned long irqflags; 838bf2a952dSSerge Semin unsigned char port; 839bf2a952dSSerge Semin u32 data; 840bf2a952dSSerge Semin 841bf2a952dSSerge Semin /* Retrieve the device port number */ 842bf2a952dSSerge Semin port = ndev->peers[pidx].port; 843bf2a952dSSerge Semin 844bf2a952dSSerge Semin /* Check whether PCIe link is up */ 845bf2a952dSSerge Semin data = idt_sw_read(ndev, portdata_tbl[port].sts); 846bf2a952dSSerge Semin if (!(data & IDT_SWPORTxSTS_LINKUP)) 847bf2a952dSSerge Semin return false; 848bf2a952dSSerge Semin 849bf2a952dSSerge Semin /* Check whether bus mastering is enabled on the peer port */ 850bf2a952dSSerge Semin data = idt_sw_read(ndev, portdata_tbl[port].pcicmdsts); 851bf2a952dSSerge Semin if (!(data & IDT_PCICMDSTS_BME)) 852bf2a952dSSerge Semin return false; 853bf2a952dSSerge Semin 854bf2a952dSSerge Semin /* Check if Completion TLPs translation is enabled on the peer port */ 855bf2a952dSSerge Semin data = idt_sw_read(ndev, portdata_tbl[port].ntctl); 856bf2a952dSSerge Semin if (!(data & IDT_NTCTL_CPEN)) 857bf2a952dSSerge Semin return false; 858bf2a952dSSerge Semin 859bf2a952dSSerge Semin /* Read Mapping table entry corresponding to the peer partition */ 860bf2a952dSSerge Semin spin_lock_irqsave(&ndev->mtbl_lock, irqflags); 861bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->peers[pidx].part); 862bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA); 863bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags); 864bf2a952dSSerge Semin 865bf2a952dSSerge Semin return !!(data & IDT_NTMTBLDATA_VALID); 866bf2a952dSSerge Semin } 867bf2a952dSSerge Semin 868bf2a952dSSerge Semin /* 869bf2a952dSSerge Semin * idt_ntb_link_is_up() - get the current ntb link state (NTB API callback) 870bf2a952dSSerge Semin * @ntb: NTB device context. 871bf2a952dSSerge Semin * @speed: OUT - The link speed expressed as PCIe generation number. 872bf2a952dSSerge Semin * @width: OUT - The link width expressed as the number of PCIe lanes. 873bf2a952dSSerge Semin * 874bf2a952dSSerge Semin * Get the bitfield of NTB link states for all peer ports 875bf2a952dSSerge Semin * 876bf2a952dSSerge Semin * Return: bitfield of indexed ports link state: bit is set/cleared if the 877bf2a952dSSerge Semin * link is up/down respectively. 878bf2a952dSSerge Semin */ 879bf2a952dSSerge Semin static u64 idt_ntb_link_is_up(struct ntb_dev *ntb, 880bf2a952dSSerge Semin enum ntb_speed *speed, enum ntb_width *width) 881bf2a952dSSerge Semin { 882bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 883bf2a952dSSerge Semin unsigned char pidx; 884bf2a952dSSerge Semin u64 status; 885bf2a952dSSerge Semin u32 data; 886bf2a952dSSerge Semin 887bf2a952dSSerge Semin /* Retrieve the local link speed and width */ 888bf2a952dSSerge Semin if (speed != NULL || width != NULL) { 889bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_PCIELCTLSTS); 890bf2a952dSSerge Semin if (speed != NULL) 891bf2a952dSSerge Semin *speed = GET_FIELD(PCIELCTLSTS_CLS, data); 892bf2a952dSSerge Semin if (width != NULL) 893bf2a952dSSerge Semin *width = GET_FIELD(PCIELCTLSTS_NLW, data); 894bf2a952dSSerge Semin } 895bf2a952dSSerge Semin 896bf2a952dSSerge Semin /* If local NTB link isn't up then all the links are considered down */ 897bf2a952dSSerge Semin if (!idt_ntb_local_link_is_up(ndev)) 898bf2a952dSSerge Semin return 0; 899bf2a952dSSerge Semin 900bf2a952dSSerge Semin /* Collect all the peer ports link states into the bitfield */ 901bf2a952dSSerge Semin status = 0; 902bf2a952dSSerge Semin for (pidx = 0; pidx < ndev->peer_cnt; pidx++) { 903bf2a952dSSerge Semin if (idt_ntb_peer_link_is_up(ndev, pidx)) 904bf2a952dSSerge Semin status |= ((u64)1 << pidx); 905bf2a952dSSerge Semin } 906bf2a952dSSerge Semin 907bf2a952dSSerge Semin return status; 908bf2a952dSSerge Semin } 909bf2a952dSSerge Semin 910bf2a952dSSerge Semin /* 911bf2a952dSSerge Semin * idt_ntb_link_enable() - enable local port ntb link (NTB API callback) 912bf2a952dSSerge Semin * @ntb: NTB device context. 913bf2a952dSSerge Semin * @max_speed: The maximum link speed expressed as PCIe generation number. 914bf2a952dSSerge Semin * @max_width: The maximum link width expressed as the number of PCIe lanes. 915bf2a952dSSerge Semin * 916bf2a952dSSerge Semin * Enable just local NTB link. PCIe link parameters are ignored. 917bf2a952dSSerge Semin * 918bf2a952dSSerge Semin * Return: always zero. 919bf2a952dSSerge Semin */ 920bf2a952dSSerge Semin static int idt_ntb_link_enable(struct ntb_dev *ntb, enum ntb_speed speed, 921bf2a952dSSerge Semin enum ntb_width width) 922bf2a952dSSerge Semin { 923bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 924bf2a952dSSerge Semin 925bf2a952dSSerge Semin /* Just enable the local NTB link */ 926bf2a952dSSerge Semin idt_ntb_local_link_enable(ndev); 927bf2a952dSSerge Semin 928bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "Local NTB link enabled"); 929bf2a952dSSerge Semin 930bf2a952dSSerge Semin return 0; 931bf2a952dSSerge Semin } 932bf2a952dSSerge Semin 933bf2a952dSSerge Semin /* 934bf2a952dSSerge Semin * idt_ntb_link_disable() - disable local port ntb link (NTB API callback) 935bf2a952dSSerge Semin * @ntb: NTB device context. 936bf2a952dSSerge Semin * 937bf2a952dSSerge Semin * Disable just local NTB link. 938bf2a952dSSerge Semin * 939bf2a952dSSerge Semin * Return: always zero. 940bf2a952dSSerge Semin */ 941bf2a952dSSerge Semin static int idt_ntb_link_disable(struct ntb_dev *ntb) 942bf2a952dSSerge Semin { 943bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 944bf2a952dSSerge Semin 945bf2a952dSSerge Semin /* Just disable the local NTB link */ 946bf2a952dSSerge Semin idt_ntb_local_link_disable(ndev); 947bf2a952dSSerge Semin 948bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "Local NTB link disabled"); 949bf2a952dSSerge Semin 950bf2a952dSSerge Semin return 0; 951bf2a952dSSerge Semin } 952bf2a952dSSerge Semin 953bf2a952dSSerge Semin /*============================================================================= 954bf2a952dSSerge Semin * 4. Memory Window operations 955bf2a952dSSerge Semin * 956bf2a952dSSerge Semin * IDT PCIe-switches have two types of memory windows: MWs with direct 957bf2a952dSSerge Semin * address translation and MWs with LUT based translation. The first type of 958bf2a952dSSerge Semin * MWs is simple map of corresponding BAR address space to a memory space 959bf2a952dSSerge Semin * of specified target port. So it implemets just ont-to-one mapping. Lookup 960bf2a952dSSerge Semin * table in its turn can map one BAR address space to up to 24 different 961bf2a952dSSerge Semin * memory spaces of different ports. 962bf2a952dSSerge Semin * NT-functions BARs can be turned on to implement either direct or lookup 963bf2a952dSSerge Semin * table based address translations, so: 964bf2a952dSSerge Semin * BAR0 - NT configuration registers space/direct address translation 965bf2a952dSSerge Semin * BAR1 - direct address translation/upper address of BAR0x64 966bf2a952dSSerge Semin * BAR2 - direct address translation/Lookup table with either 12 or 24 entries 967bf2a952dSSerge Semin * BAR3 - direct address translation/upper address of BAR2x64 968bf2a952dSSerge Semin * BAR4 - direct address translation/Lookup table with either 12 or 24 entries 969bf2a952dSSerge Semin * BAR5 - direct address translation/upper address of BAR4x64 970bf2a952dSSerge Semin * Additionally BAR2 and BAR4 can't have 24-entries LUT enabled at the same 971bf2a952dSSerge Semin * time. Since the BARs setup can be rather complicated this driver implements 972bf2a952dSSerge Semin * a scanning algorithm to have all the possible memory windows configuration 973bf2a952dSSerge Semin * covered. 974bf2a952dSSerge Semin * 975bf2a952dSSerge Semin * NOTE 1 BAR setup must be done before Linux kernel enumerated NT-function 976bf2a952dSSerge Semin * of any port, so this driver would have memory windows configurations fixed. 977bf2a952dSSerge Semin * In this way all initializations must be performed either by platform BIOS 978bf2a952dSSerge Semin * or using EEPROM connected to IDT PCIe-switch master SMBus. 979bf2a952dSSerge Semin * 980bf2a952dSSerge Semin * NOTE 2 This driver expects BAR0 mapping NT-function configuration space. 981bf2a952dSSerge Semin * Easy calculation can give us an upper boundary of 29 possible memory windows 982bf2a952dSSerge Semin * per each NT-function if all the BARs are of 32bit type. 983bf2a952dSSerge Semin *============================================================================= 984bf2a952dSSerge Semin */ 985bf2a952dSSerge Semin 986bf2a952dSSerge Semin /* 987bf2a952dSSerge Semin * idt_get_mw_count() - get memory window count 988bf2a952dSSerge Semin * @mw_type: Memory window type 989bf2a952dSSerge Semin * 990bf2a952dSSerge Semin * Return: number of memory windows with respect to the BAR type 991bf2a952dSSerge Semin */ 992bf2a952dSSerge Semin static inline unsigned char idt_get_mw_count(enum idt_mw_type mw_type) 993bf2a952dSSerge Semin { 994bf2a952dSSerge Semin switch (mw_type) { 995bf2a952dSSerge Semin case IDT_MW_DIR: 996bf2a952dSSerge Semin return 1; 997bf2a952dSSerge Semin case IDT_MW_LUT12: 998bf2a952dSSerge Semin return 12; 999bf2a952dSSerge Semin case IDT_MW_LUT24: 1000bf2a952dSSerge Semin return 24; 1001bf2a952dSSerge Semin default: 1002bf2a952dSSerge Semin break; 1003bf2a952dSSerge Semin } 1004bf2a952dSSerge Semin 1005bf2a952dSSerge Semin return 0; 1006bf2a952dSSerge Semin } 1007bf2a952dSSerge Semin 1008bf2a952dSSerge Semin /* 1009bf2a952dSSerge Semin * idt_get_mw_name() - get memory window name 1010bf2a952dSSerge Semin * @mw_type: Memory window type 1011bf2a952dSSerge Semin * 1012bf2a952dSSerge Semin * Return: pointer to a string with name 1013bf2a952dSSerge Semin */ 1014bf2a952dSSerge Semin static inline char *idt_get_mw_name(enum idt_mw_type mw_type) 1015bf2a952dSSerge Semin { 1016bf2a952dSSerge Semin switch (mw_type) { 1017bf2a952dSSerge Semin case IDT_MW_DIR: 1018bf2a952dSSerge Semin return "DIR "; 1019bf2a952dSSerge Semin case IDT_MW_LUT12: 1020bf2a952dSSerge Semin return "LUT12"; 1021bf2a952dSSerge Semin case IDT_MW_LUT24: 1022bf2a952dSSerge Semin return "LUT24"; 1023bf2a952dSSerge Semin default: 1024bf2a952dSSerge Semin break; 1025bf2a952dSSerge Semin } 1026bf2a952dSSerge Semin 1027bf2a952dSSerge Semin return "unknown"; 1028bf2a952dSSerge Semin } 1029bf2a952dSSerge Semin 1030bf2a952dSSerge Semin /* 1031bf2a952dSSerge Semin * idt_scan_mws() - scan memory windows of the port 1032bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 1033bf2a952dSSerge Semin * @port: Port to get number of memory windows for 1034bf2a952dSSerge Semin * @mw_cnt: Out - number of memory windows 1035bf2a952dSSerge Semin * 1036bf2a952dSSerge Semin * It walks over BAR setup registers of the specified port and determines 1037bf2a952dSSerge Semin * the memory windows parameters if any activated. 1038bf2a952dSSerge Semin * 1039bf2a952dSSerge Semin * Return: array of memory windows 1040bf2a952dSSerge Semin */ 1041bf2a952dSSerge Semin static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, 1042bf2a952dSSerge Semin unsigned char *mw_cnt) 1043bf2a952dSSerge Semin { 1044bf2a952dSSerge Semin struct idt_mw_cfg mws[IDT_MAX_NR_MWS], *ret_mws; 1045bf2a952dSSerge Semin const struct idt_ntb_bar *bars; 1046bf2a952dSSerge Semin enum idt_mw_type mw_type; 1047bf2a952dSSerge Semin unsigned char widx, bidx, en_cnt; 1048bf2a952dSSerge Semin bool bar_64bit = false; 1049bf2a952dSSerge Semin int aprt_size; 1050bf2a952dSSerge Semin u32 data; 1051bf2a952dSSerge Semin 1052bf2a952dSSerge Semin /* Retrieve the array of the BARs registers */ 1053bf2a952dSSerge Semin bars = portdata_tbl[port].bars; 1054bf2a952dSSerge Semin 1055bf2a952dSSerge Semin /* Scan all the BARs belonging to the port */ 1056bf2a952dSSerge Semin *mw_cnt = 0; 1057bf2a952dSSerge Semin for (bidx = 0; bidx < IDT_BAR_CNT; bidx += 1 + bar_64bit) { 1058bf2a952dSSerge Semin /* Read BARSETUP register value */ 1059bf2a952dSSerge Semin data = idt_sw_read(ndev, bars[bidx].setup); 1060bf2a952dSSerge Semin 1061bf2a952dSSerge Semin /* Skip disabled BARs */ 1062bf2a952dSSerge Semin if (!(data & IDT_BARSETUP_EN)) { 1063bf2a952dSSerge Semin bar_64bit = false; 1064bf2a952dSSerge Semin continue; 1065bf2a952dSSerge Semin } 1066bf2a952dSSerge Semin 1067bf2a952dSSerge Semin /* Skip next BARSETUP if current one has 64bit addressing */ 1068bf2a952dSSerge Semin bar_64bit = IS_FLD_SET(BARSETUP_TYPE, data, 64); 1069bf2a952dSSerge Semin 1070bf2a952dSSerge Semin /* Skip configuration space mapping BARs */ 1071bf2a952dSSerge Semin if (data & IDT_BARSETUP_MODE_CFG) 1072bf2a952dSSerge Semin continue; 1073bf2a952dSSerge Semin 1074bf2a952dSSerge Semin /* Retrieve MW type/entries count and aperture size */ 1075bf2a952dSSerge Semin mw_type = GET_FIELD(BARSETUP_ATRAN, data); 1076bf2a952dSSerge Semin en_cnt = idt_get_mw_count(mw_type); 1077bf2a952dSSerge Semin aprt_size = (u64)1 << GET_FIELD(BARSETUP_SIZE, data); 1078bf2a952dSSerge Semin 1079bf2a952dSSerge Semin /* Save configurations of all available memory windows */ 1080bf2a952dSSerge Semin for (widx = 0; widx < en_cnt; widx++, (*mw_cnt)++) { 1081bf2a952dSSerge Semin /* 1082bf2a952dSSerge Semin * IDT can expose a limited number of MWs, so it's bug 1083bf2a952dSSerge Semin * to have more than the driver expects 1084bf2a952dSSerge Semin */ 1085bf2a952dSSerge Semin if (*mw_cnt >= IDT_MAX_NR_MWS) 1086bf2a952dSSerge Semin return ERR_PTR(-EINVAL); 1087bf2a952dSSerge Semin 1088bf2a952dSSerge Semin /* Save basic MW info */ 1089bf2a952dSSerge Semin mws[*mw_cnt].type = mw_type; 1090bf2a952dSSerge Semin mws[*mw_cnt].bar = bidx; 1091bf2a952dSSerge Semin mws[*mw_cnt].idx = widx; 1092bf2a952dSSerge Semin /* It's always DWORD aligned */ 1093bf2a952dSSerge Semin mws[*mw_cnt].addr_align = IDT_TRANS_ALIGN; 1094bf2a952dSSerge Semin /* DIR and LUT approachs differently configure MWs */ 1095bf2a952dSSerge Semin if (mw_type == IDT_MW_DIR) 1096bf2a952dSSerge Semin mws[*mw_cnt].size_max = aprt_size; 1097bf2a952dSSerge Semin else if (mw_type == IDT_MW_LUT12) 1098bf2a952dSSerge Semin mws[*mw_cnt].size_max = aprt_size / 16; 1099bf2a952dSSerge Semin else 1100bf2a952dSSerge Semin mws[*mw_cnt].size_max = aprt_size / 32; 1101bf2a952dSSerge Semin mws[*mw_cnt].size_align = (mw_type == IDT_MW_DIR) ? 1102bf2a952dSSerge Semin IDT_DIR_SIZE_ALIGN : mws[*mw_cnt].size_max; 1103bf2a952dSSerge Semin } 1104bf2a952dSSerge Semin } 1105bf2a952dSSerge Semin 1106bf2a952dSSerge Semin /* Allocate memory for memory window descriptors */ 11071b761982SGustavo A. R. Silva ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws), 11081b761982SGustavo A. R. Silva GFP_KERNEL); 11091b761982SGustavo A. R. Silva if (!ret_mws) 1110bf2a952dSSerge Semin return ERR_PTR(-ENOMEM); 1111bf2a952dSSerge Semin 1112bf2a952dSSerge Semin /* Copy the info of detected memory windows */ 1113bf2a952dSSerge Semin memcpy(ret_mws, mws, (*mw_cnt)*sizeof(*ret_mws)); 1114bf2a952dSSerge Semin 1115bf2a952dSSerge Semin return ret_mws; 1116bf2a952dSSerge Semin } 1117bf2a952dSSerge Semin 1118bf2a952dSSerge Semin /* 1119bf2a952dSSerge Semin * idt_init_mws() - initialize memory windows subsystem 1120bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 1121bf2a952dSSerge Semin * 1122bf2a952dSSerge Semin * Scan BAR setup registers of local and peer ports to determine the 1123bf2a952dSSerge Semin * outbound and inbound memory windows parameters 1124bf2a952dSSerge Semin * 1125bf2a952dSSerge Semin * Return: zero on success, otherwise a negative error number 1126bf2a952dSSerge Semin */ 1127bf2a952dSSerge Semin static int idt_init_mws(struct idt_ntb_dev *ndev) 1128bf2a952dSSerge Semin { 1129bf2a952dSSerge Semin struct idt_ntb_peer *peer; 1130bf2a952dSSerge Semin unsigned char pidx; 1131bf2a952dSSerge Semin 1132bf2a952dSSerge Semin /* Scan memory windows of the local port */ 1133bf2a952dSSerge Semin ndev->mws = idt_scan_mws(ndev, ndev->port, &ndev->mw_cnt); 1134bf2a952dSSerge Semin if (IS_ERR(ndev->mws)) { 1135bf2a952dSSerge Semin dev_err(&ndev->ntb.pdev->dev, 1136bf2a952dSSerge Semin "Failed to scan mws of local port %hhu", ndev->port); 1137bf2a952dSSerge Semin return PTR_ERR(ndev->mws); 1138bf2a952dSSerge Semin } 1139bf2a952dSSerge Semin 1140bf2a952dSSerge Semin /* Scan memory windows of the peer ports */ 1141bf2a952dSSerge Semin for (pidx = 0; pidx < ndev->peer_cnt; pidx++) { 1142bf2a952dSSerge Semin peer = &ndev->peers[pidx]; 1143bf2a952dSSerge Semin peer->mws = idt_scan_mws(ndev, peer->port, &peer->mw_cnt); 1144bf2a952dSSerge Semin if (IS_ERR(peer->mws)) { 1145bf2a952dSSerge Semin dev_err(&ndev->ntb.pdev->dev, 1146bf2a952dSSerge Semin "Failed to scan mws of port %hhu", peer->port); 1147bf2a952dSSerge Semin return PTR_ERR(peer->mws); 1148bf2a952dSSerge Semin } 1149bf2a952dSSerge Semin } 1150bf2a952dSSerge Semin 1151bf2a952dSSerge Semin /* Initialize spin locker of the LUT registers */ 1152bf2a952dSSerge Semin spin_lock_init(&ndev->lut_lock); 1153bf2a952dSSerge Semin 1154bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "Outbound and inbound MWs initialized"); 1155bf2a952dSSerge Semin 1156bf2a952dSSerge Semin return 0; 1157bf2a952dSSerge Semin } 1158bf2a952dSSerge Semin 1159bf2a952dSSerge Semin /* 1160bf2a952dSSerge Semin * idt_ntb_mw_count() - number of inbound memory windows (NTB API callback) 1161bf2a952dSSerge Semin * @ntb: NTB device context. 1162bf2a952dSSerge Semin * @pidx: Port index of peer device. 1163bf2a952dSSerge Semin * 1164bf2a952dSSerge Semin * The value is returned for the specified peer, so generally speaking it can 1165bf2a952dSSerge Semin * be different for different port depending on the IDT PCIe-switch 1166bf2a952dSSerge Semin * initialization. 1167bf2a952dSSerge Semin * 1168bf2a952dSSerge Semin * Return: the number of memory windows. 1169bf2a952dSSerge Semin */ 1170bf2a952dSSerge Semin static int idt_ntb_mw_count(struct ntb_dev *ntb, int pidx) 1171bf2a952dSSerge Semin { 1172bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1173bf2a952dSSerge Semin 1174bf2a952dSSerge Semin if (pidx < 0 || ndev->peer_cnt <= pidx) 1175bf2a952dSSerge Semin return -EINVAL; 1176bf2a952dSSerge Semin 1177bf2a952dSSerge Semin return ndev->peers[pidx].mw_cnt; 1178bf2a952dSSerge Semin } 1179bf2a952dSSerge Semin 1180bf2a952dSSerge Semin /* 1181bf2a952dSSerge Semin * idt_ntb_mw_get_align() - inbound memory window parameters (NTB API callback) 1182bf2a952dSSerge Semin * @ntb: NTB device context. 1183bf2a952dSSerge Semin * @pidx: Port index of peer device. 1184bf2a952dSSerge Semin * @widx: Memory window index. 1185bf2a952dSSerge Semin * @addr_align: OUT - the base alignment for translating the memory window 1186bf2a952dSSerge Semin * @size_align: OUT - the size alignment for translating the memory window 1187bf2a952dSSerge Semin * @size_max: OUT - the maximum size of the memory window 1188bf2a952dSSerge Semin * 1189bf2a952dSSerge Semin * The peer memory window parameters have already been determined, so just 1190bf2a952dSSerge Semin * return the corresponding values, which mustn't change within session. 1191bf2a952dSSerge Semin * 1192bf2a952dSSerge Semin * Return: Zero on success, otherwise a negative error number. 1193bf2a952dSSerge Semin */ 1194bf2a952dSSerge Semin static int idt_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx, 1195bf2a952dSSerge Semin resource_size_t *addr_align, 1196bf2a952dSSerge Semin resource_size_t *size_align, 1197bf2a952dSSerge Semin resource_size_t *size_max) 1198bf2a952dSSerge Semin { 1199bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1200bf2a952dSSerge Semin struct idt_ntb_peer *peer; 1201bf2a952dSSerge Semin 1202bf2a952dSSerge Semin if (pidx < 0 || ndev->peer_cnt <= pidx) 1203bf2a952dSSerge Semin return -EINVAL; 1204bf2a952dSSerge Semin 1205bf2a952dSSerge Semin peer = &ndev->peers[pidx]; 1206bf2a952dSSerge Semin 1207bf2a952dSSerge Semin if (widx < 0 || peer->mw_cnt <= widx) 1208bf2a952dSSerge Semin return -EINVAL; 1209bf2a952dSSerge Semin 1210bf2a952dSSerge Semin if (addr_align != NULL) 1211bf2a952dSSerge Semin *addr_align = peer->mws[widx].addr_align; 1212bf2a952dSSerge Semin 1213bf2a952dSSerge Semin if (size_align != NULL) 1214bf2a952dSSerge Semin *size_align = peer->mws[widx].size_align; 1215bf2a952dSSerge Semin 1216bf2a952dSSerge Semin if (size_max != NULL) 1217bf2a952dSSerge Semin *size_max = peer->mws[widx].size_max; 1218bf2a952dSSerge Semin 1219bf2a952dSSerge Semin return 0; 1220bf2a952dSSerge Semin } 1221bf2a952dSSerge Semin 1222bf2a952dSSerge Semin /* 1223bf2a952dSSerge Semin * idt_ntb_peer_mw_count() - number of outbound memory windows 1224bf2a952dSSerge Semin * (NTB API callback) 1225bf2a952dSSerge Semin * @ntb: NTB device context. 1226bf2a952dSSerge Semin * 1227bf2a952dSSerge Semin * Outbound memory windows parameters have been determined based on the 1228bf2a952dSSerge Semin * BAR setup registers value, which are mostly constants within one session. 1229bf2a952dSSerge Semin * 1230bf2a952dSSerge Semin * Return: the number of memory windows. 1231bf2a952dSSerge Semin */ 1232bf2a952dSSerge Semin static int idt_ntb_peer_mw_count(struct ntb_dev *ntb) 1233bf2a952dSSerge Semin { 1234bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1235bf2a952dSSerge Semin 1236bf2a952dSSerge Semin return ndev->mw_cnt; 1237bf2a952dSSerge Semin } 1238bf2a952dSSerge Semin 1239bf2a952dSSerge Semin /* 1240bf2a952dSSerge Semin * idt_ntb_peer_mw_get_addr() - get map address of an outbound memory window 1241bf2a952dSSerge Semin * (NTB API callback) 1242bf2a952dSSerge Semin * @ntb: NTB device context. 1243bf2a952dSSerge Semin * @widx: Memory window index (within ntb_peer_mw_count() return value). 1244bf2a952dSSerge Semin * @base: OUT - the base address of mapping region. 1245bf2a952dSSerge Semin * @size: OUT - the size of mapping region. 1246bf2a952dSSerge Semin * 1247bf2a952dSSerge Semin * Return just parameters of BAR resources mapping. Size reflects just the size 1248bf2a952dSSerge Semin * of the resource 1249bf2a952dSSerge Semin * 1250bf2a952dSSerge Semin * Return: Zero on success, otherwise a negative error number. 1251bf2a952dSSerge Semin */ 1252bf2a952dSSerge Semin static int idt_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx, 1253bf2a952dSSerge Semin phys_addr_t *base, resource_size_t *size) 1254bf2a952dSSerge Semin { 1255bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1256bf2a952dSSerge Semin 1257bf2a952dSSerge Semin if (widx < 0 || ndev->mw_cnt <= widx) 1258bf2a952dSSerge Semin return -EINVAL; 1259bf2a952dSSerge Semin 1260bf2a952dSSerge Semin /* Mapping address is just properly shifted BAR resource start */ 1261bf2a952dSSerge Semin if (base != NULL) 1262bf2a952dSSerge Semin *base = pci_resource_start(ntb->pdev, ndev->mws[widx].bar) + 1263bf2a952dSSerge Semin ndev->mws[widx].idx * ndev->mws[widx].size_max; 1264bf2a952dSSerge Semin 1265bf2a952dSSerge Semin /* Mapping size has already been calculated at MWs scanning */ 1266bf2a952dSSerge Semin if (size != NULL) 1267bf2a952dSSerge Semin *size = ndev->mws[widx].size_max; 1268bf2a952dSSerge Semin 1269bf2a952dSSerge Semin return 0; 1270bf2a952dSSerge Semin } 1271bf2a952dSSerge Semin 1272bf2a952dSSerge Semin /* 1273bf2a952dSSerge Semin * idt_ntb_peer_mw_set_trans() - set a translation address of a memory window 1274bf2a952dSSerge Semin * (NTB API callback) 1275bf2a952dSSerge Semin * @ntb: NTB device context. 1276bf2a952dSSerge Semin * @pidx: Port index of peer device the translation address received from. 1277bf2a952dSSerge Semin * @widx: Memory window index. 1278bf2a952dSSerge Semin * @addr: The dma address of the shared memory to access. 1279bf2a952dSSerge Semin * @size: The size of the shared memory to access. 1280bf2a952dSSerge Semin * 1281bf2a952dSSerge Semin * The Direct address translation and LUT base translation is initialized a 1282bf2a952dSSerge Semin * bit differenet. Although the parameters restriction are now determined by 1283bf2a952dSSerge Semin * the same code. 1284bf2a952dSSerge Semin * 1285bf2a952dSSerge Semin * Return: Zero on success, otherwise an error number. 1286bf2a952dSSerge Semin */ 1287bf2a952dSSerge Semin static int idt_ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, 1288bf2a952dSSerge Semin u64 addr, resource_size_t size) 1289bf2a952dSSerge Semin { 1290bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1291bf2a952dSSerge Semin struct idt_mw_cfg *mw_cfg; 1292bf2a952dSSerge Semin u32 data = 0, lutoff = 0; 1293bf2a952dSSerge Semin 1294bf2a952dSSerge Semin if (pidx < 0 || ndev->peer_cnt <= pidx) 1295bf2a952dSSerge Semin return -EINVAL; 1296bf2a952dSSerge Semin 1297bf2a952dSSerge Semin if (widx < 0 || ndev->mw_cnt <= widx) 1298bf2a952dSSerge Semin return -EINVAL; 1299bf2a952dSSerge Semin 1300bf2a952dSSerge Semin /* 1301bf2a952dSSerge Semin * Retrieve the memory window config to make sure the passed arguments 1302bf2a952dSSerge Semin * fit it restrictions 1303bf2a952dSSerge Semin */ 1304bf2a952dSSerge Semin mw_cfg = &ndev->mws[widx]; 1305bf2a952dSSerge Semin if (!IS_ALIGNED(addr, mw_cfg->addr_align)) 1306bf2a952dSSerge Semin return -EINVAL; 1307bf2a952dSSerge Semin if (!IS_ALIGNED(size, mw_cfg->size_align) || size > mw_cfg->size_max) 1308bf2a952dSSerge Semin return -EINVAL; 1309bf2a952dSSerge Semin 1310bf2a952dSSerge Semin /* DIR and LUT based translations are initialized differently */ 1311bf2a952dSSerge Semin if (mw_cfg->type == IDT_MW_DIR) { 1312bf2a952dSSerge Semin const struct idt_ntb_bar *bar = &ntdata_tbl.bars[mw_cfg->bar]; 1313bf2a952dSSerge Semin u64 limit; 1314bf2a952dSSerge Semin /* Set destination partition of translation */ 1315bf2a952dSSerge Semin data = idt_nt_read(ndev, bar->setup); 1316bf2a952dSSerge Semin data = SET_FIELD(BARSETUP_TPART, data, ndev->peers[pidx].part); 1317bf2a952dSSerge Semin idt_nt_write(ndev, bar->setup, data); 1318bf2a952dSSerge Semin /* Set translation base address */ 1319bf2a952dSSerge Semin idt_nt_write(ndev, bar->ltbase, (u32)addr); 1320bf2a952dSSerge Semin idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32)); 1321bf2a952dSSerge Semin /* Set the custom BAR aperture limit */ 132237a3e969SSerge Semin limit = pci_bus_address(ntb->pdev, mw_cfg->bar) + size; 1323bf2a952dSSerge Semin idt_nt_write(ndev, bar->limit, (u32)limit); 1324bf2a952dSSerge Semin if (IS_FLD_SET(BARSETUP_TYPE, data, 64)) 1325bf2a952dSSerge Semin idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32)); 1326bf2a952dSSerge Semin } else { 1327bf2a952dSSerge Semin unsigned long irqflags; 1328bf2a952dSSerge Semin /* Initialize corresponding LUT entry */ 1329bf2a952dSSerge Semin lutoff = SET_FIELD(LUTOFFSET_INDEX, 0, mw_cfg->idx) | 1330bf2a952dSSerge Semin SET_FIELD(LUTOFFSET_BAR, 0, mw_cfg->bar); 1331bf2a952dSSerge Semin data = SET_FIELD(LUTUDATA_PART, 0, ndev->peers[pidx].part) | 1332bf2a952dSSerge Semin IDT_LUTUDATA_VALID; 1333bf2a952dSSerge Semin spin_lock_irqsave(&ndev->lut_lock, irqflags); 1334bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTOFFSET, lutoff); 1335bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTLDATA, (u32)addr); 1336bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTMDATA, (u32)(addr >> 32)); 1337bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTUDATA, data); 1338bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->lut_lock, irqflags); 1339bf2a952dSSerge Semin /* Limit address isn't specified since size is fixed for LUT */ 1340bf2a952dSSerge Semin } 1341bf2a952dSSerge Semin 1342bf2a952dSSerge Semin return 0; 1343bf2a952dSSerge Semin } 1344bf2a952dSSerge Semin 1345bf2a952dSSerge Semin /* 1346bf2a952dSSerge Semin * idt_ntb_peer_mw_clear_trans() - clear the outbound MW translation address 1347bf2a952dSSerge Semin * (NTB API callback) 1348bf2a952dSSerge Semin * @ntb: NTB device context. 1349bf2a952dSSerge Semin * @pidx: Port index of peer device. 1350bf2a952dSSerge Semin * @widx: Memory window index. 1351bf2a952dSSerge Semin * 1352bf2a952dSSerge Semin * It effectively disables the translation over the specified outbound MW. 1353bf2a952dSSerge Semin * 1354bf2a952dSSerge Semin * Return: Zero on success, otherwise an error number. 1355bf2a952dSSerge Semin */ 1356bf2a952dSSerge Semin static int idt_ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx, 1357bf2a952dSSerge Semin int widx) 1358bf2a952dSSerge Semin { 1359bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1360bf2a952dSSerge Semin struct idt_mw_cfg *mw_cfg; 1361bf2a952dSSerge Semin 1362bf2a952dSSerge Semin if (pidx < 0 || ndev->peer_cnt <= pidx) 1363bf2a952dSSerge Semin return -EINVAL; 1364bf2a952dSSerge Semin 1365bf2a952dSSerge Semin if (widx < 0 || ndev->mw_cnt <= widx) 1366bf2a952dSSerge Semin return -EINVAL; 1367bf2a952dSSerge Semin 1368bf2a952dSSerge Semin mw_cfg = &ndev->mws[widx]; 1369bf2a952dSSerge Semin 1370bf2a952dSSerge Semin /* DIR and LUT based translations are initialized differently */ 1371bf2a952dSSerge Semin if (mw_cfg->type == IDT_MW_DIR) { 1372bf2a952dSSerge Semin const struct idt_ntb_bar *bar = &ntdata_tbl.bars[mw_cfg->bar]; 1373bf2a952dSSerge Semin u32 data; 1374bf2a952dSSerge Semin /* Read BARSETUP to check BAR type */ 1375bf2a952dSSerge Semin data = idt_nt_read(ndev, bar->setup); 1376bf2a952dSSerge Semin /* Disable translation by specifying zero BAR limit */ 1377bf2a952dSSerge Semin idt_nt_write(ndev, bar->limit, 0); 1378bf2a952dSSerge Semin if (IS_FLD_SET(BARSETUP_TYPE, data, 64)) 1379bf2a952dSSerge Semin idt_nt_write(ndev, (bar + 1)->limit, 0); 1380bf2a952dSSerge Semin } else { 1381bf2a952dSSerge Semin unsigned long irqflags; 1382bf2a952dSSerge Semin u32 lutoff; 1383bf2a952dSSerge Semin /* Clear the corresponding LUT entry up */ 1384bf2a952dSSerge Semin lutoff = SET_FIELD(LUTOFFSET_INDEX, 0, mw_cfg->idx) | 1385bf2a952dSSerge Semin SET_FIELD(LUTOFFSET_BAR, 0, mw_cfg->bar); 1386bf2a952dSSerge Semin spin_lock_irqsave(&ndev->lut_lock, irqflags); 1387bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTOFFSET, lutoff); 1388bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTLDATA, 0); 1389bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTMDATA, 0); 1390bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_LUTUDATA, 0); 1391bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->lut_lock, irqflags); 1392bf2a952dSSerge Semin } 1393bf2a952dSSerge Semin 1394bf2a952dSSerge Semin return 0; 1395bf2a952dSSerge Semin } 1396bf2a952dSSerge Semin 1397bf2a952dSSerge Semin /*============================================================================= 1398bf2a952dSSerge Semin * 5. Doorbell operations 1399bf2a952dSSerge Semin * 1400bf2a952dSSerge Semin * Doorbell functionality of IDT PCIe-switches is pretty unusual. First of 1401081a6986SWolfram Sang * all there is global doorbell register which state can be changed by any 1402bf2a952dSSerge Semin * NT-function of the IDT device in accordance with global permissions. These 1403bf2a952dSSerge Semin * permissions configs are not supported by NTB API, so it must be done by 1404bf2a952dSSerge Semin * either BIOS or EEPROM settings. In the same way the state of the global 1405bf2a952dSSerge Semin * doorbell is reflected to the NT-functions local inbound doorbell registers. 1406bf2a952dSSerge Semin * It can lead to situations when client driver sets some peer doorbell bits 1407bf2a952dSSerge Semin * and get them bounced back to local inbound doorbell if permissions are 1408bf2a952dSSerge Semin * granted. 1409bf2a952dSSerge Semin * Secondly there is just one IRQ vector for Doorbell, Message, Temperature 1410bf2a952dSSerge Semin * and Switch events, so if client driver left any of Doorbell bits set and 1411bf2a952dSSerge Semin * some other event occurred, the driver will be notified of Doorbell event 1412bf2a952dSSerge Semin * again. 1413bf2a952dSSerge Semin *============================================================================= 1414bf2a952dSSerge Semin */ 1415bf2a952dSSerge Semin 1416bf2a952dSSerge Semin /* 1417bf2a952dSSerge Semin * idt_db_isr() - doorbell event ISR 1418bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 1419bf2a952dSSerge Semin * @ntint_sts: NT-function interrupt status 1420bf2a952dSSerge Semin * 1421bf2a952dSSerge Semin * Doorbell event happans when DBELL bit of NTINTSTS switches from 0 to 1. 1422bf2a952dSSerge Semin * It happens only when unmasked doorbell bits are set to ones on completely 1423bf2a952dSSerge Semin * zeroed doorbell register. 1424bf2a952dSSerge Semin * The method is called from PCIe ISR bottom-half routine. 1425bf2a952dSSerge Semin */ 1426bf2a952dSSerge Semin static void idt_db_isr(struct idt_ntb_dev *ndev, u32 ntint_sts) 1427bf2a952dSSerge Semin { 1428bf2a952dSSerge Semin /* 1429bf2a952dSSerge Semin * Doorbell IRQ status will be cleaned only when client 1430bf2a952dSSerge Semin * driver unsets all the doorbell bits. 1431bf2a952dSSerge Semin */ 1432bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "DB IRQ detected %#08x", ntint_sts); 1433bf2a952dSSerge Semin 1434bf2a952dSSerge Semin /* Notify the client driver of possible doorbell state change */ 1435bf2a952dSSerge Semin ntb_db_event(&ndev->ntb, 0); 1436bf2a952dSSerge Semin } 1437bf2a952dSSerge Semin 1438bf2a952dSSerge Semin /* 1439bf2a952dSSerge Semin * idt_ntb_db_valid_mask() - get a mask of doorbell bits supported by the ntb 1440bf2a952dSSerge Semin * (NTB API callback) 1441bf2a952dSSerge Semin * @ntb: NTB device context. 1442bf2a952dSSerge Semin * 1443bf2a952dSSerge Semin * IDT PCIe-switches expose just one Doorbell register of DWORD size. 1444bf2a952dSSerge Semin * 1445bf2a952dSSerge Semin * Return: A mask of doorbell bits supported by the ntb. 1446bf2a952dSSerge Semin */ 1447bf2a952dSSerge Semin static u64 idt_ntb_db_valid_mask(struct ntb_dev *ntb) 1448bf2a952dSSerge Semin { 1449bf2a952dSSerge Semin return IDT_DBELL_MASK; 1450bf2a952dSSerge Semin } 1451bf2a952dSSerge Semin 1452bf2a952dSSerge Semin /* 1453bf2a952dSSerge Semin * idt_ntb_db_read() - read the local doorbell register (NTB API callback) 1454bf2a952dSSerge Semin * @ntb: NTB device context. 1455bf2a952dSSerge Semin * 1456bf2a952dSSerge Semin * There is just on inbound doorbell register of each NT-function, so 1457bf2a952dSSerge Semin * this method return it value. 1458bf2a952dSSerge Semin * 1459bf2a952dSSerge Semin * Return: The bits currently set in the local doorbell register. 1460bf2a952dSSerge Semin */ 1461bf2a952dSSerge Semin static u64 idt_ntb_db_read(struct ntb_dev *ntb) 1462bf2a952dSSerge Semin { 1463bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1464bf2a952dSSerge Semin 1465bf2a952dSSerge Semin return idt_nt_read(ndev, IDT_NT_INDBELLSTS); 1466bf2a952dSSerge Semin } 1467bf2a952dSSerge Semin 1468bf2a952dSSerge Semin /* 1469bf2a952dSSerge Semin * idt_ntb_db_clear() - clear bits in the local doorbell register 1470bf2a952dSSerge Semin * (NTB API callback) 1471bf2a952dSSerge Semin * @ntb: NTB device context. 1472bf2a952dSSerge Semin * @db_bits: Doorbell bits to clear. 1473bf2a952dSSerge Semin * 1474bf2a952dSSerge Semin * Clear bits of inbound doorbell register by writing ones to it. 1475bf2a952dSSerge Semin * 1476bf2a952dSSerge Semin * NOTE! Invalid bits are always considered cleared so it's not an error 1477bf2a952dSSerge Semin * to clear them over. 1478bf2a952dSSerge Semin * 1479bf2a952dSSerge Semin * Return: always zero as success. 1480bf2a952dSSerge Semin */ 1481bf2a952dSSerge Semin static int idt_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) 1482bf2a952dSSerge Semin { 1483bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1484bf2a952dSSerge Semin 1485bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_INDBELLSTS, (u32)db_bits); 1486bf2a952dSSerge Semin 1487bf2a952dSSerge Semin return 0; 1488bf2a952dSSerge Semin } 1489bf2a952dSSerge Semin 1490bf2a952dSSerge Semin /* 1491bf2a952dSSerge Semin * idt_ntb_db_read_mask() - read the local doorbell mask (NTB API callback) 1492bf2a952dSSerge Semin * @ntb: NTB device context. 1493bf2a952dSSerge Semin * 1494bf2a952dSSerge Semin * Each inbound doorbell bit can be masked from generating IRQ by setting 1495bf2a952dSSerge Semin * the corresponding bit in inbound doorbell mask. So this method returns 1496bf2a952dSSerge Semin * the value of the register. 1497bf2a952dSSerge Semin * 1498bf2a952dSSerge Semin * Return: The bits currently set in the local doorbell mask register. 1499bf2a952dSSerge Semin */ 1500bf2a952dSSerge Semin static u64 idt_ntb_db_read_mask(struct ntb_dev *ntb) 1501bf2a952dSSerge Semin { 1502bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1503bf2a952dSSerge Semin 1504bf2a952dSSerge Semin return idt_nt_read(ndev, IDT_NT_INDBELLMSK); 1505bf2a952dSSerge Semin } 1506bf2a952dSSerge Semin 1507bf2a952dSSerge Semin /* 1508bf2a952dSSerge Semin * idt_ntb_db_set_mask() - set bits in the local doorbell mask 1509bf2a952dSSerge Semin * (NTB API callback) 1510bf2a952dSSerge Semin * @ntb: NTB device context. 1511bf2a952dSSerge Semin * @db_bits: Doorbell mask bits to set. 1512bf2a952dSSerge Semin * 1513bf2a952dSSerge Semin * The inbound doorbell register mask value must be read, then OR'ed with 1514bf2a952dSSerge Semin * passed field and only then set back. 1515bf2a952dSSerge Semin * 1516bf2a952dSSerge Semin * Return: zero on success, negative error if invalid argument passed. 1517bf2a952dSSerge Semin */ 1518bf2a952dSSerge Semin static int idt_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) 1519bf2a952dSSerge Semin { 1520bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1521bf2a952dSSerge Semin 1522bf2a952dSSerge Semin return idt_reg_set_bits(ndev, IDT_NT_INDBELLMSK, &ndev->db_mask_lock, 1523bf2a952dSSerge Semin IDT_DBELL_MASK, db_bits); 1524bf2a952dSSerge Semin } 1525bf2a952dSSerge Semin 1526bf2a952dSSerge Semin /* 1527bf2a952dSSerge Semin * idt_ntb_db_clear_mask() - clear bits in the local doorbell mask 1528bf2a952dSSerge Semin * (NTB API callback) 1529bf2a952dSSerge Semin * @ntb: NTB device context. 1530bf2a952dSSerge Semin * @db_bits: Doorbell bits to clear. 1531bf2a952dSSerge Semin * 1532bf2a952dSSerge Semin * The method just clears the set bits up in accordance with the passed 1533bf2a952dSSerge Semin * bitfield. IDT PCIe-switch shall generate an interrupt if there hasn't 1534bf2a952dSSerge Semin * been any unmasked bit set before current unmasking. Otherwise IRQ won't 1535bf2a952dSSerge Semin * be generated since there is only one IRQ vector for all doorbells. 1536bf2a952dSSerge Semin * 1537bf2a952dSSerge Semin * Return: always zero as success 1538bf2a952dSSerge Semin */ 1539bf2a952dSSerge Semin static int idt_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) 1540bf2a952dSSerge Semin { 1541bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1542bf2a952dSSerge Semin 1543bf2a952dSSerge Semin idt_reg_clear_bits(ndev, IDT_NT_INDBELLMSK, &ndev->db_mask_lock, 1544bf2a952dSSerge Semin db_bits); 1545bf2a952dSSerge Semin 1546bf2a952dSSerge Semin return 0; 1547bf2a952dSSerge Semin } 1548bf2a952dSSerge Semin 1549bf2a952dSSerge Semin /* 1550bf2a952dSSerge Semin * idt_ntb_peer_db_set() - set bits in the peer doorbell register 1551bf2a952dSSerge Semin * (NTB API callback) 1552bf2a952dSSerge Semin * @ntb: NTB device context. 1553bf2a952dSSerge Semin * @db_bits: Doorbell bits to set. 1554bf2a952dSSerge Semin * 1555bf2a952dSSerge Semin * IDT PCIe-switches exposes local outbound doorbell register to change peer 1556bf2a952dSSerge Semin * inbound doorbell register state. 1557bf2a952dSSerge Semin * 1558bf2a952dSSerge Semin * Return: zero on success, negative error if invalid argument passed. 1559bf2a952dSSerge Semin */ 1560bf2a952dSSerge Semin static int idt_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) 1561bf2a952dSSerge Semin { 1562bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1563bf2a952dSSerge Semin 1564bf2a952dSSerge Semin if (db_bits & ~(u64)IDT_DBELL_MASK) 1565bf2a952dSSerge Semin return -EINVAL; 1566bf2a952dSSerge Semin 1567bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_OUTDBELLSET, (u32)db_bits); 1568bf2a952dSSerge Semin return 0; 1569bf2a952dSSerge Semin } 1570bf2a952dSSerge Semin 1571bf2a952dSSerge Semin /*============================================================================= 1572bf2a952dSSerge Semin * 6. Messaging operations 1573bf2a952dSSerge Semin * 1574bf2a952dSSerge Semin * Each NT-function of IDT PCIe-switch has four inbound and four outbound 1575bf2a952dSSerge Semin * message registers. Each outbound message register can be connected to one or 1576bf2a952dSSerge Semin * even more than one peer inbound message registers by setting global 1577bf2a952dSSerge Semin * configurations. Since NTB API permits one-on-one message registers mapping 1578bf2a952dSSerge Semin * only, the driver acts in according with that restriction. 1579bf2a952dSSerge Semin *============================================================================= 1580bf2a952dSSerge Semin */ 1581bf2a952dSSerge Semin 1582bf2a952dSSerge Semin /* 1583bf2a952dSSerge Semin * idt_init_msg() - initialize messaging interface 1584bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 1585bf2a952dSSerge Semin * 1586bf2a952dSSerge Semin * Just initialize the message registers routing tables locker. 1587bf2a952dSSerge Semin */ 1588bf2a952dSSerge Semin static void idt_init_msg(struct idt_ntb_dev *ndev) 1589bf2a952dSSerge Semin { 1590bf2a952dSSerge Semin unsigned char midx; 1591bf2a952dSSerge Semin 1592bf2a952dSSerge Semin /* Init the messages routing table lockers */ 1593bf2a952dSSerge Semin for (midx = 0; midx < IDT_MSG_CNT; midx++) 1594bf2a952dSSerge Semin spin_lock_init(&ndev->msg_locks[midx]); 1595bf2a952dSSerge Semin 1596bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "NTB Messaging initialized"); 1597bf2a952dSSerge Semin } 1598bf2a952dSSerge Semin 1599bf2a952dSSerge Semin /* 1600bf2a952dSSerge Semin * idt_msg_isr() - message event ISR 1601bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 1602bf2a952dSSerge Semin * @ntint_sts: NT-function interrupt status 1603bf2a952dSSerge Semin * 1604bf2a952dSSerge Semin * Message event happens when MSG bit of NTINTSTS switches from 0 to 1. 1605bf2a952dSSerge Semin * It happens only when unmasked message status bits are set to ones on 1606bf2a952dSSerge Semin * completely zeroed message status register. 1607bf2a952dSSerge Semin * The method is called from PCIe ISR bottom-half routine. 1608bf2a952dSSerge Semin */ 1609bf2a952dSSerge Semin static void idt_msg_isr(struct idt_ntb_dev *ndev, u32 ntint_sts) 1610bf2a952dSSerge Semin { 1611bf2a952dSSerge Semin /* 1612bf2a952dSSerge Semin * Message IRQ status will be cleaned only when client 1613bf2a952dSSerge Semin * driver unsets all the message status bits. 1614bf2a952dSSerge Semin */ 1615bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "Message IRQ detected %#08x", ntint_sts); 1616bf2a952dSSerge Semin 1617bf2a952dSSerge Semin /* Notify the client driver of possible message status change */ 1618bf2a952dSSerge Semin ntb_msg_event(&ndev->ntb); 1619bf2a952dSSerge Semin } 1620bf2a952dSSerge Semin 1621bf2a952dSSerge Semin /* 1622bf2a952dSSerge Semin * idt_ntb_msg_count() - get the number of message registers (NTB API callback) 1623bf2a952dSSerge Semin * @ntb: NTB device context. 1624bf2a952dSSerge Semin * 1625bf2a952dSSerge Semin * IDT PCIe-switches support four message registers. 1626bf2a952dSSerge Semin * 1627bf2a952dSSerge Semin * Return: the number of message registers. 1628bf2a952dSSerge Semin */ 1629bf2a952dSSerge Semin static int idt_ntb_msg_count(struct ntb_dev *ntb) 1630bf2a952dSSerge Semin { 1631bf2a952dSSerge Semin return IDT_MSG_CNT; 1632bf2a952dSSerge Semin } 1633bf2a952dSSerge Semin 1634bf2a952dSSerge Semin /* 1635bf2a952dSSerge Semin * idt_ntb_msg_inbits() - get a bitfield of inbound message registers status 1636bf2a952dSSerge Semin * (NTB API callback) 1637bf2a952dSSerge Semin * @ntb: NTB device context. 1638bf2a952dSSerge Semin * 1639bf2a952dSSerge Semin * NT message status register is shared between inbound and outbound message 1640bf2a952dSSerge Semin * registers status 1641bf2a952dSSerge Semin * 1642bf2a952dSSerge Semin * Return: bitfield of inbound message registers. 1643bf2a952dSSerge Semin */ 1644bf2a952dSSerge Semin static u64 idt_ntb_msg_inbits(struct ntb_dev *ntb) 1645bf2a952dSSerge Semin { 1646bf2a952dSSerge Semin return (u64)IDT_INMSG_MASK; 1647bf2a952dSSerge Semin } 1648bf2a952dSSerge Semin 1649bf2a952dSSerge Semin /* 1650bf2a952dSSerge Semin * idt_ntb_msg_outbits() - get a bitfield of outbound message registers status 1651bf2a952dSSerge Semin * (NTB API callback) 1652bf2a952dSSerge Semin * @ntb: NTB device context. 1653bf2a952dSSerge Semin * 1654bf2a952dSSerge Semin * NT message status register is shared between inbound and outbound message 1655bf2a952dSSerge Semin * registers status 1656bf2a952dSSerge Semin * 1657bf2a952dSSerge Semin * Return: bitfield of outbound message registers. 1658bf2a952dSSerge Semin */ 1659bf2a952dSSerge Semin static u64 idt_ntb_msg_outbits(struct ntb_dev *ntb) 1660bf2a952dSSerge Semin { 1661bf2a952dSSerge Semin return (u64)IDT_OUTMSG_MASK; 1662bf2a952dSSerge Semin } 1663bf2a952dSSerge Semin 1664bf2a952dSSerge Semin /* 1665bf2a952dSSerge Semin * idt_ntb_msg_read_sts() - read the message registers status (NTB API callback) 1666bf2a952dSSerge Semin * @ntb: NTB device context. 1667bf2a952dSSerge Semin * 1668bf2a952dSSerge Semin * IDT PCIe-switches expose message status registers to notify drivers of 1669bf2a952dSSerge Semin * incoming data and failures in case if peer message register isn't freed. 1670bf2a952dSSerge Semin * 1671bf2a952dSSerge Semin * Return: status bits of message registers 1672bf2a952dSSerge Semin */ 1673bf2a952dSSerge Semin static u64 idt_ntb_msg_read_sts(struct ntb_dev *ntb) 1674bf2a952dSSerge Semin { 1675bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1676bf2a952dSSerge Semin 1677bf2a952dSSerge Semin return idt_nt_read(ndev, IDT_NT_MSGSTS); 1678bf2a952dSSerge Semin } 1679bf2a952dSSerge Semin 1680bf2a952dSSerge Semin /* 1681bf2a952dSSerge Semin * idt_ntb_msg_clear_sts() - clear status bits of message registers 1682bf2a952dSSerge Semin * (NTB API callback) 1683bf2a952dSSerge Semin * @ntb: NTB device context. 1684bf2a952dSSerge Semin * @sts_bits: Status bits to clear. 1685bf2a952dSSerge Semin * 1686bf2a952dSSerge Semin * Clear bits in the status register by writing ones. 1687bf2a952dSSerge Semin * 1688bf2a952dSSerge Semin * NOTE! Invalid bits are always considered cleared so it's not an error 1689bf2a952dSSerge Semin * to clear them over. 1690bf2a952dSSerge Semin * 1691bf2a952dSSerge Semin * Return: always zero as success. 1692bf2a952dSSerge Semin */ 1693bf2a952dSSerge Semin static int idt_ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits) 1694bf2a952dSSerge Semin { 1695bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1696bf2a952dSSerge Semin 1697bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_MSGSTS, sts_bits); 1698bf2a952dSSerge Semin 1699bf2a952dSSerge Semin return 0; 1700bf2a952dSSerge Semin } 1701bf2a952dSSerge Semin 1702bf2a952dSSerge Semin /* 1703bf2a952dSSerge Semin * idt_ntb_msg_set_mask() - set mask of message register status bits 1704bf2a952dSSerge Semin * (NTB API callback) 1705bf2a952dSSerge Semin * @ntb: NTB device context. 1706bf2a952dSSerge Semin * @mask_bits: Mask bits. 1707bf2a952dSSerge Semin * 1708bf2a952dSSerge Semin * Mask the message status bits from raising an IRQ. 1709bf2a952dSSerge Semin * 1710bf2a952dSSerge Semin * Return: zero on success, negative error if invalid argument passed. 1711bf2a952dSSerge Semin */ 1712bf2a952dSSerge Semin static int idt_ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits) 1713bf2a952dSSerge Semin { 1714bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1715bf2a952dSSerge Semin 1716bf2a952dSSerge Semin return idt_reg_set_bits(ndev, IDT_NT_MSGSTSMSK, &ndev->msg_mask_lock, 1717bf2a952dSSerge Semin IDT_MSG_MASK, mask_bits); 1718bf2a952dSSerge Semin } 1719bf2a952dSSerge Semin 1720bf2a952dSSerge Semin /* 1721bf2a952dSSerge Semin * idt_ntb_msg_clear_mask() - clear message registers mask 1722bf2a952dSSerge Semin * (NTB API callback) 1723bf2a952dSSerge Semin * @ntb: NTB device context. 1724bf2a952dSSerge Semin * @mask_bits: Mask bits. 1725bf2a952dSSerge Semin * 1726bf2a952dSSerge Semin * Clear mask of message status bits IRQs. 1727bf2a952dSSerge Semin * 1728bf2a952dSSerge Semin * Return: always zero as success. 1729bf2a952dSSerge Semin */ 1730bf2a952dSSerge Semin static int idt_ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits) 1731bf2a952dSSerge Semin { 1732bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1733bf2a952dSSerge Semin 1734bf2a952dSSerge Semin idt_reg_clear_bits(ndev, IDT_NT_MSGSTSMSK, &ndev->msg_mask_lock, 1735bf2a952dSSerge Semin mask_bits); 1736bf2a952dSSerge Semin 1737bf2a952dSSerge Semin return 0; 1738bf2a952dSSerge Semin } 1739bf2a952dSSerge Semin 1740bf2a952dSSerge Semin /* 1741bf2a952dSSerge Semin * idt_ntb_msg_read() - read message register with specified index 1742bf2a952dSSerge Semin * (NTB API callback) 1743bf2a952dSSerge Semin * @ntb: NTB device context. 1744bf2a952dSSerge Semin * @pidx: OUT - Port index of peer device a message retrieved from 1745b87ab219SSerge Semin * @midx: Message register index 1746bf2a952dSSerge Semin * 1747bf2a952dSSerge Semin * Read data from the specified message register and source register. 1748bf2a952dSSerge Semin * 1749b87ab219SSerge Semin * Return: inbound message register value. 1750bf2a952dSSerge Semin */ 1751b87ab219SSerge Semin static u32 idt_ntb_msg_read(struct ntb_dev *ntb, int *pidx, int midx) 1752bf2a952dSSerge Semin { 1753bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1754bf2a952dSSerge Semin 1755bf2a952dSSerge Semin if (midx < 0 || IDT_MSG_CNT <= midx) 1756b87ab219SSerge Semin return ~(u32)0; 1757bf2a952dSSerge Semin 1758bf2a952dSSerge Semin /* Retrieve source port index of the message */ 1759bf2a952dSSerge Semin if (pidx != NULL) { 1760bf2a952dSSerge Semin u32 srcpart; 1761bf2a952dSSerge Semin 1762bf2a952dSSerge Semin srcpart = idt_nt_read(ndev, ntdata_tbl.msgs[midx].src); 1763bf2a952dSSerge Semin *pidx = ndev->part_idx_map[srcpart]; 1764bf2a952dSSerge Semin 1765bf2a952dSSerge Semin /* Sanity check partition index (for initial case) */ 1766bf2a952dSSerge Semin if (*pidx == -EINVAL) 1767bf2a952dSSerge Semin *pidx = 0; 1768bf2a952dSSerge Semin } 1769bf2a952dSSerge Semin 1770bf2a952dSSerge Semin /* Retrieve data of the corresponding message register */ 1771b87ab219SSerge Semin return idt_nt_read(ndev, ntdata_tbl.msgs[midx].in); 1772bf2a952dSSerge Semin } 1773bf2a952dSSerge Semin 1774bf2a952dSSerge Semin /* 1775b87ab219SSerge Semin * idt_ntb_peer_msg_write() - write data to the specified message register 1776bf2a952dSSerge Semin * (NTB API callback) 1777bf2a952dSSerge Semin * @ntb: NTB device context. 1778bf2a952dSSerge Semin * @pidx: Port index of peer device a message being sent to 1779b87ab219SSerge Semin * @midx: Message register index 1780bf2a952dSSerge Semin * @msg: Data to send 1781bf2a952dSSerge Semin * 1782bf2a952dSSerge Semin * Just try to send data to a peer. Message status register should be 1783bf2a952dSSerge Semin * checked by client driver. 1784bf2a952dSSerge Semin * 1785bf2a952dSSerge Semin * Return: zero on success, negative error if invalid argument passed. 1786bf2a952dSSerge Semin */ 1787b87ab219SSerge Semin static int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx, 1788b87ab219SSerge Semin u32 msg) 1789bf2a952dSSerge Semin { 1790bf2a952dSSerge Semin struct idt_ntb_dev *ndev = to_ndev_ntb(ntb); 1791bf2a952dSSerge Semin unsigned long irqflags; 1792bf2a952dSSerge Semin u32 swpmsgctl = 0; 1793bf2a952dSSerge Semin 1794bf2a952dSSerge Semin if (midx < 0 || IDT_MSG_CNT <= midx) 1795bf2a952dSSerge Semin return -EINVAL; 1796bf2a952dSSerge Semin 1797bf2a952dSSerge Semin if (pidx < 0 || ndev->peer_cnt <= pidx) 1798bf2a952dSSerge Semin return -EINVAL; 1799bf2a952dSSerge Semin 1800bf2a952dSSerge Semin /* Collect the routing information */ 1801bf2a952dSSerge Semin swpmsgctl = SET_FIELD(SWPxMSGCTL_REG, 0, midx) | 1802bf2a952dSSerge Semin SET_FIELD(SWPxMSGCTL_PART, 0, ndev->peers[pidx].part); 1803bf2a952dSSerge Semin 1804bf2a952dSSerge Semin /* Lock the messages routing table of the specified register */ 1805bf2a952dSSerge Semin spin_lock_irqsave(&ndev->msg_locks[midx], irqflags); 1806bf2a952dSSerge Semin /* Set the route and send the data */ 1807bf2a952dSSerge Semin idt_sw_write(ndev, partdata_tbl[ndev->part].msgctl[midx], swpmsgctl); 1808bf2a952dSSerge Semin idt_nt_write(ndev, ntdata_tbl.msgs[midx].out, msg); 1809bf2a952dSSerge Semin /* Unlock the messages routing table */ 1810bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->msg_locks[midx], irqflags); 1811bf2a952dSSerge Semin 1812bf2a952dSSerge Semin /* Client driver shall check the status register */ 1813bf2a952dSSerge Semin return 0; 1814bf2a952dSSerge Semin } 1815bf2a952dSSerge Semin 1816bf2a952dSSerge Semin /*============================================================================= 1817bf2a952dSSerge Semin * 7. Temperature sensor operations 1818bf2a952dSSerge Semin * 1819bf2a952dSSerge Semin * IDT PCIe-switch has an embedded temperature sensor, which can be used to 1820a662315dSSerge Semin * check current chip core temperature. Since a workload environment can be 1821a662315dSSerge Semin * different on different platforms, an offset and ADC/filter settings can be 1822a662315dSSerge Semin * specified. Although the offset configuration is only exposed to the sysfs 1823a662315dSSerge Semin * hwmon interface at the moment. The rest of the settings can be adjusted 1824a662315dSSerge Semin * for instance by the BIOS/EEPROM firmware. 1825bf2a952dSSerge Semin *============================================================================= 1826bf2a952dSSerge Semin */ 1827bf2a952dSSerge Semin 1828bf2a952dSSerge Semin /* 182940070408SSerge Semin * idt_get_deg() - convert millidegree Celsius value to just degree 183040070408SSerge Semin * @mdegC: IN - millidegree Celsius value 183140070408SSerge Semin * 183240070408SSerge Semin * Return: Degree corresponding to the passed millidegree value 183340070408SSerge Semin */ 183440070408SSerge Semin static inline s8 idt_get_deg(long mdegC) 183540070408SSerge Semin { 183640070408SSerge Semin return mdegC / 1000; 183740070408SSerge Semin } 183840070408SSerge Semin 183940070408SSerge Semin /* 184040070408SSerge Semin * idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value 184140070408SSerge Semin * @mdegC: IN - millidegree Celsius value 184240070408SSerge Semin * 184340070408SSerge Semin * Return: 0/0.5 degree fraction of the passed millidegree value 184440070408SSerge Semin */ 184540070408SSerge Semin static inline u8 idt_get_deg_frac(long mdegC) 184640070408SSerge Semin { 184740070408SSerge Semin return (mdegC % 1000) >= 500 ? 5 : 0; 184840070408SSerge Semin } 184940070408SSerge Semin 185040070408SSerge Semin /* 185140070408SSerge Semin * idt_get_temp_fmt() - convert millidegree Celsius value to 0:7:1 format 185240070408SSerge Semin * @mdegC: IN - millidegree Celsius value 185340070408SSerge Semin * 185440070408SSerge Semin * Return: 0:7:1 format acceptable by the IDT temperature sensor 185540070408SSerge Semin */ 185640070408SSerge Semin static inline u8 idt_temp_get_fmt(long mdegC) 185740070408SSerge Semin { 185840070408SSerge Semin return (idt_get_deg(mdegC) << 1) | (idt_get_deg_frac(mdegC) ? 1 : 0); 185940070408SSerge Semin } 186040070408SSerge Semin 186140070408SSerge Semin /* 186240070408SSerge Semin * idt_get_temp_sval() - convert temp sample to signed millidegree Celsius 186340070408SSerge Semin * @data: IN - shifted to LSB 8-bits temperature sample 186440070408SSerge Semin * 186540070408SSerge Semin * Return: signed millidegree Celsius 186640070408SSerge Semin */ 186740070408SSerge Semin static inline long idt_get_temp_sval(u32 data) 186840070408SSerge Semin { 186940070408SSerge Semin return ((s8)data / 2) * 1000 + (data & 0x1 ? 500 : 0); 187040070408SSerge Semin } 187140070408SSerge Semin 187240070408SSerge Semin /* 187340070408SSerge Semin * idt_get_temp_sval() - convert temp sample to unsigned millidegree Celsius 187440070408SSerge Semin * @data: IN - shifted to LSB 8-bits temperature sample 187540070408SSerge Semin * 187640070408SSerge Semin * Return: unsigned millidegree Celsius 187740070408SSerge Semin */ 187840070408SSerge Semin static inline long idt_get_temp_uval(u32 data) 187940070408SSerge Semin { 188040070408SSerge Semin return (data / 2) * 1000 + (data & 0x1 ? 500 : 0); 188140070408SSerge Semin } 188240070408SSerge Semin 188340070408SSerge Semin /* 1884bf2a952dSSerge Semin * idt_read_temp() - read temperature from chip sensor 1885bf2a952dSSerge Semin * @ntb: NTB device context. 188640070408SSerge Semin * @type: IN - type of the temperature value to read 188740070408SSerge Semin * @val: OUT - integer value of temperature in millidegree Celsius 1888bf2a952dSSerge Semin */ 188940070408SSerge Semin static void idt_read_temp(struct idt_ntb_dev *ndev, 189040070408SSerge Semin const enum idt_temp_val type, long *val) 1891bf2a952dSSerge Semin { 1892bf2a952dSSerge Semin u32 data; 1893bf2a952dSSerge Semin 189440070408SSerge Semin /* Alter the temperature field in accordance with the passed type */ 189540070408SSerge Semin switch (type) { 189640070408SSerge Semin case IDT_TEMP_CUR: 189740070408SSerge Semin data = GET_FIELD(TMPSTS_TEMP, 189840070408SSerge Semin idt_sw_read(ndev, IDT_SW_TMPSTS)); 189940070408SSerge Semin break; 190040070408SSerge Semin case IDT_TEMP_LOW: 190140070408SSerge Semin data = GET_FIELD(TMPSTS_LTEMP, 190240070408SSerge Semin idt_sw_read(ndev, IDT_SW_TMPSTS)); 190340070408SSerge Semin break; 190440070408SSerge Semin case IDT_TEMP_HIGH: 190540070408SSerge Semin data = GET_FIELD(TMPSTS_HTEMP, 190640070408SSerge Semin idt_sw_read(ndev, IDT_SW_TMPSTS)); 190740070408SSerge Semin break; 190840070408SSerge Semin case IDT_TEMP_OFFSET: 190940070408SSerge Semin /* This is the only field with signed 0:7:1 format */ 191040070408SSerge Semin data = GET_FIELD(TMPADJ_OFFSET, 191140070408SSerge Semin idt_sw_read(ndev, IDT_SW_TMPADJ)); 191240070408SSerge Semin *val = idt_get_temp_sval(data); 191340070408SSerge Semin return; 191440070408SSerge Semin default: 191540070408SSerge Semin data = GET_FIELD(TMPSTS_TEMP, 191640070408SSerge Semin idt_sw_read(ndev, IDT_SW_TMPSTS)); 191740070408SSerge Semin break; 191840070408SSerge Semin } 191940070408SSerge Semin 192040070408SSerge Semin /* The rest of the fields accept unsigned 0:7:1 format */ 192140070408SSerge Semin *val = idt_get_temp_uval(data); 1922bf2a952dSSerge Semin } 1923bf2a952dSSerge Semin 1924bf2a952dSSerge Semin /* 1925aed1b7b3SSerge Semin * idt_write_temp() - write temperature to the chip sensor register 1926aed1b7b3SSerge Semin * @ntb: NTB device context. 1927aed1b7b3SSerge Semin * @type: IN - type of the temperature value to change 1928aed1b7b3SSerge Semin * @val: IN - integer value of temperature in millidegree Celsius 1929aed1b7b3SSerge Semin */ 1930aed1b7b3SSerge Semin static void idt_write_temp(struct idt_ntb_dev *ndev, 1931aed1b7b3SSerge Semin const enum idt_temp_val type, const long val) 1932aed1b7b3SSerge Semin { 1933aed1b7b3SSerge Semin unsigned int reg; 1934aed1b7b3SSerge Semin u32 data; 1935aed1b7b3SSerge Semin u8 fmt; 1936aed1b7b3SSerge Semin 1937aed1b7b3SSerge Semin /* Retrieve the properly formatted temperature value */ 1938aed1b7b3SSerge Semin fmt = idt_temp_get_fmt(val); 1939aed1b7b3SSerge Semin 1940aed1b7b3SSerge Semin mutex_lock(&ndev->hwmon_mtx); 1941aed1b7b3SSerge Semin switch (type) { 1942aed1b7b3SSerge Semin case IDT_TEMP_LOW: 1943aed1b7b3SSerge Semin reg = IDT_SW_TMPALARM; 1944aed1b7b3SSerge Semin data = SET_FIELD(TMPALARM_LTEMP, idt_sw_read(ndev, reg), fmt) & 1945aed1b7b3SSerge Semin ~IDT_TMPALARM_IRQ_MASK; 1946aed1b7b3SSerge Semin break; 1947aed1b7b3SSerge Semin case IDT_TEMP_HIGH: 1948aed1b7b3SSerge Semin reg = IDT_SW_TMPALARM; 1949aed1b7b3SSerge Semin data = SET_FIELD(TMPALARM_HTEMP, idt_sw_read(ndev, reg), fmt) & 1950aed1b7b3SSerge Semin ~IDT_TMPALARM_IRQ_MASK; 1951aed1b7b3SSerge Semin break; 1952aed1b7b3SSerge Semin case IDT_TEMP_OFFSET: 1953aed1b7b3SSerge Semin reg = IDT_SW_TMPADJ; 1954aed1b7b3SSerge Semin data = SET_FIELD(TMPADJ_OFFSET, idt_sw_read(ndev, reg), fmt); 1955aed1b7b3SSerge Semin break; 1956aed1b7b3SSerge Semin default: 1957aed1b7b3SSerge Semin goto inval_spin_unlock; 1958aed1b7b3SSerge Semin } 1959aed1b7b3SSerge Semin 1960aed1b7b3SSerge Semin idt_sw_write(ndev, reg, data); 1961aed1b7b3SSerge Semin 1962aed1b7b3SSerge Semin inval_spin_unlock: 1963aed1b7b3SSerge Semin mutex_unlock(&ndev->hwmon_mtx); 1964aed1b7b3SSerge Semin } 1965aed1b7b3SSerge Semin 1966aed1b7b3SSerge Semin /* 1967aed1b7b3SSerge Semin * idt_sysfs_show_temp() - printout corresponding temperature value 1968aed1b7b3SSerge Semin * @dev: Pointer to the NTB device structure 1969aed1b7b3SSerge Semin * @da: Sensor device attribute structure 1970aed1b7b3SSerge Semin * @buf: Buffer to print temperature out 1971aed1b7b3SSerge Semin * 1972aed1b7b3SSerge Semin * Return: Number of written symbols or negative error 1973aed1b7b3SSerge Semin */ 1974aed1b7b3SSerge Semin static ssize_t idt_sysfs_show_temp(struct device *dev, 1975aed1b7b3SSerge Semin struct device_attribute *da, char *buf) 1976aed1b7b3SSerge Semin { 1977aed1b7b3SSerge Semin struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 1978aed1b7b3SSerge Semin struct idt_ntb_dev *ndev = dev_get_drvdata(dev); 1979aed1b7b3SSerge Semin enum idt_temp_val type = attr->index; 1980aed1b7b3SSerge Semin long mdeg; 1981aed1b7b3SSerge Semin 1982aed1b7b3SSerge Semin idt_read_temp(ndev, type, &mdeg); 1983aed1b7b3SSerge Semin return sprintf(buf, "%ld\n", mdeg); 1984aed1b7b3SSerge Semin } 1985aed1b7b3SSerge Semin 1986aed1b7b3SSerge Semin /* 1987aed1b7b3SSerge Semin * idt_sysfs_set_temp() - set corresponding temperature value 1988aed1b7b3SSerge Semin * @dev: Pointer to the NTB device structure 1989aed1b7b3SSerge Semin * @da: Sensor device attribute structure 1990aed1b7b3SSerge Semin * @buf: Buffer to print temperature out 1991aed1b7b3SSerge Semin * @count: Size of the passed buffer 1992aed1b7b3SSerge Semin * 1993aed1b7b3SSerge Semin * Return: Number of written symbols or negative error 1994aed1b7b3SSerge Semin */ 1995aed1b7b3SSerge Semin static ssize_t idt_sysfs_set_temp(struct device *dev, 1996aed1b7b3SSerge Semin struct device_attribute *da, const char *buf, 1997aed1b7b3SSerge Semin size_t count) 1998aed1b7b3SSerge Semin { 1999aed1b7b3SSerge Semin struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 2000aed1b7b3SSerge Semin struct idt_ntb_dev *ndev = dev_get_drvdata(dev); 2001aed1b7b3SSerge Semin enum idt_temp_val type = attr->index; 2002aed1b7b3SSerge Semin long mdeg; 2003aed1b7b3SSerge Semin int ret; 2004aed1b7b3SSerge Semin 2005aed1b7b3SSerge Semin ret = kstrtol(buf, 10, &mdeg); 2006aed1b7b3SSerge Semin if (ret) 2007aed1b7b3SSerge Semin return ret; 2008aed1b7b3SSerge Semin 2009aed1b7b3SSerge Semin /* Clamp the passed value in accordance with the type */ 2010aed1b7b3SSerge Semin if (type == IDT_TEMP_OFFSET) 2011aed1b7b3SSerge Semin mdeg = clamp_val(mdeg, IDT_TEMP_MIN_OFFSET, 2012aed1b7b3SSerge Semin IDT_TEMP_MAX_OFFSET); 2013aed1b7b3SSerge Semin else 2014aed1b7b3SSerge Semin mdeg = clamp_val(mdeg, IDT_TEMP_MIN_MDEG, IDT_TEMP_MAX_MDEG); 2015aed1b7b3SSerge Semin 2016aed1b7b3SSerge Semin idt_write_temp(ndev, type, mdeg); 2017aed1b7b3SSerge Semin 2018aed1b7b3SSerge Semin return count; 2019aed1b7b3SSerge Semin } 2020aed1b7b3SSerge Semin 2021aed1b7b3SSerge Semin /* 2022aed1b7b3SSerge Semin * idt_sysfs_reset_hist() - reset temperature history 2023aed1b7b3SSerge Semin * @dev: Pointer to the NTB device structure 2024aed1b7b3SSerge Semin * @da: Sensor device attribute structure 2025aed1b7b3SSerge Semin * @buf: Buffer to print temperature out 2026aed1b7b3SSerge Semin * @count: Size of the passed buffer 2027aed1b7b3SSerge Semin * 2028aed1b7b3SSerge Semin * Return: Number of written symbols or negative error 2029aed1b7b3SSerge Semin */ 2030aed1b7b3SSerge Semin static ssize_t idt_sysfs_reset_hist(struct device *dev, 2031aed1b7b3SSerge Semin struct device_attribute *da, 2032aed1b7b3SSerge Semin const char *buf, size_t count) 2033aed1b7b3SSerge Semin { 2034aed1b7b3SSerge Semin struct idt_ntb_dev *ndev = dev_get_drvdata(dev); 2035aed1b7b3SSerge Semin 2036aed1b7b3SSerge Semin /* Just set the maximal value to the lowest temperature field and 2037aed1b7b3SSerge Semin * minimal value to the highest temperature field 2038aed1b7b3SSerge Semin */ 2039aed1b7b3SSerge Semin idt_write_temp(ndev, IDT_TEMP_LOW, IDT_TEMP_MAX_MDEG); 2040aed1b7b3SSerge Semin idt_write_temp(ndev, IDT_TEMP_HIGH, IDT_TEMP_MIN_MDEG); 2041aed1b7b3SSerge Semin 2042aed1b7b3SSerge Semin return count; 2043aed1b7b3SSerge Semin } 2044aed1b7b3SSerge Semin 2045aed1b7b3SSerge Semin /* 2046aed1b7b3SSerge Semin * Hwmon IDT sysfs attributes 2047aed1b7b3SSerge Semin */ 2048aed1b7b3SSerge Semin static SENSOR_DEVICE_ATTR(temp1_input, 0444, idt_sysfs_show_temp, NULL, 2049aed1b7b3SSerge Semin IDT_TEMP_CUR); 2050aed1b7b3SSerge Semin static SENSOR_DEVICE_ATTR(temp1_lowest, 0444, idt_sysfs_show_temp, NULL, 2051aed1b7b3SSerge Semin IDT_TEMP_LOW); 2052aed1b7b3SSerge Semin static SENSOR_DEVICE_ATTR(temp1_highest, 0444, idt_sysfs_show_temp, NULL, 2053aed1b7b3SSerge Semin IDT_TEMP_HIGH); 2054aed1b7b3SSerge Semin static SENSOR_DEVICE_ATTR(temp1_offset, 0644, idt_sysfs_show_temp, 2055aed1b7b3SSerge Semin idt_sysfs_set_temp, IDT_TEMP_OFFSET); 2056aed1b7b3SSerge Semin static DEVICE_ATTR(temp1_reset_history, 0200, NULL, idt_sysfs_reset_hist); 2057aed1b7b3SSerge Semin 2058aed1b7b3SSerge Semin /* 2059aed1b7b3SSerge Semin * Hwmon IDT sysfs attributes group 2060aed1b7b3SSerge Semin */ 2061aed1b7b3SSerge Semin static struct attribute *idt_temp_attrs[] = { 2062aed1b7b3SSerge Semin &sensor_dev_attr_temp1_input.dev_attr.attr, 2063aed1b7b3SSerge Semin &sensor_dev_attr_temp1_lowest.dev_attr.attr, 2064aed1b7b3SSerge Semin &sensor_dev_attr_temp1_highest.dev_attr.attr, 2065aed1b7b3SSerge Semin &sensor_dev_attr_temp1_offset.dev_attr.attr, 2066aed1b7b3SSerge Semin &dev_attr_temp1_reset_history.attr, 2067aed1b7b3SSerge Semin NULL 2068aed1b7b3SSerge Semin }; 2069aed1b7b3SSerge Semin ATTRIBUTE_GROUPS(idt_temp); 2070aed1b7b3SSerge Semin 2071aed1b7b3SSerge Semin /* 2072aed1b7b3SSerge Semin * idt_init_temp() - initialize temperature sensor interface 2073aed1b7b3SSerge Semin * @ndev: IDT NTB hardware driver descriptor 2074aed1b7b3SSerge Semin * 2075aed1b7b3SSerge Semin * Simple sensor initializarion method is responsible for device switching 2076aed1b7b3SSerge Semin * on and resource management based hwmon interface registration. Note, that 2077aed1b7b3SSerge Semin * since the device is shared we won't disable it on remove, but leave it 2078aed1b7b3SSerge Semin * working until the system is powered off. 2079aed1b7b3SSerge Semin */ 2080aed1b7b3SSerge Semin static void idt_init_temp(struct idt_ntb_dev *ndev) 2081aed1b7b3SSerge Semin { 2082aed1b7b3SSerge Semin struct device *hwmon; 2083aed1b7b3SSerge Semin 2084aed1b7b3SSerge Semin /* Enable sensor if it hasn't been already */ 2085aed1b7b3SSerge Semin idt_sw_write(ndev, IDT_SW_TMPCTL, 0x0); 2086aed1b7b3SSerge Semin 2087aed1b7b3SSerge Semin /* Initialize hwmon interface fields */ 2088aed1b7b3SSerge Semin mutex_init(&ndev->hwmon_mtx); 2089aed1b7b3SSerge Semin 2090aed1b7b3SSerge Semin hwmon = devm_hwmon_device_register_with_groups(&ndev->ntb.pdev->dev, 2091aed1b7b3SSerge Semin ndev->swcfg->name, ndev, idt_temp_groups); 2092aed1b7b3SSerge Semin if (IS_ERR(hwmon)) { 2093aed1b7b3SSerge Semin dev_err(&ndev->ntb.pdev->dev, "Couldn't create hwmon device"); 2094aed1b7b3SSerge Semin return; 2095aed1b7b3SSerge Semin } 2096aed1b7b3SSerge Semin 2097aed1b7b3SSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "Temperature HWmon interface registered"); 2098aed1b7b3SSerge Semin } 2099aed1b7b3SSerge Semin 2100bf2a952dSSerge Semin /*============================================================================= 2101bf2a952dSSerge Semin * 8. ISRs related operations 2102bf2a952dSSerge Semin * 2103bf2a952dSSerge Semin * IDT PCIe-switch has strangely developed IRQ system. There is just one 2104bf2a952dSSerge Semin * interrupt vector for doorbell and message registers. So the hardware driver 2105bf2a952dSSerge Semin * can't determine actual source of IRQ if, for example, message event happened 2106bf2a952dSSerge Semin * while any of unmasked doorbell is still set. The similar situation may be if 2107bf2a952dSSerge Semin * switch or temperature sensor events pop up. The difference is that SEVENT 2108bf2a952dSSerge Semin * and TMPSENSOR bits of NT interrupt status register can be cleaned by 2109bf2a952dSSerge Semin * IRQ handler so a next interrupt request won't have false handling of 2110bf2a952dSSerge Semin * corresponding events. 2111bf2a952dSSerge Semin * The hardware driver has only bottom-half handler of the IRQ, since if any 2112bf2a952dSSerge Semin * of events happened the device won't raise it again before the last one is 2113bf2a952dSSerge Semin * handled by clearing of corresponding NTINTSTS bit. 2114bf2a952dSSerge Semin *============================================================================= 2115bf2a952dSSerge Semin */ 2116bf2a952dSSerge Semin 2117bf2a952dSSerge Semin static irqreturn_t idt_thread_isr(int irq, void *devid); 2118bf2a952dSSerge Semin 2119bf2a952dSSerge Semin /* 2120bf2a952dSSerge Semin * idt_init_isr() - initialize PCIe interrupt handler 2121bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 2122bf2a952dSSerge Semin * 2123bf2a952dSSerge Semin * Return: zero on success, otherwise a negative error number. 2124bf2a952dSSerge Semin */ 2125bf2a952dSSerge Semin static int idt_init_isr(struct idt_ntb_dev *ndev) 2126bf2a952dSSerge Semin { 2127bf2a952dSSerge Semin struct pci_dev *pdev = ndev->ntb.pdev; 2128bf2a952dSSerge Semin u32 ntint_mask; 2129bf2a952dSSerge Semin int ret; 2130bf2a952dSSerge Semin 2131bf2a952dSSerge Semin /* Allocate just one interrupt vector for the ISR */ 2132bf2a952dSSerge Semin ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY); 2133bf2a952dSSerge Semin if (ret != 1) { 2134bf2a952dSSerge Semin dev_err(&pdev->dev, "Failed to allocate IRQ vector"); 2135bf2a952dSSerge Semin return ret; 2136bf2a952dSSerge Semin } 2137bf2a952dSSerge Semin 2138bf2a952dSSerge Semin /* Retrieve the IRQ vector */ 2139bf2a952dSSerge Semin ret = pci_irq_vector(pdev, 0); 2140bf2a952dSSerge Semin if (ret < 0) { 2141bf2a952dSSerge Semin dev_err(&pdev->dev, "Failed to get IRQ vector"); 2142bf2a952dSSerge Semin goto err_free_vectors; 2143bf2a952dSSerge Semin } 2144bf2a952dSSerge Semin 2145bf2a952dSSerge Semin /* Set the IRQ handler */ 2146bf2a952dSSerge Semin ret = devm_request_threaded_irq(&pdev->dev, ret, NULL, idt_thread_isr, 2147bf2a952dSSerge Semin IRQF_ONESHOT, NTB_IRQNAME, ndev); 2148bf2a952dSSerge Semin if (ret != 0) { 2149bf2a952dSSerge Semin dev_err(&pdev->dev, "Failed to set MSI IRQ handler, %d", ret); 2150bf2a952dSSerge Semin goto err_free_vectors; 2151bf2a952dSSerge Semin } 2152bf2a952dSSerge Semin 2153b8babacbSSerge Semin /* Unmask Message/Doorbell/SE interrupts */ 2154bf2a952dSSerge Semin ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) & ~IDT_NTINTMSK_ALL; 2155bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask); 2156bf2a952dSSerge Semin 2157bf2a952dSSerge Semin /* From now on the interrupts are enabled */ 2158bf2a952dSSerge Semin dev_dbg(&pdev->dev, "NTB interrupts initialized"); 2159bf2a952dSSerge Semin 2160bf2a952dSSerge Semin return 0; 2161bf2a952dSSerge Semin 2162bf2a952dSSerge Semin err_free_vectors: 2163bf2a952dSSerge Semin pci_free_irq_vectors(pdev); 2164bf2a952dSSerge Semin 2165bf2a952dSSerge Semin return ret; 2166bf2a952dSSerge Semin } 2167bf2a952dSSerge Semin 2168bf2a952dSSerge Semin /* 2169bf2a952dSSerge Semin * idt_deinit_ist() - deinitialize PCIe interrupt handler 2170bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 2171bf2a952dSSerge Semin * 2172bf2a952dSSerge Semin * Disable corresponding interrupts and free allocated IRQ vectors. 2173bf2a952dSSerge Semin */ 2174bf2a952dSSerge Semin static void idt_deinit_isr(struct idt_ntb_dev *ndev) 2175bf2a952dSSerge Semin { 2176bf2a952dSSerge Semin struct pci_dev *pdev = ndev->ntb.pdev; 2177bf2a952dSSerge Semin u32 ntint_mask; 2178bf2a952dSSerge Semin 2179bf2a952dSSerge Semin /* Mask interrupts back */ 2180bf2a952dSSerge Semin ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) | IDT_NTINTMSK_ALL; 2181bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask); 2182bf2a952dSSerge Semin 2183bf2a952dSSerge Semin /* Manually free IRQ otherwise PCI free irq vectors will fail */ 2184bf2a952dSSerge Semin devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 0), ndev); 2185bf2a952dSSerge Semin 2186bf2a952dSSerge Semin /* Free allocated IRQ vectors */ 2187bf2a952dSSerge Semin pci_free_irq_vectors(pdev); 2188bf2a952dSSerge Semin 2189bf2a952dSSerge Semin dev_dbg(&pdev->dev, "NTB interrupts deinitialized"); 2190bf2a952dSSerge Semin } 2191bf2a952dSSerge Semin 2192bf2a952dSSerge Semin /* 2193bf2a952dSSerge Semin * idt_thread_isr() - NT function interrupts handler 2194bf2a952dSSerge Semin * @irq: IRQ number 2195bf2a952dSSerge Semin * @devid: Custom buffer 2196bf2a952dSSerge Semin * 2197bf2a952dSSerge Semin * It reads current NT interrupts state register and handles all the event 2198bf2a952dSSerge Semin * it declares. 2199bf2a952dSSerge Semin * The method is bottom-half routine of actual default PCIe IRQ handler. 2200bf2a952dSSerge Semin */ 2201bf2a952dSSerge Semin static irqreturn_t idt_thread_isr(int irq, void *devid) 2202bf2a952dSSerge Semin { 2203bf2a952dSSerge Semin struct idt_ntb_dev *ndev = devid; 2204bf2a952dSSerge Semin bool handled = false; 2205bf2a952dSSerge Semin u32 ntint_sts; 2206bf2a952dSSerge Semin 2207bf2a952dSSerge Semin /* Read the NT interrupts status register */ 2208bf2a952dSSerge Semin ntint_sts = idt_nt_read(ndev, IDT_NT_NTINTSTS); 2209bf2a952dSSerge Semin 2210bf2a952dSSerge Semin /* Handle messaging interrupts */ 2211bf2a952dSSerge Semin if (ntint_sts & IDT_NTINTSTS_MSG) { 2212bf2a952dSSerge Semin idt_msg_isr(ndev, ntint_sts); 2213bf2a952dSSerge Semin handled = true; 2214bf2a952dSSerge Semin } 2215bf2a952dSSerge Semin 2216bf2a952dSSerge Semin /* Handle doorbell interrupts */ 2217bf2a952dSSerge Semin if (ntint_sts & IDT_NTINTSTS_DBELL) { 2218bf2a952dSSerge Semin idt_db_isr(ndev, ntint_sts); 2219bf2a952dSSerge Semin handled = true; 2220bf2a952dSSerge Semin } 2221bf2a952dSSerge Semin 2222bf2a952dSSerge Semin /* Handle switch event interrupts */ 2223bf2a952dSSerge Semin if (ntint_sts & IDT_NTINTSTS_SEVENT) { 2224bf2a952dSSerge Semin idt_se_isr(ndev, ntint_sts); 2225bf2a952dSSerge Semin handled = true; 2226bf2a952dSSerge Semin } 2227bf2a952dSSerge Semin 2228bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "IDT IRQs 0x%08x handled", ntint_sts); 2229bf2a952dSSerge Semin 2230bf2a952dSSerge Semin return handled ? IRQ_HANDLED : IRQ_NONE; 2231bf2a952dSSerge Semin } 2232bf2a952dSSerge Semin 2233bf2a952dSSerge Semin /*=========================================================================== 2234bf2a952dSSerge Semin * 9. NTB hardware driver initialization 2235bf2a952dSSerge Semin *=========================================================================== 2236bf2a952dSSerge Semin */ 2237bf2a952dSSerge Semin 2238bf2a952dSSerge Semin /* 2239bf2a952dSSerge Semin * NTB API operations 2240bf2a952dSSerge Semin */ 2241bf2a952dSSerge Semin static const struct ntb_dev_ops idt_ntb_ops = { 2242bf2a952dSSerge Semin .port_number = idt_ntb_port_number, 2243bf2a952dSSerge Semin .peer_port_count = idt_ntb_peer_port_count, 2244bf2a952dSSerge Semin .peer_port_number = idt_ntb_peer_port_number, 2245bf2a952dSSerge Semin .peer_port_idx = idt_ntb_peer_port_idx, 2246bf2a952dSSerge Semin .link_is_up = idt_ntb_link_is_up, 2247bf2a952dSSerge Semin .link_enable = idt_ntb_link_enable, 2248bf2a952dSSerge Semin .link_disable = idt_ntb_link_disable, 2249bf2a952dSSerge Semin .mw_count = idt_ntb_mw_count, 2250bf2a952dSSerge Semin .mw_get_align = idt_ntb_mw_get_align, 2251bf2a952dSSerge Semin .peer_mw_count = idt_ntb_peer_mw_count, 2252bf2a952dSSerge Semin .peer_mw_get_addr = idt_ntb_peer_mw_get_addr, 2253bf2a952dSSerge Semin .peer_mw_set_trans = idt_ntb_peer_mw_set_trans, 2254bf2a952dSSerge Semin .peer_mw_clear_trans = idt_ntb_peer_mw_clear_trans, 2255bf2a952dSSerge Semin .db_valid_mask = idt_ntb_db_valid_mask, 2256bf2a952dSSerge Semin .db_read = idt_ntb_db_read, 2257bf2a952dSSerge Semin .db_clear = idt_ntb_db_clear, 2258bf2a952dSSerge Semin .db_read_mask = idt_ntb_db_read_mask, 2259bf2a952dSSerge Semin .db_set_mask = idt_ntb_db_set_mask, 2260bf2a952dSSerge Semin .db_clear_mask = idt_ntb_db_clear_mask, 2261bf2a952dSSerge Semin .peer_db_set = idt_ntb_peer_db_set, 2262bf2a952dSSerge Semin .msg_count = idt_ntb_msg_count, 2263bf2a952dSSerge Semin .msg_inbits = idt_ntb_msg_inbits, 2264bf2a952dSSerge Semin .msg_outbits = idt_ntb_msg_outbits, 2265bf2a952dSSerge Semin .msg_read_sts = idt_ntb_msg_read_sts, 2266bf2a952dSSerge Semin .msg_clear_sts = idt_ntb_msg_clear_sts, 2267bf2a952dSSerge Semin .msg_set_mask = idt_ntb_msg_set_mask, 2268bf2a952dSSerge Semin .msg_clear_mask = idt_ntb_msg_clear_mask, 2269bf2a952dSSerge Semin .msg_read = idt_ntb_msg_read, 2270b87ab219SSerge Semin .peer_msg_write = idt_ntb_peer_msg_write 2271bf2a952dSSerge Semin }; 2272bf2a952dSSerge Semin 2273bf2a952dSSerge Semin /* 2274bf2a952dSSerge Semin * idt_register_device() - register IDT NTB device 2275bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 2276bf2a952dSSerge Semin * 2277bf2a952dSSerge Semin * Return: zero on success, otherwise a negative error number. 2278bf2a952dSSerge Semin */ 2279bf2a952dSSerge Semin static int idt_register_device(struct idt_ntb_dev *ndev) 2280bf2a952dSSerge Semin { 2281bf2a952dSSerge Semin int ret; 2282bf2a952dSSerge Semin 2283bf2a952dSSerge Semin /* Initialize the rest of NTB device structure and register it */ 2284bf2a952dSSerge Semin ndev->ntb.ops = &idt_ntb_ops; 22856952c6deSSerge Semin ndev->ntb.topo = NTB_TOPO_SWITCH; 2286bf2a952dSSerge Semin 2287bf2a952dSSerge Semin ret = ntb_register_device(&ndev->ntb); 2288bf2a952dSSerge Semin if (ret != 0) { 2289bf2a952dSSerge Semin dev_err(&ndev->ntb.pdev->dev, "Failed to register NTB device"); 2290bf2a952dSSerge Semin return ret; 2291bf2a952dSSerge Semin } 2292bf2a952dSSerge Semin 2293bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "NTB device successfully registered"); 2294bf2a952dSSerge Semin 2295bf2a952dSSerge Semin return 0; 2296bf2a952dSSerge Semin } 2297bf2a952dSSerge Semin 2298bf2a952dSSerge Semin /* 2299bf2a952dSSerge Semin * idt_unregister_device() - unregister IDT NTB device 2300bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 2301bf2a952dSSerge Semin */ 2302bf2a952dSSerge Semin static void idt_unregister_device(struct idt_ntb_dev *ndev) 2303bf2a952dSSerge Semin { 2304bf2a952dSSerge Semin /* Just unregister the NTB device */ 2305bf2a952dSSerge Semin ntb_unregister_device(&ndev->ntb); 2306bf2a952dSSerge Semin 2307bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "NTB device unregistered"); 2308bf2a952dSSerge Semin } 2309bf2a952dSSerge Semin 2310bf2a952dSSerge Semin /*============================================================================= 2311bf2a952dSSerge Semin * 10. DebugFS node initialization 2312bf2a952dSSerge Semin *============================================================================= 2313bf2a952dSSerge Semin */ 2314bf2a952dSSerge Semin 2315bf2a952dSSerge Semin static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf, 2316bf2a952dSSerge Semin size_t count, loff_t *offp); 2317bf2a952dSSerge Semin 2318bf2a952dSSerge Semin /* 2319bf2a952dSSerge Semin * Driver DebugFS info file operations 2320bf2a952dSSerge Semin */ 2321bf2a952dSSerge Semin static const struct file_operations idt_dbgfs_info_ops = { 2322bf2a952dSSerge Semin .owner = THIS_MODULE, 2323bf2a952dSSerge Semin .open = simple_open, 2324bf2a952dSSerge Semin .read = idt_dbgfs_info_read 2325bf2a952dSSerge Semin }; 2326bf2a952dSSerge Semin 2327bf2a952dSSerge Semin /* 2328bf2a952dSSerge Semin * idt_dbgfs_info_read() - DebugFS read info node callback 2329bf2a952dSSerge Semin * @file: File node descriptor. 2330bf2a952dSSerge Semin * @ubuf: User-space buffer to put data to 2331bf2a952dSSerge Semin * @count: Size of the buffer 2332bf2a952dSSerge Semin * @offp: Offset within the buffer 2333bf2a952dSSerge Semin */ 2334bf2a952dSSerge Semin static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf, 2335bf2a952dSSerge Semin size_t count, loff_t *offp) 2336bf2a952dSSerge Semin { 2337bf2a952dSSerge Semin struct idt_ntb_dev *ndev = filp->private_data; 233840070408SSerge Semin unsigned char idx, pidx, cnt; 233940070408SSerge Semin unsigned long irqflags, mdeg; 2340bf2a952dSSerge Semin ssize_t ret = 0, off = 0; 2341bf2a952dSSerge Semin enum ntb_speed speed; 2342bf2a952dSSerge Semin enum ntb_width width; 2343bf2a952dSSerge Semin char *strbuf; 2344bf2a952dSSerge Semin size_t size; 2345bf2a952dSSerge Semin u32 data; 2346bf2a952dSSerge Semin 2347bf2a952dSSerge Semin /* Lets limit the buffer size the way the Intel/AMD drivers do */ 2348bf2a952dSSerge Semin size = min_t(size_t, count, 0x1000U); 2349bf2a952dSSerge Semin 2350bf2a952dSSerge Semin /* Allocate the memory for the buffer */ 2351bf2a952dSSerge Semin strbuf = kmalloc(size, GFP_KERNEL); 2352bf2a952dSSerge Semin if (strbuf == NULL) 2353bf2a952dSSerge Semin return -ENOMEM; 2354bf2a952dSSerge Semin 2355bf2a952dSSerge Semin /* Put the data into the string buffer */ 2356bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2357bf2a952dSSerge Semin "\n\t\tIDT NTB device Information:\n\n"); 2358bf2a952dSSerge Semin 2359bf2a952dSSerge Semin /* General local device configurations */ 2360bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2361bf2a952dSSerge Semin "Local Port %hhu, Partition %hhu\n", ndev->port, ndev->part); 2362bf2a952dSSerge Semin 2363bf2a952dSSerge Semin /* Peer ports information */ 2364bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "Peers:\n"); 2365bf2a952dSSerge Semin for (idx = 0; idx < ndev->peer_cnt; idx++) { 2366bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2367bf2a952dSSerge Semin "\t%hhu. Port %hhu, Partition %hhu\n", 2368bf2a952dSSerge Semin idx, ndev->peers[idx].port, ndev->peers[idx].part); 2369bf2a952dSSerge Semin } 2370bf2a952dSSerge Semin 2371bf2a952dSSerge Semin /* Links status */ 2372bf2a952dSSerge Semin data = idt_ntb_link_is_up(&ndev->ntb, &speed, &width); 2373bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2374bf2a952dSSerge Semin "NTB link status\t- 0x%08x, ", data); 2375bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "PCIe Gen %d x%d lanes\n", 2376bf2a952dSSerge Semin speed, width); 2377bf2a952dSSerge Semin 2378bf2a952dSSerge Semin /* Mapping table entries */ 2379bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "NTB Mapping Table:\n"); 2380bf2a952dSSerge Semin for (idx = 0; idx < IDT_MTBL_ENTRY_CNT; idx++) { 2381bf2a952dSSerge Semin spin_lock_irqsave(&ndev->mtbl_lock, irqflags); 2382bf2a952dSSerge Semin idt_nt_write(ndev, IDT_NT_NTMTBLADDR, idx); 2383bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA); 2384bf2a952dSSerge Semin spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags); 2385bf2a952dSSerge Semin 2386bf2a952dSSerge Semin /* Print valid entries only */ 2387bf2a952dSSerge Semin if (data & IDT_NTMTBLDATA_VALID) { 2388bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2389bf2a952dSSerge Semin "\t%hhu. Partition %d, Requester ID 0x%04x\n", 2390bf2a952dSSerge Semin idx, GET_FIELD(NTMTBLDATA_PART, data), 2391bf2a952dSSerge Semin GET_FIELD(NTMTBLDATA_REQID, data)); 2392bf2a952dSSerge Semin } 2393bf2a952dSSerge Semin } 2394bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "\n"); 2395bf2a952dSSerge Semin 2396bf2a952dSSerge Semin /* Outbound memory windows information */ 2397bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2398bf2a952dSSerge Semin "Outbound Memory Windows:\n"); 2399bf2a952dSSerge Semin for (idx = 0; idx < ndev->mw_cnt; idx += cnt) { 2400bf2a952dSSerge Semin data = ndev->mws[idx].type; 2401bf2a952dSSerge Semin cnt = idt_get_mw_count(data); 2402bf2a952dSSerge Semin 2403bf2a952dSSerge Semin /* Print Memory Window information */ 2404bf2a952dSSerge Semin if (data == IDT_MW_DIR) 2405bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2406bf2a952dSSerge Semin "\t%hhu.\t", idx); 2407bf2a952dSSerge Semin else 2408bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2409*a44252d5SJustin Stitt "\t%hhu-%d.\t", idx, idx + cnt - 1); 2410bf2a952dSSerge Semin 2411bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "%s BAR%hhu, ", 2412bf2a952dSSerge Semin idt_get_mw_name(data), ndev->mws[idx].bar); 2413bf2a952dSSerge Semin 2414bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2415bf2a952dSSerge Semin "Address align 0x%08llx, ", ndev->mws[idx].addr_align); 2416bf2a952dSSerge Semin 2417bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2418bf2a952dSSerge Semin "Size align 0x%08llx, Size max %llu\n", 2419bf2a952dSSerge Semin ndev->mws[idx].size_align, ndev->mws[idx].size_max); 2420bf2a952dSSerge Semin } 2421bf2a952dSSerge Semin 2422bf2a952dSSerge Semin /* Inbound memory windows information */ 2423bf2a952dSSerge Semin for (pidx = 0; pidx < ndev->peer_cnt; pidx++) { 2424bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2425bf2a952dSSerge Semin "Inbound Memory Windows for peer %hhu (Port %hhu):\n", 2426bf2a952dSSerge Semin pidx, ndev->peers[pidx].port); 2427bf2a952dSSerge Semin 2428bf2a952dSSerge Semin /* Print Memory Windows information */ 2429bf2a952dSSerge Semin for (idx = 0; idx < ndev->peers[pidx].mw_cnt; idx += cnt) { 2430bf2a952dSSerge Semin data = ndev->peers[pidx].mws[idx].type; 2431bf2a952dSSerge Semin cnt = idt_get_mw_count(data); 2432bf2a952dSSerge Semin 2433bf2a952dSSerge Semin if (data == IDT_MW_DIR) 2434bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2435bf2a952dSSerge Semin "\t%hhu.\t", idx); 2436bf2a952dSSerge Semin else 2437bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2438*a44252d5SJustin Stitt "\t%hhu-%d.\t", idx, idx + cnt - 1); 2439bf2a952dSSerge Semin 2440bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2441bf2a952dSSerge Semin "%s BAR%hhu, ", idt_get_mw_name(data), 2442bf2a952dSSerge Semin ndev->peers[pidx].mws[idx].bar); 2443bf2a952dSSerge Semin 2444bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2445bf2a952dSSerge Semin "Address align 0x%08llx, ", 2446bf2a952dSSerge Semin ndev->peers[pidx].mws[idx].addr_align); 2447bf2a952dSSerge Semin 2448bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2449bf2a952dSSerge Semin "Size align 0x%08llx, Size max %llu\n", 2450bf2a952dSSerge Semin ndev->peers[pidx].mws[idx].size_align, 2451bf2a952dSSerge Semin ndev->peers[pidx].mws[idx].size_max); 2452bf2a952dSSerge Semin } 2453bf2a952dSSerge Semin } 2454bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "\n"); 2455bf2a952dSSerge Semin 2456bf2a952dSSerge Semin /* Doorbell information */ 2457bf2a952dSSerge Semin data = idt_sw_read(ndev, IDT_SW_GDBELLSTS); 2458bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2459bf2a952dSSerge Semin "Global Doorbell state\t- 0x%08x\n", data); 2460bf2a952dSSerge Semin data = idt_ntb_db_read(&ndev->ntb); 2461bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2462bf2a952dSSerge Semin "Local Doorbell state\t- 0x%08x\n", data); 2463bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_INDBELLMSK); 2464bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2465bf2a952dSSerge Semin "Local Doorbell mask\t- 0x%08x\n", data); 2466bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "\n"); 2467bf2a952dSSerge Semin 2468bf2a952dSSerge Semin /* Messaging information */ 2469bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2470bf2a952dSSerge Semin "Message event valid\t- 0x%08x\n", IDT_MSG_MASK); 2471bf2a952dSSerge Semin data = idt_ntb_msg_read_sts(&ndev->ntb); 2472bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2473bf2a952dSSerge Semin "Message event status\t- 0x%08x\n", data); 2474bf2a952dSSerge Semin data = idt_nt_read(ndev, IDT_NT_MSGSTSMSK); 2475bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2476bf2a952dSSerge Semin "Message event mask\t- 0x%08x\n", data); 2477bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2478bf2a952dSSerge Semin "Message data:\n"); 2479bf2a952dSSerge Semin for (idx = 0; idx < IDT_MSG_CNT; idx++) { 2480bf2a952dSSerge Semin int src; 2481b87ab219SSerge Semin data = idt_ntb_msg_read(&ndev->ntb, &src, idx); 2482bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 2483*a44252d5SJustin Stitt "\t%hhu. 0x%08x from peer %d (Port %hhu)\n", 2484bf2a952dSSerge Semin idx, data, src, ndev->peers[src].port); 2485bf2a952dSSerge Semin } 2486bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, "\n"); 2487bf2a952dSSerge Semin 2488bf2a952dSSerge Semin /* Current temperature */ 248940070408SSerge Semin idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg); 2490bf2a952dSSerge Semin off += scnprintf(strbuf + off, size - off, 249140070408SSerge Semin "Switch temperature\t\t- %hhd.%hhuC\n", 249240070408SSerge Semin idt_get_deg(mdeg), idt_get_deg_frac(mdeg)); 2493bf2a952dSSerge Semin 2494bf2a952dSSerge Semin /* Copy the buffer to the User Space */ 2495bf2a952dSSerge Semin ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off); 2496bf2a952dSSerge Semin kfree(strbuf); 2497bf2a952dSSerge Semin 2498bf2a952dSSerge Semin return ret; 2499bf2a952dSSerge Semin } 2500bf2a952dSSerge Semin 2501bf2a952dSSerge Semin /* 2502bf2a952dSSerge Semin * idt_init_dbgfs() - initialize DebugFS node 2503bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 2504bf2a952dSSerge Semin * 2505bf2a952dSSerge Semin * Return: zero on success, otherwise a negative error number. 2506bf2a952dSSerge Semin */ 2507bf2a952dSSerge Semin static int idt_init_dbgfs(struct idt_ntb_dev *ndev) 2508bf2a952dSSerge Semin { 2509bf2a952dSSerge Semin char devname[64]; 2510bf2a952dSSerge Semin 2511bf2a952dSSerge Semin /* If the top directory is not created then do nothing */ 2512bf2a952dSSerge Semin if (IS_ERR_OR_NULL(dbgfs_topdir)) { 2513bf2a952dSSerge Semin dev_info(&ndev->ntb.pdev->dev, "Top DebugFS directory absent"); 251491b8246dSWang Qing return PTR_ERR_OR_ZERO(dbgfs_topdir); 2515bf2a952dSSerge Semin } 2516bf2a952dSSerge Semin 2517bf2a952dSSerge Semin /* Create the info file node */ 2518bf2a952dSSerge Semin snprintf(devname, 64, "info:%s", pci_name(ndev->ntb.pdev)); 2519bf2a952dSSerge Semin ndev->dbgfs_info = debugfs_create_file(devname, 0400, dbgfs_topdir, 2520bf2a952dSSerge Semin ndev, &idt_dbgfs_info_ops); 2521bf2a952dSSerge Semin if (IS_ERR(ndev->dbgfs_info)) { 2522bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "Failed to create DebugFS node"); 2523bf2a952dSSerge Semin return PTR_ERR(ndev->dbgfs_info); 2524bf2a952dSSerge Semin } 2525bf2a952dSSerge Semin 2526bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "NTB device DebugFS node created"); 2527bf2a952dSSerge Semin 2528bf2a952dSSerge Semin return 0; 2529bf2a952dSSerge Semin } 2530bf2a952dSSerge Semin 2531bf2a952dSSerge Semin /* 2532bf2a952dSSerge Semin * idt_deinit_dbgfs() - deinitialize DebugFS node 2533bf2a952dSSerge Semin * @ndev: IDT NTB hardware driver descriptor 2534bf2a952dSSerge Semin * 2535bf2a952dSSerge Semin * Just discard the info node from DebugFS 2536bf2a952dSSerge Semin */ 2537bf2a952dSSerge Semin static void idt_deinit_dbgfs(struct idt_ntb_dev *ndev) 2538bf2a952dSSerge Semin { 2539bf2a952dSSerge Semin debugfs_remove(ndev->dbgfs_info); 2540bf2a952dSSerge Semin 2541bf2a952dSSerge Semin dev_dbg(&ndev->ntb.pdev->dev, "NTB device DebugFS node discarded"); 2542bf2a952dSSerge Semin } 2543bf2a952dSSerge Semin 2544bf2a952dSSerge Semin /*============================================================================= 2545bf2a952dSSerge Semin * 11. Basic PCIe device initialization 2546bf2a952dSSerge Semin *============================================================================= 2547bf2a952dSSerge Semin */ 2548bf2a952dSSerge Semin 2549bf2a952dSSerge Semin /* 2550bf2a952dSSerge Semin * idt_check_setup() - Check whether the IDT PCIe-swtich is properly 2551bf2a952dSSerge Semin * pre-initialized 2552bf2a952dSSerge Semin * @pdev: Pointer to the PCI device descriptor 2553bf2a952dSSerge Semin * 2554bf2a952dSSerge Semin * Return: zero on success, otherwise a negative error number. 2555bf2a952dSSerge Semin */ 2556bf2a952dSSerge Semin static int idt_check_setup(struct pci_dev *pdev) 2557bf2a952dSSerge Semin { 2558bf2a952dSSerge Semin u32 data; 2559bf2a952dSSerge Semin int ret; 2560bf2a952dSSerge Semin 2561bf2a952dSSerge Semin /* Read the BARSETUP0 */ 2562bf2a952dSSerge Semin ret = pci_read_config_dword(pdev, IDT_NT_BARSETUP0, &data); 2563bf2a952dSSerge Semin if (ret != 0) { 2564bf2a952dSSerge Semin dev_err(&pdev->dev, 2565bf2a952dSSerge Semin "Failed to read BARSETUP0 config register"); 2566bf2a952dSSerge Semin return ret; 2567bf2a952dSSerge Semin } 2568bf2a952dSSerge Semin 2569bf2a952dSSerge Semin /* Check whether the BAR0 register is enabled to be of config space */ 2570bf2a952dSSerge Semin if (!(data & IDT_BARSETUP_EN) || !(data & IDT_BARSETUP_MODE_CFG)) { 2571bf2a952dSSerge Semin dev_err(&pdev->dev, "BAR0 doesn't map config space"); 2572bf2a952dSSerge Semin return -EINVAL; 2573bf2a952dSSerge Semin } 2574bf2a952dSSerge Semin 2575bf2a952dSSerge Semin /* Configuration space BAR0 must have certain size */ 2576bf2a952dSSerge Semin if ((data & IDT_BARSETUP_SIZE_MASK) != IDT_BARSETUP_SIZE_CFG) { 2577bf2a952dSSerge Semin dev_err(&pdev->dev, "Invalid size of config space"); 2578bf2a952dSSerge Semin return -EINVAL; 2579bf2a952dSSerge Semin } 2580bf2a952dSSerge Semin 2581bf2a952dSSerge Semin dev_dbg(&pdev->dev, "NTB device pre-initialized correctly"); 2582bf2a952dSSerge Semin 2583bf2a952dSSerge Semin return 0; 2584bf2a952dSSerge Semin } 2585bf2a952dSSerge Semin 2586bf2a952dSSerge Semin /* 2587bf2a952dSSerge Semin * Create the IDT PCIe-switch driver descriptor 2588bf2a952dSSerge Semin * @pdev: Pointer to the PCI device descriptor 2589bf2a952dSSerge Semin * @id: IDT PCIe-device configuration 2590bf2a952dSSerge Semin * 2591bf2a952dSSerge Semin * It just allocates a memory for IDT PCIe-switch device structure and 2592bf2a952dSSerge Semin * initializes some commonly used fields. 2593bf2a952dSSerge Semin * 2594bf2a952dSSerge Semin * No need of release method, since managed device resource is used for 2595bf2a952dSSerge Semin * memory allocation. 2596bf2a952dSSerge Semin * 2597bf2a952dSSerge Semin * Return: pointer to the descriptor, otherwise a negative error number. 2598bf2a952dSSerge Semin */ 2599bf2a952dSSerge Semin static struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev, 2600bf2a952dSSerge Semin const struct pci_device_id *id) 2601bf2a952dSSerge Semin { 2602bf2a952dSSerge Semin struct idt_ntb_dev *ndev; 2603bf2a952dSSerge Semin 2604bf2a952dSSerge Semin /* Allocate memory for the IDT PCIe-device descriptor */ 2605bf2a952dSSerge Semin ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL); 26061b761982SGustavo A. R. Silva if (!ndev) { 2607bf2a952dSSerge Semin dev_err(&pdev->dev, "Memory allocation failed for descriptor"); 2608bf2a952dSSerge Semin return ERR_PTR(-ENOMEM); 2609bf2a952dSSerge Semin } 2610bf2a952dSSerge Semin 2611bf2a952dSSerge Semin /* Save the IDT PCIe-switch ports configuration */ 2612bf2a952dSSerge Semin ndev->swcfg = (struct idt_89hpes_cfg *)id->driver_data; 2613bf2a952dSSerge Semin /* Save the PCI-device pointer inside the NTB device structure */ 2614bf2a952dSSerge Semin ndev->ntb.pdev = pdev; 2615bf2a952dSSerge Semin 2616bf2a952dSSerge Semin /* Initialize spin locker of Doorbell, Message and GASA registers */ 2617bf2a952dSSerge Semin spin_lock_init(&ndev->db_mask_lock); 2618bf2a952dSSerge Semin spin_lock_init(&ndev->msg_mask_lock); 2619bf2a952dSSerge Semin spin_lock_init(&ndev->gasa_lock); 2620bf2a952dSSerge Semin 2621bf2a952dSSerge Semin dev_info(&pdev->dev, "IDT %s discovered", ndev->swcfg->name); 2622bf2a952dSSerge Semin 2623bf2a952dSSerge Semin dev_dbg(&pdev->dev, "NTB device descriptor created"); 2624bf2a952dSSerge Semin 2625bf2a952dSSerge Semin return ndev; 2626bf2a952dSSerge Semin } 2627bf2a952dSSerge Semin 2628bf2a952dSSerge Semin /* 2629bf2a952dSSerge Semin * idt_init_pci() - initialize the basic PCI-related subsystem 2630bf2a952dSSerge Semin * @ndev: Pointer to the IDT PCIe-switch driver descriptor 2631bf2a952dSSerge Semin * 2632bf2a952dSSerge Semin * Managed device resources will be freed automatically in case of failure or 2633bf2a952dSSerge Semin * driver detachment. 2634bf2a952dSSerge Semin * 2635bf2a952dSSerge Semin * Return: zero on success, otherwise negative error number. 2636bf2a952dSSerge Semin */ 2637bf2a952dSSerge Semin static int idt_init_pci(struct idt_ntb_dev *ndev) 2638bf2a952dSSerge Semin { 2639bf2a952dSSerge Semin struct pci_dev *pdev = ndev->ntb.pdev; 2640bf2a952dSSerge Semin int ret; 2641bf2a952dSSerge Semin 2642417cf39cSSerge Semin /* Initialize the bit mask of PCI/NTB DMA */ 264338de3affSChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 2644bf2a952dSSerge Semin if (ret != 0) { 264538de3affSChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 2646bf2a952dSSerge Semin if (ret != 0) { 2647bf2a952dSSerge Semin dev_err(&pdev->dev, "Failed to set DMA bit mask\n"); 2648bf2a952dSSerge Semin return ret; 2649bf2a952dSSerge Semin } 2650bf2a952dSSerge Semin dev_warn(&pdev->dev, "Cannot set DMA highmem bit mask\n"); 2651bf2a952dSSerge Semin } 2652bf2a952dSSerge Semin 2653bf2a952dSSerge Semin /* 2654bf2a952dSSerge Semin * Enable the device advanced error reporting. It's not critical to 2655bf2a952dSSerge Semin * have AER disabled in the kernel. 2656bf2a952dSSerge Semin */ 2657bf2a952dSSerge Semin ret = pci_enable_pcie_error_reporting(pdev); 2658bf2a952dSSerge Semin if (ret != 0) 2659bf2a952dSSerge Semin dev_warn(&pdev->dev, "PCIe AER capability disabled\n"); 2660894020fdSKuppuswamy Sathyanarayanan else /* Cleanup nonfatal error status before getting to init */ 2661894020fdSKuppuswamy Sathyanarayanan pci_aer_clear_nonfatal_status(pdev); 2662bf2a952dSSerge Semin 2663bf2a952dSSerge Semin /* First enable the PCI device */ 2664bf2a952dSSerge Semin ret = pcim_enable_device(pdev); 2665bf2a952dSSerge Semin if (ret != 0) { 2666bf2a952dSSerge Semin dev_err(&pdev->dev, "Failed to enable PCIe device\n"); 2667bf2a952dSSerge Semin goto err_disable_aer; 2668bf2a952dSSerge Semin } 2669bf2a952dSSerge Semin 2670bf2a952dSSerge Semin /* 2671bf2a952dSSerge Semin * Enable the bus mastering, which effectively enables MSI IRQs and 2672bf2a952dSSerge Semin * Request TLPs translation 2673bf2a952dSSerge Semin */ 2674bf2a952dSSerge Semin pci_set_master(pdev); 2675bf2a952dSSerge Semin 2676bf2a952dSSerge Semin /* Request all BARs resources and map BAR0 only */ 2677bf2a952dSSerge Semin ret = pcim_iomap_regions_request_all(pdev, 1, NTB_NAME); 2678bf2a952dSSerge Semin if (ret != 0) { 2679bf2a952dSSerge Semin dev_err(&pdev->dev, "Failed to request resources\n"); 2680bf2a952dSSerge Semin goto err_clear_master; 2681bf2a952dSSerge Semin } 2682bf2a952dSSerge Semin 2683bf2a952dSSerge Semin /* Retrieve virtual address of BAR0 - PCI configuration space */ 2684bf2a952dSSerge Semin ndev->cfgspc = pcim_iomap_table(pdev)[0]; 2685bf2a952dSSerge Semin 2686bf2a952dSSerge Semin /* Put the IDT driver data pointer to the PCI-device private pointer */ 2687bf2a952dSSerge Semin pci_set_drvdata(pdev, ndev); 2688bf2a952dSSerge Semin 2689bf2a952dSSerge Semin dev_dbg(&pdev->dev, "NT-function PCIe interface initialized"); 2690bf2a952dSSerge Semin 2691bf2a952dSSerge Semin return 0; 2692bf2a952dSSerge Semin 2693bf2a952dSSerge Semin err_clear_master: 2694bf2a952dSSerge Semin pci_clear_master(pdev); 2695bf2a952dSSerge Semin err_disable_aer: 2696bf2a952dSSerge Semin (void)pci_disable_pcie_error_reporting(pdev); 2697bf2a952dSSerge Semin 2698bf2a952dSSerge Semin return ret; 2699bf2a952dSSerge Semin } 2700bf2a952dSSerge Semin 2701bf2a952dSSerge Semin /* 2702bf2a952dSSerge Semin * idt_deinit_pci() - deinitialize the basic PCI-related subsystem 2703bf2a952dSSerge Semin * @ndev: Pointer to the IDT PCIe-switch driver descriptor 2704bf2a952dSSerge Semin * 2705bf2a952dSSerge Semin * Managed resources will be freed on the driver detachment 2706bf2a952dSSerge Semin */ 2707bf2a952dSSerge Semin static void idt_deinit_pci(struct idt_ntb_dev *ndev) 2708bf2a952dSSerge Semin { 2709bf2a952dSSerge Semin struct pci_dev *pdev = ndev->ntb.pdev; 2710bf2a952dSSerge Semin 2711bf2a952dSSerge Semin /* Clean up the PCI-device private data pointer */ 2712bf2a952dSSerge Semin pci_set_drvdata(pdev, NULL); 2713bf2a952dSSerge Semin 2714bf2a952dSSerge Semin /* Clear the bus master disabling the Request TLPs translation */ 2715bf2a952dSSerge Semin pci_clear_master(pdev); 2716bf2a952dSSerge Semin 2717bf2a952dSSerge Semin /* Disable the AER capability */ 2718bf2a952dSSerge Semin (void)pci_disable_pcie_error_reporting(pdev); 2719bf2a952dSSerge Semin 2720bf2a952dSSerge Semin dev_dbg(&pdev->dev, "NT-function PCIe interface cleared"); 2721bf2a952dSSerge Semin } 2722bf2a952dSSerge Semin 2723bf2a952dSSerge Semin /*=========================================================================== 2724bf2a952dSSerge Semin * 12. PCI bus callback functions 2725bf2a952dSSerge Semin *=========================================================================== 2726bf2a952dSSerge Semin */ 2727bf2a952dSSerge Semin 2728bf2a952dSSerge Semin /* 2729bf2a952dSSerge Semin * idt_pci_probe() - PCI device probe callback 2730bf2a952dSSerge Semin * @pdev: Pointer to PCI device structure 2731bf2a952dSSerge Semin * @id: PCIe device custom descriptor 2732bf2a952dSSerge Semin * 2733bf2a952dSSerge Semin * Return: zero on success, otherwise negative error number 2734bf2a952dSSerge Semin */ 2735bf2a952dSSerge Semin static int idt_pci_probe(struct pci_dev *pdev, 2736bf2a952dSSerge Semin const struct pci_device_id *id) 2737bf2a952dSSerge Semin { 2738bf2a952dSSerge Semin struct idt_ntb_dev *ndev; 2739bf2a952dSSerge Semin int ret; 2740bf2a952dSSerge Semin 2741bf2a952dSSerge Semin /* Check whether IDT PCIe-switch is properly pre-initialized */ 2742bf2a952dSSerge Semin ret = idt_check_setup(pdev); 2743bf2a952dSSerge Semin if (ret != 0) 2744bf2a952dSSerge Semin return ret; 2745bf2a952dSSerge Semin 2746bf2a952dSSerge Semin /* Allocate the memory for IDT NTB device data */ 2747bf2a952dSSerge Semin ndev = idt_create_dev(pdev, id); 274891b8246dSWang Qing if (IS_ERR(ndev)) 2749bf2a952dSSerge Semin return PTR_ERR(ndev); 2750bf2a952dSSerge Semin 2751bf2a952dSSerge Semin /* Initialize the basic PCI subsystem of the device */ 2752bf2a952dSSerge Semin ret = idt_init_pci(ndev); 2753bf2a952dSSerge Semin if (ret != 0) 2754bf2a952dSSerge Semin return ret; 2755bf2a952dSSerge Semin 2756bf2a952dSSerge Semin /* Scan ports of the IDT PCIe-switch */ 2757bf2a952dSSerge Semin (void)idt_scan_ports(ndev); 2758bf2a952dSSerge Semin 2759bf2a952dSSerge Semin /* Initialize NTB link events subsystem */ 2760bf2a952dSSerge Semin idt_init_link(ndev); 2761bf2a952dSSerge Semin 2762bf2a952dSSerge Semin /* Initialize MWs subsystem */ 2763bf2a952dSSerge Semin ret = idt_init_mws(ndev); 2764bf2a952dSSerge Semin if (ret != 0) 2765bf2a952dSSerge Semin goto err_deinit_link; 2766bf2a952dSSerge Semin 2767bf2a952dSSerge Semin /* Initialize Messaging subsystem */ 2768bf2a952dSSerge Semin idt_init_msg(ndev); 2769bf2a952dSSerge Semin 2770aed1b7b3SSerge Semin /* Initialize hwmon interface */ 2771aed1b7b3SSerge Semin idt_init_temp(ndev); 2772aed1b7b3SSerge Semin 2773bf2a952dSSerge Semin /* Initialize IDT interrupts handler */ 2774bf2a952dSSerge Semin ret = idt_init_isr(ndev); 2775bf2a952dSSerge Semin if (ret != 0) 2776bf2a952dSSerge Semin goto err_deinit_link; 2777bf2a952dSSerge Semin 2778bf2a952dSSerge Semin /* Register IDT NTB devices on the NTB bus */ 2779bf2a952dSSerge Semin ret = idt_register_device(ndev); 2780bf2a952dSSerge Semin if (ret != 0) 2781bf2a952dSSerge Semin goto err_deinit_isr; 2782bf2a952dSSerge Semin 2783bf2a952dSSerge Semin /* Initialize DebugFS info node */ 2784bf2a952dSSerge Semin (void)idt_init_dbgfs(ndev); 2785bf2a952dSSerge Semin 2786bf2a952dSSerge Semin /* IDT PCIe-switch NTB driver is finally initialized */ 2787bf2a952dSSerge Semin dev_info(&pdev->dev, "IDT NTB device is ready"); 2788bf2a952dSSerge Semin 2789bf2a952dSSerge Semin /* May the force be with us... */ 2790bf2a952dSSerge Semin return 0; 2791bf2a952dSSerge Semin 2792bf2a952dSSerge Semin err_deinit_isr: 2793bf2a952dSSerge Semin idt_deinit_isr(ndev); 2794bf2a952dSSerge Semin err_deinit_link: 2795bf2a952dSSerge Semin idt_deinit_link(ndev); 2796bf2a952dSSerge Semin idt_deinit_pci(ndev); 2797bf2a952dSSerge Semin 2798bf2a952dSSerge Semin return ret; 2799bf2a952dSSerge Semin } 2800bf2a952dSSerge Semin 2801bf2a952dSSerge Semin /* 2802bf2a952dSSerge Semin * idt_pci_probe() - PCI device remove callback 2803bf2a952dSSerge Semin * @pdev: Pointer to PCI device structure 2804bf2a952dSSerge Semin */ 2805bf2a952dSSerge Semin static void idt_pci_remove(struct pci_dev *pdev) 2806bf2a952dSSerge Semin { 2807bf2a952dSSerge Semin struct idt_ntb_dev *ndev = pci_get_drvdata(pdev); 2808bf2a952dSSerge Semin 2809bf2a952dSSerge Semin /* Deinit the DebugFS node */ 2810bf2a952dSSerge Semin idt_deinit_dbgfs(ndev); 2811bf2a952dSSerge Semin 2812bf2a952dSSerge Semin /* Unregister NTB device */ 2813bf2a952dSSerge Semin idt_unregister_device(ndev); 2814bf2a952dSSerge Semin 2815bf2a952dSSerge Semin /* Stop the interrupts handling */ 2816bf2a952dSSerge Semin idt_deinit_isr(ndev); 2817bf2a952dSSerge Semin 2818bf2a952dSSerge Semin /* Deinitialize link event subsystem */ 2819bf2a952dSSerge Semin idt_deinit_link(ndev); 2820bf2a952dSSerge Semin 2821bf2a952dSSerge Semin /* Deinit basic PCI subsystem */ 2822bf2a952dSSerge Semin idt_deinit_pci(ndev); 2823bf2a952dSSerge Semin 2824bf2a952dSSerge Semin /* IDT PCIe-switch NTB driver is finally initialized */ 2825bf2a952dSSerge Semin dev_info(&pdev->dev, "IDT NTB device is removed"); 2826bf2a952dSSerge Semin 2827bf2a952dSSerge Semin /* Sayonara... */ 2828bf2a952dSSerge Semin } 2829bf2a952dSSerge Semin 2830bf2a952dSSerge Semin /* 2831bf2a952dSSerge Semin * IDT PCIe-switch models ports configuration structures 2832bf2a952dSSerge Semin */ 28333a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes24nt6ag2_config = { 2834bf2a952dSSerge Semin .name = "89HPES24NT6AG2", 2835bf2a952dSSerge Semin .port_cnt = 6, .ports = {0, 2, 4, 6, 8, 12} 2836bf2a952dSSerge Semin }; 28373a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes32nt8ag2_config = { 2838bf2a952dSSerge Semin .name = "89HPES32NT8AG2", 2839bf2a952dSSerge Semin .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20} 2840bf2a952dSSerge Semin }; 28413a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes32nt8bg2_config = { 2842bf2a952dSSerge Semin .name = "89HPES32NT8BG2", 2843bf2a952dSSerge Semin .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20} 2844bf2a952dSSerge Semin }; 28453a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes12nt12g2_config = { 2846bf2a952dSSerge Semin .name = "89HPES12NT12G2", 2847bf2a952dSSerge Semin .port_cnt = 3, .ports = {0, 8, 16} 2848bf2a952dSSerge Semin }; 28493a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes16nt16g2_config = { 2850bf2a952dSSerge Semin .name = "89HPES16NT16G2", 2851bf2a952dSSerge Semin .port_cnt = 4, .ports = {0, 8, 12, 16} 2852bf2a952dSSerge Semin }; 28533a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes24nt24g2_config = { 2854bf2a952dSSerge Semin .name = "89HPES24NT24G2", 2855bf2a952dSSerge Semin .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20} 2856bf2a952dSSerge Semin }; 28573a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes32nt24ag2_config = { 2858bf2a952dSSerge Semin .name = "89HPES32NT24AG2", 2859bf2a952dSSerge Semin .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20} 2860bf2a952dSSerge Semin }; 28613a814a04SBhumika Goyal static const struct idt_89hpes_cfg idt_89hpes32nt24bg2_config = { 2862bf2a952dSSerge Semin .name = "89HPES32NT24BG2", 2863bf2a952dSSerge Semin .port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20} 2864bf2a952dSSerge Semin }; 2865bf2a952dSSerge Semin 2866bf2a952dSSerge Semin /* 2867bf2a952dSSerge Semin * PCI-ids table of the supported IDT PCIe-switch devices 2868bf2a952dSSerge Semin */ 2869bf2a952dSSerge Semin static const struct pci_device_id idt_pci_tbl[] = { 2870bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES24NT6AG2, idt_89hpes24nt6ag2_config)}, 2871bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES32NT8AG2, idt_89hpes32nt8ag2_config)}, 2872bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES32NT8BG2, idt_89hpes32nt8bg2_config)}, 2873bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES12NT12G2, idt_89hpes12nt12g2_config)}, 2874bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES16NT16G2, idt_89hpes16nt16g2_config)}, 2875bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES24NT24G2, idt_89hpes24nt24g2_config)}, 2876bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES32NT24AG2, idt_89hpes32nt24ag2_config)}, 2877bf2a952dSSerge Semin {IDT_PCI_DEVICE_IDS(89HPES32NT24BG2, idt_89hpes32nt24bg2_config)}, 2878bf2a952dSSerge Semin {0} 2879bf2a952dSSerge Semin }; 2880bf2a952dSSerge Semin MODULE_DEVICE_TABLE(pci, idt_pci_tbl); 2881bf2a952dSSerge Semin 2882bf2a952dSSerge Semin /* 2883bf2a952dSSerge Semin * IDT PCIe-switch NT-function device driver structure definition 2884bf2a952dSSerge Semin */ 2885bf2a952dSSerge Semin static struct pci_driver idt_pci_driver = { 2886bf2a952dSSerge Semin .name = KBUILD_MODNAME, 2887bf2a952dSSerge Semin .probe = idt_pci_probe, 2888bf2a952dSSerge Semin .remove = idt_pci_remove, 2889bf2a952dSSerge Semin .id_table = idt_pci_tbl, 2890bf2a952dSSerge Semin }; 2891bf2a952dSSerge Semin 2892bf2a952dSSerge Semin static int __init idt_pci_driver_init(void) 2893bf2a952dSSerge Semin { 2894bf2a952dSSerge Semin pr_info("%s %s\n", NTB_DESC, NTB_VER); 2895bf2a952dSSerge Semin 2896bf2a952dSSerge Semin /* Create the top DebugFS directory if the FS is initialized */ 2897bf2a952dSSerge Semin if (debugfs_initialized()) 2898bf2a952dSSerge Semin dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 2899bf2a952dSSerge Semin 2900bf2a952dSSerge Semin /* Register the NTB hardware driver to handle the PCI device */ 2901bf2a952dSSerge Semin return pci_register_driver(&idt_pci_driver); 2902bf2a952dSSerge Semin } 2903bf2a952dSSerge Semin module_init(idt_pci_driver_init); 2904bf2a952dSSerge Semin 2905bf2a952dSSerge Semin static void __exit idt_pci_driver_exit(void) 2906bf2a952dSSerge Semin { 2907bf2a952dSSerge Semin /* Unregister the NTB hardware driver */ 2908bf2a952dSSerge Semin pci_unregister_driver(&idt_pci_driver); 2909bf2a952dSSerge Semin 2910bf2a952dSSerge Semin /* Discard the top DebugFS directory */ 2911bf2a952dSSerge Semin debugfs_remove_recursive(dbgfs_topdir); 2912bf2a952dSSerge Semin } 2913bf2a952dSSerge Semin module_exit(idt_pci_driver_exit); 2914bf2a952dSSerge Semin 2915