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