162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *   This file is provided under a GPLv2 license.  When using or
362306a36Sopenharmony_ci *   redistributing this file, you may do so under that license.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *   GPL LICENSE SUMMARY
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *   Copyright (C) 2016-2018 T-Platforms JSC All Rights Reserved.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *   This program is free software; you can redistribute it and/or modify it
1062306a36Sopenharmony_ci *   under the terms and conditions of the GNU General Public License,
1162306a36Sopenharmony_ci *   version 2, as published by the Free Software Foundation.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *   This program is distributed in the hope that it will be useful, but
1462306a36Sopenharmony_ci *   WITHOUT ANY WARRANTY; without even the implied warranty of
1562306a36Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
1662306a36Sopenharmony_ci *   Public License for more details.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *   You should have received a copy of the GNU General Public License along
1962306a36Sopenharmony_ci *   with this program; if not, one can be found http://www.gnu.org/licenses/.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci *   The full GNU General Public License is included in this distribution in
2262306a36Sopenharmony_ci *   the file called "COPYING".
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2562306a36Sopenharmony_ci *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2662306a36Sopenharmony_ci *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2762306a36Sopenharmony_ci *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2862306a36Sopenharmony_ci *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2962306a36Sopenharmony_ci *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3062306a36Sopenharmony_ci *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3162306a36Sopenharmony_ci *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3262306a36Sopenharmony_ci *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3362306a36Sopenharmony_ci *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3462306a36Sopenharmony_ci *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * IDT PCIe-switch NTB Linux driver
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Contact Information:
3962306a36Sopenharmony_ci * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru>
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <linux/stddef.h>
4362306a36Sopenharmony_ci#include <linux/types.h>
4462306a36Sopenharmony_ci#include <linux/kernel.h>
4562306a36Sopenharmony_ci#include <linux/bitops.h>
4662306a36Sopenharmony_ci#include <linux/sizes.h>
4762306a36Sopenharmony_ci#include <linux/module.h>
4862306a36Sopenharmony_ci#include <linux/moduleparam.h>
4962306a36Sopenharmony_ci#include <linux/init.h>
5062306a36Sopenharmony_ci#include <linux/interrupt.h>
5162306a36Sopenharmony_ci#include <linux/spinlock.h>
5262306a36Sopenharmony_ci#include <linux/mutex.h>
5362306a36Sopenharmony_ci#include <linux/pci.h>
5462306a36Sopenharmony_ci#include <linux/aer.h>
5562306a36Sopenharmony_ci#include <linux/slab.h>
5662306a36Sopenharmony_ci#include <linux/list.h>
5762306a36Sopenharmony_ci#include <linux/debugfs.h>
5862306a36Sopenharmony_ci#include <linux/hwmon.h>
5962306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
6062306a36Sopenharmony_ci#include <linux/ntb.h>
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#include "ntb_hw_idt.h"
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define NTB_NAME	"ntb_hw_idt"
6562306a36Sopenharmony_ci#define NTB_DESC	"IDT PCI-E Non-Transparent Bridge Driver"
6662306a36Sopenharmony_ci#define NTB_VER		"2.0"
6762306a36Sopenharmony_ci#define NTB_IRQNAME	"ntb_irq_idt"
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ciMODULE_DESCRIPTION(NTB_DESC);
7062306a36Sopenharmony_ciMODULE_VERSION(NTB_VER);
7162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
7262306a36Sopenharmony_ciMODULE_AUTHOR("T-platforms");
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * NT Endpoint registers table simplifying a loop access to the functionally
7662306a36Sopenharmony_ci * related registers
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_cistatic const struct idt_ntb_regs ntdata_tbl = {
7962306a36Sopenharmony_ci	{ {IDT_NT_BARSETUP0,	IDT_NT_BARLIMIT0,
8062306a36Sopenharmony_ci	   IDT_NT_BARLTBASE0,	IDT_NT_BARUTBASE0},
8162306a36Sopenharmony_ci	  {IDT_NT_BARSETUP1,	IDT_NT_BARLIMIT1,
8262306a36Sopenharmony_ci	   IDT_NT_BARLTBASE1,	IDT_NT_BARUTBASE1},
8362306a36Sopenharmony_ci	  {IDT_NT_BARSETUP2,	IDT_NT_BARLIMIT2,
8462306a36Sopenharmony_ci	   IDT_NT_BARLTBASE2,	IDT_NT_BARUTBASE2},
8562306a36Sopenharmony_ci	  {IDT_NT_BARSETUP3,	IDT_NT_BARLIMIT3,
8662306a36Sopenharmony_ci	   IDT_NT_BARLTBASE3,	IDT_NT_BARUTBASE3},
8762306a36Sopenharmony_ci	  {IDT_NT_BARSETUP4,	IDT_NT_BARLIMIT4,
8862306a36Sopenharmony_ci	   IDT_NT_BARLTBASE4,	IDT_NT_BARUTBASE4},
8962306a36Sopenharmony_ci	  {IDT_NT_BARSETUP5,	IDT_NT_BARLIMIT5,
9062306a36Sopenharmony_ci	   IDT_NT_BARLTBASE5,	IDT_NT_BARUTBASE5} },
9162306a36Sopenharmony_ci	{ {IDT_NT_INMSG0,	IDT_NT_OUTMSG0,	IDT_NT_INMSGSRC0},
9262306a36Sopenharmony_ci	  {IDT_NT_INMSG1,	IDT_NT_OUTMSG1,	IDT_NT_INMSGSRC1},
9362306a36Sopenharmony_ci	  {IDT_NT_INMSG2,	IDT_NT_OUTMSG2,	IDT_NT_INMSGSRC2},
9462306a36Sopenharmony_ci	  {IDT_NT_INMSG3,	IDT_NT_OUTMSG3,	IDT_NT_INMSGSRC3} }
9562306a36Sopenharmony_ci};
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/*
9862306a36Sopenharmony_ci * NT Endpoint ports data table with the corresponding pcie command, link
9962306a36Sopenharmony_ci * status, control and BAR-related registers
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_cistatic const struct idt_ntb_port portdata_tbl[IDT_MAX_NR_PORTS] = {
10262306a36Sopenharmony_ci/*0*/	{ IDT_SW_NTP0_PCIECMDSTS,	IDT_SW_NTP0_PCIELCTLSTS,
10362306a36Sopenharmony_ci	  IDT_SW_NTP0_NTCTL,
10462306a36Sopenharmony_ci	  IDT_SW_SWPORT0CTL,		IDT_SW_SWPORT0STS,
10562306a36Sopenharmony_ci	  { {IDT_SW_NTP0_BARSETUP0,	IDT_SW_NTP0_BARLIMIT0,
10662306a36Sopenharmony_ci	     IDT_SW_NTP0_BARLTBASE0,	IDT_SW_NTP0_BARUTBASE0},
10762306a36Sopenharmony_ci	    {IDT_SW_NTP0_BARSETUP1,	IDT_SW_NTP0_BARLIMIT1,
10862306a36Sopenharmony_ci	     IDT_SW_NTP0_BARLTBASE1,	IDT_SW_NTP0_BARUTBASE1},
10962306a36Sopenharmony_ci	    {IDT_SW_NTP0_BARSETUP2,	IDT_SW_NTP0_BARLIMIT2,
11062306a36Sopenharmony_ci	     IDT_SW_NTP0_BARLTBASE2,	IDT_SW_NTP0_BARUTBASE2},
11162306a36Sopenharmony_ci	    {IDT_SW_NTP0_BARSETUP3,	IDT_SW_NTP0_BARLIMIT3,
11262306a36Sopenharmony_ci	     IDT_SW_NTP0_BARLTBASE3,	IDT_SW_NTP0_BARUTBASE3},
11362306a36Sopenharmony_ci	    {IDT_SW_NTP0_BARSETUP4,	IDT_SW_NTP0_BARLIMIT4,
11462306a36Sopenharmony_ci	     IDT_SW_NTP0_BARLTBASE4,	IDT_SW_NTP0_BARUTBASE4},
11562306a36Sopenharmony_ci	    {IDT_SW_NTP0_BARSETUP5,	IDT_SW_NTP0_BARLIMIT5,
11662306a36Sopenharmony_ci	     IDT_SW_NTP0_BARLTBASE5,	IDT_SW_NTP0_BARUTBASE5} } },
11762306a36Sopenharmony_ci/*1*/	{0},
11862306a36Sopenharmony_ci/*2*/	{ IDT_SW_NTP2_PCIECMDSTS,	IDT_SW_NTP2_PCIELCTLSTS,
11962306a36Sopenharmony_ci	  IDT_SW_NTP2_NTCTL,
12062306a36Sopenharmony_ci	  IDT_SW_SWPORT2CTL,		IDT_SW_SWPORT2STS,
12162306a36Sopenharmony_ci	  { {IDT_SW_NTP2_BARSETUP0,	IDT_SW_NTP2_BARLIMIT0,
12262306a36Sopenharmony_ci	     IDT_SW_NTP2_BARLTBASE0,	IDT_SW_NTP2_BARUTBASE0},
12362306a36Sopenharmony_ci	    {IDT_SW_NTP2_BARSETUP1,	IDT_SW_NTP2_BARLIMIT1,
12462306a36Sopenharmony_ci	     IDT_SW_NTP2_BARLTBASE1,	IDT_SW_NTP2_BARUTBASE1},
12562306a36Sopenharmony_ci	    {IDT_SW_NTP2_BARSETUP2,	IDT_SW_NTP2_BARLIMIT2,
12662306a36Sopenharmony_ci	     IDT_SW_NTP2_BARLTBASE2,	IDT_SW_NTP2_BARUTBASE2},
12762306a36Sopenharmony_ci	    {IDT_SW_NTP2_BARSETUP3,	IDT_SW_NTP2_BARLIMIT3,
12862306a36Sopenharmony_ci	     IDT_SW_NTP2_BARLTBASE3,	IDT_SW_NTP2_BARUTBASE3},
12962306a36Sopenharmony_ci	    {IDT_SW_NTP2_BARSETUP4,	IDT_SW_NTP2_BARLIMIT4,
13062306a36Sopenharmony_ci	     IDT_SW_NTP2_BARLTBASE4,	IDT_SW_NTP2_BARUTBASE4},
13162306a36Sopenharmony_ci	    {IDT_SW_NTP2_BARSETUP5,	IDT_SW_NTP2_BARLIMIT5,
13262306a36Sopenharmony_ci	     IDT_SW_NTP2_BARLTBASE5,	IDT_SW_NTP2_BARUTBASE5} } },
13362306a36Sopenharmony_ci/*3*/	{0},
13462306a36Sopenharmony_ci/*4*/	{ IDT_SW_NTP4_PCIECMDSTS,	IDT_SW_NTP4_PCIELCTLSTS,
13562306a36Sopenharmony_ci	  IDT_SW_NTP4_NTCTL,
13662306a36Sopenharmony_ci	  IDT_SW_SWPORT4CTL,		IDT_SW_SWPORT4STS,
13762306a36Sopenharmony_ci	  { {IDT_SW_NTP4_BARSETUP0,	IDT_SW_NTP4_BARLIMIT0,
13862306a36Sopenharmony_ci	     IDT_SW_NTP4_BARLTBASE0,	IDT_SW_NTP4_BARUTBASE0},
13962306a36Sopenharmony_ci	    {IDT_SW_NTP4_BARSETUP1,	IDT_SW_NTP4_BARLIMIT1,
14062306a36Sopenharmony_ci	     IDT_SW_NTP4_BARLTBASE1,	IDT_SW_NTP4_BARUTBASE1},
14162306a36Sopenharmony_ci	    {IDT_SW_NTP4_BARSETUP2,	IDT_SW_NTP4_BARLIMIT2,
14262306a36Sopenharmony_ci	     IDT_SW_NTP4_BARLTBASE2,	IDT_SW_NTP4_BARUTBASE2},
14362306a36Sopenharmony_ci	    {IDT_SW_NTP4_BARSETUP3,	IDT_SW_NTP4_BARLIMIT3,
14462306a36Sopenharmony_ci	     IDT_SW_NTP4_BARLTBASE3,	IDT_SW_NTP4_BARUTBASE3},
14562306a36Sopenharmony_ci	    {IDT_SW_NTP4_BARSETUP4,	IDT_SW_NTP4_BARLIMIT4,
14662306a36Sopenharmony_ci	     IDT_SW_NTP4_BARLTBASE4,	IDT_SW_NTP4_BARUTBASE4},
14762306a36Sopenharmony_ci	    {IDT_SW_NTP4_BARSETUP5,	IDT_SW_NTP4_BARLIMIT5,
14862306a36Sopenharmony_ci	     IDT_SW_NTP4_BARLTBASE5,	IDT_SW_NTP4_BARUTBASE5} } },
14962306a36Sopenharmony_ci/*5*/	{0},
15062306a36Sopenharmony_ci/*6*/	{ IDT_SW_NTP6_PCIECMDSTS,	IDT_SW_NTP6_PCIELCTLSTS,
15162306a36Sopenharmony_ci	  IDT_SW_NTP6_NTCTL,
15262306a36Sopenharmony_ci	  IDT_SW_SWPORT6CTL,		IDT_SW_SWPORT6STS,
15362306a36Sopenharmony_ci	  { {IDT_SW_NTP6_BARSETUP0,	IDT_SW_NTP6_BARLIMIT0,
15462306a36Sopenharmony_ci	     IDT_SW_NTP6_BARLTBASE0,	IDT_SW_NTP6_BARUTBASE0},
15562306a36Sopenharmony_ci	    {IDT_SW_NTP6_BARSETUP1,	IDT_SW_NTP6_BARLIMIT1,
15662306a36Sopenharmony_ci	     IDT_SW_NTP6_BARLTBASE1,	IDT_SW_NTP6_BARUTBASE1},
15762306a36Sopenharmony_ci	    {IDT_SW_NTP6_BARSETUP2,	IDT_SW_NTP6_BARLIMIT2,
15862306a36Sopenharmony_ci	     IDT_SW_NTP6_BARLTBASE2,	IDT_SW_NTP6_BARUTBASE2},
15962306a36Sopenharmony_ci	    {IDT_SW_NTP6_BARSETUP3,	IDT_SW_NTP6_BARLIMIT3,
16062306a36Sopenharmony_ci	     IDT_SW_NTP6_BARLTBASE3,	IDT_SW_NTP6_BARUTBASE3},
16162306a36Sopenharmony_ci	    {IDT_SW_NTP6_BARSETUP4,	IDT_SW_NTP6_BARLIMIT4,
16262306a36Sopenharmony_ci	     IDT_SW_NTP6_BARLTBASE4,	IDT_SW_NTP6_BARUTBASE4},
16362306a36Sopenharmony_ci	    {IDT_SW_NTP6_BARSETUP5,	IDT_SW_NTP6_BARLIMIT5,
16462306a36Sopenharmony_ci	     IDT_SW_NTP6_BARLTBASE5,	IDT_SW_NTP6_BARUTBASE5} } },
16562306a36Sopenharmony_ci/*7*/	{0},
16662306a36Sopenharmony_ci/*8*/	{ IDT_SW_NTP8_PCIECMDSTS,	IDT_SW_NTP8_PCIELCTLSTS,
16762306a36Sopenharmony_ci	  IDT_SW_NTP8_NTCTL,
16862306a36Sopenharmony_ci	  IDT_SW_SWPORT8CTL,		IDT_SW_SWPORT8STS,
16962306a36Sopenharmony_ci	  { {IDT_SW_NTP8_BARSETUP0,	IDT_SW_NTP8_BARLIMIT0,
17062306a36Sopenharmony_ci	     IDT_SW_NTP8_BARLTBASE0,	IDT_SW_NTP8_BARUTBASE0},
17162306a36Sopenharmony_ci	    {IDT_SW_NTP8_BARSETUP1,	IDT_SW_NTP8_BARLIMIT1,
17262306a36Sopenharmony_ci	     IDT_SW_NTP8_BARLTBASE1,	IDT_SW_NTP8_BARUTBASE1},
17362306a36Sopenharmony_ci	    {IDT_SW_NTP8_BARSETUP2,	IDT_SW_NTP8_BARLIMIT2,
17462306a36Sopenharmony_ci	     IDT_SW_NTP8_BARLTBASE2,	IDT_SW_NTP8_BARUTBASE2},
17562306a36Sopenharmony_ci	    {IDT_SW_NTP8_BARSETUP3,	IDT_SW_NTP8_BARLIMIT3,
17662306a36Sopenharmony_ci	     IDT_SW_NTP8_BARLTBASE3,	IDT_SW_NTP8_BARUTBASE3},
17762306a36Sopenharmony_ci	    {IDT_SW_NTP8_BARSETUP4,	IDT_SW_NTP8_BARLIMIT4,
17862306a36Sopenharmony_ci	     IDT_SW_NTP8_BARLTBASE4,	IDT_SW_NTP8_BARUTBASE4},
17962306a36Sopenharmony_ci	    {IDT_SW_NTP8_BARSETUP5,	IDT_SW_NTP8_BARLIMIT5,
18062306a36Sopenharmony_ci	     IDT_SW_NTP8_BARLTBASE5,	IDT_SW_NTP8_BARUTBASE5} } },
18162306a36Sopenharmony_ci/*9*/	{0},
18262306a36Sopenharmony_ci/*10*/	{0},
18362306a36Sopenharmony_ci/*11*/	{0},
18462306a36Sopenharmony_ci/*12*/	{ IDT_SW_NTP12_PCIECMDSTS,	IDT_SW_NTP12_PCIELCTLSTS,
18562306a36Sopenharmony_ci	  IDT_SW_NTP12_NTCTL,
18662306a36Sopenharmony_ci	  IDT_SW_SWPORT12CTL,		IDT_SW_SWPORT12STS,
18762306a36Sopenharmony_ci	  { {IDT_SW_NTP12_BARSETUP0,	IDT_SW_NTP12_BARLIMIT0,
18862306a36Sopenharmony_ci	     IDT_SW_NTP12_BARLTBASE0,	IDT_SW_NTP12_BARUTBASE0},
18962306a36Sopenharmony_ci	    {IDT_SW_NTP12_BARSETUP1,	IDT_SW_NTP12_BARLIMIT1,
19062306a36Sopenharmony_ci	     IDT_SW_NTP12_BARLTBASE1,	IDT_SW_NTP12_BARUTBASE1},
19162306a36Sopenharmony_ci	    {IDT_SW_NTP12_BARSETUP2,	IDT_SW_NTP12_BARLIMIT2,
19262306a36Sopenharmony_ci	     IDT_SW_NTP12_BARLTBASE2,	IDT_SW_NTP12_BARUTBASE2},
19362306a36Sopenharmony_ci	    {IDT_SW_NTP12_BARSETUP3,	IDT_SW_NTP12_BARLIMIT3,
19462306a36Sopenharmony_ci	     IDT_SW_NTP12_BARLTBASE3,	IDT_SW_NTP12_BARUTBASE3},
19562306a36Sopenharmony_ci	    {IDT_SW_NTP12_BARSETUP4,	IDT_SW_NTP12_BARLIMIT4,
19662306a36Sopenharmony_ci	     IDT_SW_NTP12_BARLTBASE4,	IDT_SW_NTP12_BARUTBASE4},
19762306a36Sopenharmony_ci	    {IDT_SW_NTP12_BARSETUP5,	IDT_SW_NTP12_BARLIMIT5,
19862306a36Sopenharmony_ci	     IDT_SW_NTP12_BARLTBASE5,	IDT_SW_NTP12_BARUTBASE5} } },
19962306a36Sopenharmony_ci/*13*/	{0},
20062306a36Sopenharmony_ci/*14*/	{0},
20162306a36Sopenharmony_ci/*15*/	{0},
20262306a36Sopenharmony_ci/*16*/	{ IDT_SW_NTP16_PCIECMDSTS,	IDT_SW_NTP16_PCIELCTLSTS,
20362306a36Sopenharmony_ci	  IDT_SW_NTP16_NTCTL,
20462306a36Sopenharmony_ci	  IDT_SW_SWPORT16CTL,		IDT_SW_SWPORT16STS,
20562306a36Sopenharmony_ci	  { {IDT_SW_NTP16_BARSETUP0,	IDT_SW_NTP16_BARLIMIT0,
20662306a36Sopenharmony_ci	     IDT_SW_NTP16_BARLTBASE0,	IDT_SW_NTP16_BARUTBASE0},
20762306a36Sopenharmony_ci	    {IDT_SW_NTP16_BARSETUP1,	IDT_SW_NTP16_BARLIMIT1,
20862306a36Sopenharmony_ci	     IDT_SW_NTP16_BARLTBASE1,	IDT_SW_NTP16_BARUTBASE1},
20962306a36Sopenharmony_ci	    {IDT_SW_NTP16_BARSETUP2,	IDT_SW_NTP16_BARLIMIT2,
21062306a36Sopenharmony_ci	     IDT_SW_NTP16_BARLTBASE2,	IDT_SW_NTP16_BARUTBASE2},
21162306a36Sopenharmony_ci	    {IDT_SW_NTP16_BARSETUP3,	IDT_SW_NTP16_BARLIMIT3,
21262306a36Sopenharmony_ci	     IDT_SW_NTP16_BARLTBASE3,	IDT_SW_NTP16_BARUTBASE3},
21362306a36Sopenharmony_ci	    {IDT_SW_NTP16_BARSETUP4,	IDT_SW_NTP16_BARLIMIT4,
21462306a36Sopenharmony_ci	     IDT_SW_NTP16_BARLTBASE4,	IDT_SW_NTP16_BARUTBASE4},
21562306a36Sopenharmony_ci	    {IDT_SW_NTP16_BARSETUP5,	IDT_SW_NTP16_BARLIMIT5,
21662306a36Sopenharmony_ci	     IDT_SW_NTP16_BARLTBASE5,	IDT_SW_NTP16_BARUTBASE5} } },
21762306a36Sopenharmony_ci/*17*/	{0},
21862306a36Sopenharmony_ci/*18*/	{0},
21962306a36Sopenharmony_ci/*19*/	{0},
22062306a36Sopenharmony_ci/*20*/	{ IDT_SW_NTP20_PCIECMDSTS,	IDT_SW_NTP20_PCIELCTLSTS,
22162306a36Sopenharmony_ci	  IDT_SW_NTP20_NTCTL,
22262306a36Sopenharmony_ci	  IDT_SW_SWPORT20CTL,		IDT_SW_SWPORT20STS,
22362306a36Sopenharmony_ci	  { {IDT_SW_NTP20_BARSETUP0,	IDT_SW_NTP20_BARLIMIT0,
22462306a36Sopenharmony_ci	     IDT_SW_NTP20_BARLTBASE0,	IDT_SW_NTP20_BARUTBASE0},
22562306a36Sopenharmony_ci	    {IDT_SW_NTP20_BARSETUP1,	IDT_SW_NTP20_BARLIMIT1,
22662306a36Sopenharmony_ci	     IDT_SW_NTP20_BARLTBASE1,	IDT_SW_NTP20_BARUTBASE1},
22762306a36Sopenharmony_ci	    {IDT_SW_NTP20_BARSETUP2,	IDT_SW_NTP20_BARLIMIT2,
22862306a36Sopenharmony_ci	     IDT_SW_NTP20_BARLTBASE2,	IDT_SW_NTP20_BARUTBASE2},
22962306a36Sopenharmony_ci	    {IDT_SW_NTP20_BARSETUP3,	IDT_SW_NTP20_BARLIMIT3,
23062306a36Sopenharmony_ci	     IDT_SW_NTP20_BARLTBASE3,	IDT_SW_NTP20_BARUTBASE3},
23162306a36Sopenharmony_ci	    {IDT_SW_NTP20_BARSETUP4,	IDT_SW_NTP20_BARLIMIT4,
23262306a36Sopenharmony_ci	     IDT_SW_NTP20_BARLTBASE4,	IDT_SW_NTP20_BARUTBASE4},
23362306a36Sopenharmony_ci	    {IDT_SW_NTP20_BARSETUP5,	IDT_SW_NTP20_BARLIMIT5,
23462306a36Sopenharmony_ci	     IDT_SW_NTP20_BARLTBASE5,	IDT_SW_NTP20_BARUTBASE5} } },
23562306a36Sopenharmony_ci/*21*/	{0},
23662306a36Sopenharmony_ci/*22*/	{0},
23762306a36Sopenharmony_ci/*23*/	{0}
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/*
24162306a36Sopenharmony_ci * IDT PCIe-switch partitions table with the corresponding control, status
24262306a36Sopenharmony_ci * and messages control registers
24362306a36Sopenharmony_ci */
24462306a36Sopenharmony_cistatic const struct idt_ntb_part partdata_tbl[IDT_MAX_NR_PARTS] = {
24562306a36Sopenharmony_ci/*0*/	{ IDT_SW_SWPART0CTL,	IDT_SW_SWPART0STS,
24662306a36Sopenharmony_ci	  {IDT_SW_SWP0MSGCTL0,	IDT_SW_SWP0MSGCTL1,
24762306a36Sopenharmony_ci	   IDT_SW_SWP0MSGCTL2,	IDT_SW_SWP0MSGCTL3} },
24862306a36Sopenharmony_ci/*1*/	{ IDT_SW_SWPART1CTL,	IDT_SW_SWPART1STS,
24962306a36Sopenharmony_ci	  {IDT_SW_SWP1MSGCTL0,	IDT_SW_SWP1MSGCTL1,
25062306a36Sopenharmony_ci	   IDT_SW_SWP1MSGCTL2,	IDT_SW_SWP1MSGCTL3} },
25162306a36Sopenharmony_ci/*2*/	{ IDT_SW_SWPART2CTL,	IDT_SW_SWPART2STS,
25262306a36Sopenharmony_ci	  {IDT_SW_SWP2MSGCTL0,	IDT_SW_SWP2MSGCTL1,
25362306a36Sopenharmony_ci	   IDT_SW_SWP2MSGCTL2,	IDT_SW_SWP2MSGCTL3} },
25462306a36Sopenharmony_ci/*3*/	{ IDT_SW_SWPART3CTL,	IDT_SW_SWPART3STS,
25562306a36Sopenharmony_ci	  {IDT_SW_SWP3MSGCTL0,	IDT_SW_SWP3MSGCTL1,
25662306a36Sopenharmony_ci	   IDT_SW_SWP3MSGCTL2,	IDT_SW_SWP3MSGCTL3} },
25762306a36Sopenharmony_ci/*4*/	{ IDT_SW_SWPART4CTL,	IDT_SW_SWPART4STS,
25862306a36Sopenharmony_ci	  {IDT_SW_SWP4MSGCTL0,	IDT_SW_SWP4MSGCTL1,
25962306a36Sopenharmony_ci	   IDT_SW_SWP4MSGCTL2,	IDT_SW_SWP4MSGCTL3} },
26062306a36Sopenharmony_ci/*5*/	{ IDT_SW_SWPART5CTL,	IDT_SW_SWPART5STS,
26162306a36Sopenharmony_ci	  {IDT_SW_SWP5MSGCTL0,	IDT_SW_SWP5MSGCTL1,
26262306a36Sopenharmony_ci	   IDT_SW_SWP5MSGCTL2,	IDT_SW_SWP5MSGCTL3} },
26362306a36Sopenharmony_ci/*6*/	{ IDT_SW_SWPART6CTL,	IDT_SW_SWPART6STS,
26462306a36Sopenharmony_ci	  {IDT_SW_SWP6MSGCTL0,	IDT_SW_SWP6MSGCTL1,
26562306a36Sopenharmony_ci	   IDT_SW_SWP6MSGCTL2,	IDT_SW_SWP6MSGCTL3} },
26662306a36Sopenharmony_ci/*7*/	{ IDT_SW_SWPART7CTL,	IDT_SW_SWPART7STS,
26762306a36Sopenharmony_ci	  {IDT_SW_SWP7MSGCTL0,	IDT_SW_SWP7MSGCTL1,
26862306a36Sopenharmony_ci	   IDT_SW_SWP7MSGCTL2,	IDT_SW_SWP7MSGCTL3} }
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/*
27262306a36Sopenharmony_ci * DebugFS directory to place the driver debug file
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_cistatic struct dentry *dbgfs_topdir;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/*=============================================================================
27762306a36Sopenharmony_ci *                1. IDT PCIe-switch registers IO-functions
27862306a36Sopenharmony_ci *
27962306a36Sopenharmony_ci *    Beside ordinary configuration space registers IDT PCIe-switch expose
28062306a36Sopenharmony_ci * global configuration registers, which are used to determine state of other
28162306a36Sopenharmony_ci * device ports as well as being notified of some switch-related events.
28262306a36Sopenharmony_ci * Additionally all the configuration space registers of all the IDT
28362306a36Sopenharmony_ci * PCIe-switch functions are mapped to the Global Address space, so each
28462306a36Sopenharmony_ci * function can determine a configuration of any other PCI-function.
28562306a36Sopenharmony_ci *    Functions declared in this chapter are created to encapsulate access
28662306a36Sopenharmony_ci * to configuration and global registers, so the driver code just need to
28762306a36Sopenharmony_ci * provide IDT NTB hardware descriptor and a register address.
28862306a36Sopenharmony_ci *=============================================================================
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/*
29262306a36Sopenharmony_ci * idt_nt_write() - PCI configuration space registers write method
29362306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
29462306a36Sopenharmony_ci * @reg:	Register to write data to
29562306a36Sopenharmony_ci * @data:	Value to write to the register
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * IDT PCIe-switch registers are all Little endian.
29862306a36Sopenharmony_ci */
29962306a36Sopenharmony_cistatic void idt_nt_write(struct idt_ntb_dev *ndev,
30062306a36Sopenharmony_ci			 const unsigned int reg, const u32 data)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	/*
30362306a36Sopenharmony_ci	 * It's obvious bug to request a register exceeding the maximum possible
30462306a36Sopenharmony_ci	 * value as well as to have it unaligned.
30562306a36Sopenharmony_ci	 */
30662306a36Sopenharmony_ci	if (WARN_ON(reg > IDT_REG_PCI_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
30762306a36Sopenharmony_ci		return;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Just write the value to the specified register */
31062306a36Sopenharmony_ci	iowrite32(data, ndev->cfgspc + (ptrdiff_t)reg);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci/*
31462306a36Sopenharmony_ci * idt_nt_read() - PCI configuration space registers read method
31562306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
31662306a36Sopenharmony_ci * @reg:	Register to write data to
31762306a36Sopenharmony_ci *
31862306a36Sopenharmony_ci * IDT PCIe-switch Global configuration registers are all Little endian.
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * Return: register value
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_cistatic u32 idt_nt_read(struct idt_ntb_dev *ndev, const unsigned int reg)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	/*
32562306a36Sopenharmony_ci	 * It's obvious bug to request a register exceeding the maximum possible
32662306a36Sopenharmony_ci	 * value as well as to have it unaligned.
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	if (WARN_ON(reg > IDT_REG_PCI_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
32962306a36Sopenharmony_ci		return ~0;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Just read the value from the specified register */
33262306a36Sopenharmony_ci	return ioread32(ndev->cfgspc + (ptrdiff_t)reg);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/*
33662306a36Sopenharmony_ci * idt_sw_write() - Global registers write method
33762306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
33862306a36Sopenharmony_ci * @reg:	Register to write data to
33962306a36Sopenharmony_ci * @data:	Value to write to the register
34062306a36Sopenharmony_ci *
34162306a36Sopenharmony_ci * IDT PCIe-switch Global configuration registers are all Little endian.
34262306a36Sopenharmony_ci */
34362306a36Sopenharmony_cistatic void idt_sw_write(struct idt_ntb_dev *ndev,
34462306a36Sopenharmony_ci			 const unsigned int reg, const u32 data)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	unsigned long irqflags;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/*
34962306a36Sopenharmony_ci	 * It's obvious bug to request a register exceeding the maximum possible
35062306a36Sopenharmony_ci	 * value as well as to have it unaligned.
35162306a36Sopenharmony_ci	 */
35262306a36Sopenharmony_ci	if (WARN_ON(reg > IDT_REG_SW_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
35362306a36Sopenharmony_ci		return;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Lock GASA registers operations */
35662306a36Sopenharmony_ci	spin_lock_irqsave(&ndev->gasa_lock, irqflags);
35762306a36Sopenharmony_ci	/* Set the global register address */
35862306a36Sopenharmony_ci	iowrite32((u32)reg, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASAADDR);
35962306a36Sopenharmony_ci	/* Put the new value of the register */
36062306a36Sopenharmony_ci	iowrite32(data, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASADATA);
36162306a36Sopenharmony_ci	/* Unlock GASA registers operations */
36262306a36Sopenharmony_ci	spin_unlock_irqrestore(&ndev->gasa_lock, irqflags);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/*
36662306a36Sopenharmony_ci * idt_sw_read() - Global registers read method
36762306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
36862306a36Sopenharmony_ci * @reg:	Register to write data to
36962306a36Sopenharmony_ci *
37062306a36Sopenharmony_ci * IDT PCIe-switch Global configuration registers are all Little endian.
37162306a36Sopenharmony_ci *
37262306a36Sopenharmony_ci * Return: register value
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_cistatic u32 idt_sw_read(struct idt_ntb_dev *ndev, const unsigned int reg)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	unsigned long irqflags;
37762306a36Sopenharmony_ci	u32 data;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/*
38062306a36Sopenharmony_ci	 * It's obvious bug to request a register exceeding the maximum possible
38162306a36Sopenharmony_ci	 * value as well as to have it unaligned.
38262306a36Sopenharmony_ci	 */
38362306a36Sopenharmony_ci	if (WARN_ON(reg > IDT_REG_SW_MAX || !IS_ALIGNED(reg, IDT_REG_ALIGN)))
38462306a36Sopenharmony_ci		return ~0;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Lock GASA registers operations */
38762306a36Sopenharmony_ci	spin_lock_irqsave(&ndev->gasa_lock, irqflags);
38862306a36Sopenharmony_ci	/* Set the global register address */
38962306a36Sopenharmony_ci	iowrite32((u32)reg, ndev->cfgspc + (ptrdiff_t)IDT_NT_GASAADDR);
39062306a36Sopenharmony_ci	/* Get the data of the register (read ops acts as MMIO barrier) */
39162306a36Sopenharmony_ci	data = ioread32(ndev->cfgspc + (ptrdiff_t)IDT_NT_GASADATA);
39262306a36Sopenharmony_ci	/* Unlock GASA registers operations */
39362306a36Sopenharmony_ci	spin_unlock_irqrestore(&ndev->gasa_lock, irqflags);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return data;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci/*
39962306a36Sopenharmony_ci * idt_reg_set_bits() - set bits of a passed register
40062306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
40162306a36Sopenharmony_ci * @reg:	Register to change bits of
40262306a36Sopenharmony_ci * @reg_lock:	Register access spin lock
40362306a36Sopenharmony_ci * @valid_mask:	Mask of valid bits
40462306a36Sopenharmony_ci * @set_bits:	Bitmask to set
40562306a36Sopenharmony_ci *
40662306a36Sopenharmony_ci * Helper method to check whether a passed bitfield is valid and set
40762306a36Sopenharmony_ci * corresponding bits of a register.
40862306a36Sopenharmony_ci *
40962306a36Sopenharmony_ci * WARNING! Make sure the passed register isn't accessed over plane
41062306a36Sopenharmony_ci * idt_nt_write() method (read method is ok to be used concurrently).
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci * Return: zero on success, negative error on invalid bitmask.
41362306a36Sopenharmony_ci */
41462306a36Sopenharmony_cistatic inline int idt_reg_set_bits(struct idt_ntb_dev *ndev, unsigned int reg,
41562306a36Sopenharmony_ci				   spinlock_t *reg_lock,
41662306a36Sopenharmony_ci				   u64 valid_mask, u64 set_bits)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	unsigned long irqflags;
41962306a36Sopenharmony_ci	u32 data;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	if (set_bits & ~(u64)valid_mask)
42262306a36Sopenharmony_ci		return -EINVAL;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Lock access to the register unless the change is written back */
42562306a36Sopenharmony_ci	spin_lock_irqsave(reg_lock, irqflags);
42662306a36Sopenharmony_ci	data = idt_nt_read(ndev, reg) | (u32)set_bits;
42762306a36Sopenharmony_ci	idt_nt_write(ndev, reg, data);
42862306a36Sopenharmony_ci	/* Unlock the register */
42962306a36Sopenharmony_ci	spin_unlock_irqrestore(reg_lock, irqflags);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci/*
43562306a36Sopenharmony_ci * idt_reg_clear_bits() - clear bits of a passed register
43662306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
43762306a36Sopenharmony_ci * @reg:	Register to change bits of
43862306a36Sopenharmony_ci * @reg_lock:	Register access spin lock
43962306a36Sopenharmony_ci * @set_bits:	Bitmask to clear
44062306a36Sopenharmony_ci *
44162306a36Sopenharmony_ci * Helper method to check whether a passed bitfield is valid and clear
44262306a36Sopenharmony_ci * corresponding bits of a register.
44362306a36Sopenharmony_ci *
44462306a36Sopenharmony_ci * NOTE! Invalid bits are always considered cleared so it's not an error
44562306a36Sopenharmony_ci * to clear them over.
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * WARNING! Make sure the passed register isn't accessed over plane
44862306a36Sopenharmony_ci * idt_nt_write() method (read method is ok to use concurrently).
44962306a36Sopenharmony_ci */
45062306a36Sopenharmony_cistatic inline void idt_reg_clear_bits(struct idt_ntb_dev *ndev,
45162306a36Sopenharmony_ci				     unsigned int reg, spinlock_t *reg_lock,
45262306a36Sopenharmony_ci				     u64 clear_bits)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	unsigned long irqflags;
45562306a36Sopenharmony_ci	u32 data;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/* Lock access to the register unless the change is written back */
45862306a36Sopenharmony_ci	spin_lock_irqsave(reg_lock, irqflags);
45962306a36Sopenharmony_ci	data = idt_nt_read(ndev, reg) & ~(u32)clear_bits;
46062306a36Sopenharmony_ci	idt_nt_write(ndev, reg, data);
46162306a36Sopenharmony_ci	/* Unlock the register */
46262306a36Sopenharmony_ci	spin_unlock_irqrestore(reg_lock, irqflags);
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci/*===========================================================================
46662306a36Sopenharmony_ci *                           2. Ports operations
46762306a36Sopenharmony_ci *
46862306a36Sopenharmony_ci *    IDT PCIe-switches can have from 3 up to 8 ports with possible
46962306a36Sopenharmony_ci * NT-functions enabled. So all the possible ports need to be scanned looking
47062306a36Sopenharmony_ci * for NTB activated. NTB API will have enumerated only the ports with NTB.
47162306a36Sopenharmony_ci *===========================================================================
47262306a36Sopenharmony_ci */
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci/*
47562306a36Sopenharmony_ci * idt_scan_ports() - scan IDT PCIe-switch ports collecting info in the tables
47662306a36Sopenharmony_ci * @ndev:	Pointer to the PCI device descriptor
47762306a36Sopenharmony_ci *
47862306a36Sopenharmony_ci * Return: zero on success, otherwise a negative error number.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_cistatic int idt_scan_ports(struct idt_ntb_dev *ndev)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	unsigned char pidx, port, part;
48362306a36Sopenharmony_ci	u32 data, portsts, partsts;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* Retrieve the local port number */
48662306a36Sopenharmony_ci	data = idt_nt_read(ndev, IDT_NT_PCIELCAP);
48762306a36Sopenharmony_ci	ndev->port = GET_FIELD(PCIELCAP_PORTNUM, data);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* Retrieve the local partition number */
49062306a36Sopenharmony_ci	portsts = idt_sw_read(ndev, portdata_tbl[ndev->port].sts);
49162306a36Sopenharmony_ci	ndev->part = GET_FIELD(SWPORTxSTS_SWPART, portsts);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	/* Initialize port/partition -> index tables with invalid values */
49462306a36Sopenharmony_ci	memset(ndev->port_idx_map, -EINVAL, sizeof(ndev->port_idx_map));
49562306a36Sopenharmony_ci	memset(ndev->part_idx_map, -EINVAL, sizeof(ndev->part_idx_map));
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/*
49862306a36Sopenharmony_ci	 * Walk over all the possible ports checking whether any of them has
49962306a36Sopenharmony_ci	 * NT-function activated
50062306a36Sopenharmony_ci	 */
50162306a36Sopenharmony_ci	ndev->peer_cnt = 0;
50262306a36Sopenharmony_ci	for (pidx = 0; pidx < ndev->swcfg->port_cnt; pidx++) {
50362306a36Sopenharmony_ci		port = ndev->swcfg->ports[pidx];
50462306a36Sopenharmony_ci		/* Skip local port */
50562306a36Sopenharmony_ci		if (port == ndev->port)
50662306a36Sopenharmony_ci			continue;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		/* Read the port status register to get it partition */
50962306a36Sopenharmony_ci		portsts = idt_sw_read(ndev, portdata_tbl[port].sts);
51062306a36Sopenharmony_ci		part = GET_FIELD(SWPORTxSTS_SWPART, portsts);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		/* Retrieve the partition status */
51362306a36Sopenharmony_ci		partsts = idt_sw_read(ndev, partdata_tbl[part].sts);
51462306a36Sopenharmony_ci		/* Check if partition state is active and port has NTB */
51562306a36Sopenharmony_ci		if (IS_FLD_SET(SWPARTxSTS_STATE, partsts, ACT) &&
51662306a36Sopenharmony_ci		    (IS_FLD_SET(SWPORTxSTS_MODE, portsts, NT) ||
51762306a36Sopenharmony_ci		     IS_FLD_SET(SWPORTxSTS_MODE, portsts, USNT) ||
51862306a36Sopenharmony_ci		     IS_FLD_SET(SWPORTxSTS_MODE, portsts, USNTDMA) ||
51962306a36Sopenharmony_ci		     IS_FLD_SET(SWPORTxSTS_MODE, portsts, NTDMA))) {
52062306a36Sopenharmony_ci			/* Save the port and partition numbers */
52162306a36Sopenharmony_ci			ndev->peers[ndev->peer_cnt].port = port;
52262306a36Sopenharmony_ci			ndev->peers[ndev->peer_cnt].part = part;
52362306a36Sopenharmony_ci			/* Fill in the port/partition -> index tables */
52462306a36Sopenharmony_ci			ndev->port_idx_map[port] = ndev->peer_cnt;
52562306a36Sopenharmony_ci			ndev->part_idx_map[part] = ndev->peer_cnt;
52662306a36Sopenharmony_ci			ndev->peer_cnt++;
52762306a36Sopenharmony_ci		}
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "Local port: %hhu, num of peers: %hhu\n",
53162306a36Sopenharmony_ci		ndev->port, ndev->peer_cnt);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* It's useless to have this driver loaded if there is no any peer */
53462306a36Sopenharmony_ci	if (ndev->peer_cnt == 0) {
53562306a36Sopenharmony_ci		dev_warn(&ndev->ntb.pdev->dev, "No active peer found\n");
53662306a36Sopenharmony_ci		return -ENODEV;
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci/*
54362306a36Sopenharmony_ci * idt_ntb_port_number() - get the local port number
54462306a36Sopenharmony_ci * @ntb:	NTB device context.
54562306a36Sopenharmony_ci *
54662306a36Sopenharmony_ci * Return: the local port number
54762306a36Sopenharmony_ci */
54862306a36Sopenharmony_cistatic int idt_ntb_port_number(struct ntb_dev *ntb)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return ndev->port;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci/*
55662306a36Sopenharmony_ci * idt_ntb_peer_port_count() - get the number of peer ports
55762306a36Sopenharmony_ci * @ntb:	NTB device context.
55862306a36Sopenharmony_ci *
55962306a36Sopenharmony_ci * Return the count of detected peer NT-functions.
56062306a36Sopenharmony_ci *
56162306a36Sopenharmony_ci * Return: number of peer ports
56262306a36Sopenharmony_ci */
56362306a36Sopenharmony_cistatic int idt_ntb_peer_port_count(struct ntb_dev *ntb)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return ndev->peer_cnt;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/*
57162306a36Sopenharmony_ci * idt_ntb_peer_port_number() - get peer port by given index
57262306a36Sopenharmony_ci * @ntb:	NTB device context.
57362306a36Sopenharmony_ci * @pidx:	Peer port index.
57462306a36Sopenharmony_ci *
57562306a36Sopenharmony_ci * Return: peer port or negative error
57662306a36Sopenharmony_ci */
57762306a36Sopenharmony_cistatic int idt_ntb_peer_port_number(struct ntb_dev *ntb, int pidx)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (pidx < 0 || ndev->peer_cnt <= pidx)
58262306a36Sopenharmony_ci		return -EINVAL;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/* Return the detected NT-function port number */
58562306a36Sopenharmony_ci	return ndev->peers[pidx].port;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci/*
58962306a36Sopenharmony_ci * idt_ntb_peer_port_idx() - get peer port index by given port number
59062306a36Sopenharmony_ci * @ntb:	NTB device context.
59162306a36Sopenharmony_ci * @port:	Peer port number.
59262306a36Sopenharmony_ci *
59362306a36Sopenharmony_ci * Internal port -> index table is pre-initialized with -EINVAL values,
59462306a36Sopenharmony_ci * so we just need to return it value
59562306a36Sopenharmony_ci *
59662306a36Sopenharmony_ci * Return: peer NT-function port index or negative error
59762306a36Sopenharmony_ci */
59862306a36Sopenharmony_cistatic int idt_ntb_peer_port_idx(struct ntb_dev *ntb, int port)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (port < 0 || IDT_MAX_NR_PORTS <= port)
60362306a36Sopenharmony_ci		return -EINVAL;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return ndev->port_idx_map[port];
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci/*===========================================================================
60962306a36Sopenharmony_ci *                         3. Link status operations
61062306a36Sopenharmony_ci *    There is no any ready-to-use method to have peer ports notified if NTB
61162306a36Sopenharmony_ci * link is set up or got down. Instead global signal can be used instead.
61262306a36Sopenharmony_ci * In case if any one of ports changes local NTB link state, it sends
61362306a36Sopenharmony_ci * global signal and clears corresponding global state bit. Then all the ports
61462306a36Sopenharmony_ci * receive a notification of that, so to make client driver being aware of
61562306a36Sopenharmony_ci * possible NTB link change.
61662306a36Sopenharmony_ci *    Additionally each of active NT-functions is subscribed to PCIe-link
61762306a36Sopenharmony_ci * state changes of peer ports.
61862306a36Sopenharmony_ci *===========================================================================
61962306a36Sopenharmony_ci */
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic void idt_ntb_local_link_disable(struct idt_ntb_dev *ndev);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/*
62462306a36Sopenharmony_ci * idt_init_link() - Initialize NTB link state notification subsystem
62562306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
62662306a36Sopenharmony_ci *
62762306a36Sopenharmony_ci * Function performs the basic initialization of some global registers
62862306a36Sopenharmony_ci * needed to enable IRQ-based notifications of PCIe Link Up/Down and
62962306a36Sopenharmony_ci * Global Signal events.
63062306a36Sopenharmony_ci * NOTE Since it's not possible to determine when all the NTB peer drivers are
63162306a36Sopenharmony_ci * unloaded as well as have those registers accessed concurrently, we must
63262306a36Sopenharmony_ci * preinitialize them with the same value and leave it uncleared on local
63362306a36Sopenharmony_ci * driver unload.
63462306a36Sopenharmony_ci */
63562306a36Sopenharmony_cistatic void idt_init_link(struct idt_ntb_dev *ndev)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	u32 part_mask, port_mask, se_mask;
63862306a36Sopenharmony_ci	unsigned char pidx;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Initialize spin locker of Mapping Table access registers */
64162306a36Sopenharmony_ci	spin_lock_init(&ndev->mtbl_lock);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* Walk over all detected peers collecting port and partition masks */
64462306a36Sopenharmony_ci	port_mask = ~BIT(ndev->port);
64562306a36Sopenharmony_ci	part_mask = ~BIT(ndev->part);
64662306a36Sopenharmony_ci	for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
64762306a36Sopenharmony_ci		port_mask &= ~BIT(ndev->peers[pidx].port);
64862306a36Sopenharmony_ci		part_mask &= ~BIT(ndev->peers[pidx].part);
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	/* Clean the Link Up/Down and GLobal Signal status registers */
65262306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SELINKUPSTS, (u32)-1);
65362306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SELINKDNSTS, (u32)-1);
65462306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)-1);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/* Unmask NT-activated partitions to receive Global Switch events */
65762306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SEPMSK, part_mask);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/* Enable PCIe Link Up events of NT-activated ports */
66062306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SELINKUPMSK, port_mask);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* Enable PCIe Link Down events of NT-activated ports */
66362306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SELINKDNMSK, port_mask);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* Unmask NT-activated partitions to receive Global Signal events */
66662306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SEGSIGMSK, part_mask);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Unmask Link Up/Down and Global Switch Events */
66962306a36Sopenharmony_ci	se_mask = ~(IDT_SEMSK_LINKUP | IDT_SEMSK_LINKDN | IDT_SEMSK_GSIGNAL);
67062306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SEMSK, se_mask);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "NTB link status events initialized");
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci/*
67662306a36Sopenharmony_ci * idt_deinit_link() - deinitialize link subsystem
67762306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
67862306a36Sopenharmony_ci *
67962306a36Sopenharmony_ci * Just disable the link back.
68062306a36Sopenharmony_ci */
68162306a36Sopenharmony_cistatic void idt_deinit_link(struct idt_ntb_dev *ndev)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	/* Disable the link */
68462306a36Sopenharmony_ci	idt_ntb_local_link_disable(ndev);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "NTB link status events deinitialized");
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci/*
69062306a36Sopenharmony_ci * idt_se_isr() - switch events ISR
69162306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
69262306a36Sopenharmony_ci * @ntint_sts:	NT-function interrupt status
69362306a36Sopenharmony_ci *
69462306a36Sopenharmony_ci * This driver doesn't support IDT PCIe-switch dynamic reconfigurations,
69562306a36Sopenharmony_ci * Failover capability, etc, so switch events are utilized to notify of
69662306a36Sopenharmony_ci * PCIe and NTB link events.
69762306a36Sopenharmony_ci * The method is called from PCIe ISR bottom-half routine.
69862306a36Sopenharmony_ci */
69962306a36Sopenharmony_cistatic void idt_se_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	u32 sests;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* Read Switch Events status */
70462306a36Sopenharmony_ci	sests = idt_sw_read(ndev, IDT_SW_SESTS);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Clean the Link Up/Down and Global Signal status registers */
70762306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SELINKUPSTS, (u32)-1);
70862306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SELINKDNSTS, (u32)-1);
70962306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)-1);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/* Clean the corresponding interrupt bit */
71262306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_SEVENT);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "SE IRQ detected %#08x (SESTS %#08x)",
71562306a36Sopenharmony_ci			  ntint_sts, sests);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* Notify the client driver of possible link state change */
71862306a36Sopenharmony_ci	ntb_link_event(&ndev->ntb);
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/*
72262306a36Sopenharmony_ci * idt_ntb_local_link_enable() - enable the local NTB link.
72362306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
72462306a36Sopenharmony_ci *
72562306a36Sopenharmony_ci * In order to enable the NTB link we need:
72662306a36Sopenharmony_ci * - enable Completion TLPs translation
72762306a36Sopenharmony_ci * - initialize mapping table to enable the Request ID translation
72862306a36Sopenharmony_ci * - notify peers of NTB link state change
72962306a36Sopenharmony_ci */
73062306a36Sopenharmony_cistatic void idt_ntb_local_link_enable(struct idt_ntb_dev *ndev)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	u32 reqid, mtbldata = 0;
73362306a36Sopenharmony_ci	unsigned long irqflags;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* Enable the ID protection and Completion TLPs translation */
73662306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTCTL, IDT_NTCTL_CPEN);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	/* Retrieve the current Requester ID (Bus:Device:Function) */
73962306a36Sopenharmony_ci	reqid = idt_nt_read(ndev, IDT_NT_REQIDCAP);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/*
74262306a36Sopenharmony_ci	 * Set the corresponding NT Mapping table entry of port partition index
74362306a36Sopenharmony_ci	 * with the data to perform the Request ID translation
74462306a36Sopenharmony_ci	 */
74562306a36Sopenharmony_ci	mtbldata = SET_FIELD(NTMTBLDATA_REQID, 0, reqid) |
74662306a36Sopenharmony_ci		   SET_FIELD(NTMTBLDATA_PART, 0, ndev->part) |
74762306a36Sopenharmony_ci		   IDT_NTMTBLDATA_VALID;
74862306a36Sopenharmony_ci	spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
74962306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part);
75062306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTMTBLDATA, mtbldata);
75162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	/* Notify the peers by setting and clearing the global signal bit */
75462306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTGSIGNAL, IDT_NTGSIGNAL_SET);
75562306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)1 << ndev->part);
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci/*
75962306a36Sopenharmony_ci * idt_ntb_local_link_disable() - disable the local NTB link.
76062306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
76162306a36Sopenharmony_ci *
76262306a36Sopenharmony_ci * In order to enable the NTB link we need:
76362306a36Sopenharmony_ci * - disable Completion TLPs translation
76462306a36Sopenharmony_ci * - clear corresponding mapping table entry
76562306a36Sopenharmony_ci * - notify peers of NTB link state change
76662306a36Sopenharmony_ci */
76762306a36Sopenharmony_cistatic void idt_ntb_local_link_disable(struct idt_ntb_dev *ndev)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	unsigned long irqflags;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	/* Disable Completion TLPs translation */
77262306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTCTL, 0);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* Clear the corresponding NT Mapping table entry */
77562306a36Sopenharmony_ci	spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
77662306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part);
77762306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTMTBLDATA, 0);
77862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* Notify the peers by setting and clearing the global signal bit */
78162306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTGSIGNAL, IDT_NTGSIGNAL_SET);
78262306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_SEGSIGSTS, (u32)1 << ndev->part);
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci/*
78662306a36Sopenharmony_ci * idt_ntb_local_link_is_up() - test wethter local NTB link is up
78762306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
78862306a36Sopenharmony_ci *
78962306a36Sopenharmony_ci * Local link is up under the following conditions:
79062306a36Sopenharmony_ci * - Bus mastering is enabled
79162306a36Sopenharmony_ci * - NTCTL has Completion TLPs translation enabled
79262306a36Sopenharmony_ci * - Mapping table permits Request TLPs translation
79362306a36Sopenharmony_ci * NOTE: We don't need to check PCIe link state since it's obviously
79462306a36Sopenharmony_ci * up while we are able to communicate with IDT PCIe-switch
79562306a36Sopenharmony_ci *
79662306a36Sopenharmony_ci * Return: true if link is up, otherwise false
79762306a36Sopenharmony_ci */
79862306a36Sopenharmony_cistatic bool idt_ntb_local_link_is_up(struct idt_ntb_dev *ndev)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	unsigned long irqflags;
80162306a36Sopenharmony_ci	u32 data;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/* Read the local Bus Master Enable status */
80462306a36Sopenharmony_ci	data = idt_nt_read(ndev, IDT_NT_PCICMDSTS);
80562306a36Sopenharmony_ci	if (!(data & IDT_PCICMDSTS_BME))
80662306a36Sopenharmony_ci		return false;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/* Read the local Completion TLPs translation enable status */
80962306a36Sopenharmony_ci	data = idt_nt_read(ndev, IDT_NT_NTCTL);
81062306a36Sopenharmony_ci	if (!(data & IDT_NTCTL_CPEN))
81162306a36Sopenharmony_ci		return false;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	/* Read Mapping table entry corresponding to the local partition */
81462306a36Sopenharmony_ci	spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
81562306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->part);
81662306a36Sopenharmony_ci	data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA);
81762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return !!(data & IDT_NTMTBLDATA_VALID);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci/*
82362306a36Sopenharmony_ci * idt_ntb_peer_link_is_up() - test whether peer NTB link is up
82462306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
82562306a36Sopenharmony_ci * @pidx:	Peer port index
82662306a36Sopenharmony_ci *
82762306a36Sopenharmony_ci * Peer link is up under the following conditions:
82862306a36Sopenharmony_ci * - PCIe link is up
82962306a36Sopenharmony_ci * - Bus mastering is enabled
83062306a36Sopenharmony_ci * - NTCTL has Completion TLPs translation enabled
83162306a36Sopenharmony_ci * - Mapping table permits Request TLPs translation
83262306a36Sopenharmony_ci *
83362306a36Sopenharmony_ci * Return: true if link is up, otherwise false
83462306a36Sopenharmony_ci */
83562306a36Sopenharmony_cistatic bool idt_ntb_peer_link_is_up(struct idt_ntb_dev *ndev, int pidx)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	unsigned long irqflags;
83862306a36Sopenharmony_ci	unsigned char port;
83962306a36Sopenharmony_ci	u32 data;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	/* Retrieve the device port number */
84262306a36Sopenharmony_ci	port = ndev->peers[pidx].port;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	/* Check whether PCIe link is up */
84562306a36Sopenharmony_ci	data = idt_sw_read(ndev, portdata_tbl[port].sts);
84662306a36Sopenharmony_ci	if (!(data & IDT_SWPORTxSTS_LINKUP))
84762306a36Sopenharmony_ci		return false;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* Check whether bus mastering is enabled on the peer port */
85062306a36Sopenharmony_ci	data = idt_sw_read(ndev, portdata_tbl[port].pcicmdsts);
85162306a36Sopenharmony_ci	if (!(data & IDT_PCICMDSTS_BME))
85262306a36Sopenharmony_ci		return false;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	/* Check if Completion TLPs translation is enabled on the peer port */
85562306a36Sopenharmony_ci	data = idt_sw_read(ndev, portdata_tbl[port].ntctl);
85662306a36Sopenharmony_ci	if (!(data & IDT_NTCTL_CPEN))
85762306a36Sopenharmony_ci		return false;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	/* Read Mapping table entry corresponding to the peer partition */
86062306a36Sopenharmony_ci	spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
86162306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTMTBLADDR, ndev->peers[pidx].part);
86262306a36Sopenharmony_ci	data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA);
86362306a36Sopenharmony_ci	spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	return !!(data & IDT_NTMTBLDATA_VALID);
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci/*
86962306a36Sopenharmony_ci * idt_ntb_link_is_up() - get the current ntb link state (NTB API callback)
87062306a36Sopenharmony_ci * @ntb:	NTB device context.
87162306a36Sopenharmony_ci * @speed:	OUT - The link speed expressed as PCIe generation number.
87262306a36Sopenharmony_ci * @width:	OUT - The link width expressed as the number of PCIe lanes.
87362306a36Sopenharmony_ci *
87462306a36Sopenharmony_ci * Get the bitfield of NTB link states for all peer ports
87562306a36Sopenharmony_ci *
87662306a36Sopenharmony_ci * Return: bitfield of indexed ports link state: bit is set/cleared if the
87762306a36Sopenharmony_ci *         link is up/down respectively.
87862306a36Sopenharmony_ci */
87962306a36Sopenharmony_cistatic u64 idt_ntb_link_is_up(struct ntb_dev *ntb,
88062306a36Sopenharmony_ci			      enum ntb_speed *speed, enum ntb_width *width)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
88362306a36Sopenharmony_ci	unsigned char pidx;
88462306a36Sopenharmony_ci	u64 status;
88562306a36Sopenharmony_ci	u32 data;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Retrieve the local link speed and width */
88862306a36Sopenharmony_ci	if (speed != NULL || width != NULL) {
88962306a36Sopenharmony_ci		data = idt_nt_read(ndev, IDT_NT_PCIELCTLSTS);
89062306a36Sopenharmony_ci		if (speed != NULL)
89162306a36Sopenharmony_ci			*speed = GET_FIELD(PCIELCTLSTS_CLS, data);
89262306a36Sopenharmony_ci		if (width != NULL)
89362306a36Sopenharmony_ci			*width = GET_FIELD(PCIELCTLSTS_NLW, data);
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/* If local NTB link isn't up then all the links are considered down */
89762306a36Sopenharmony_ci	if (!idt_ntb_local_link_is_up(ndev))
89862306a36Sopenharmony_ci		return 0;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	/* Collect all the peer ports link states into the bitfield */
90162306a36Sopenharmony_ci	status = 0;
90262306a36Sopenharmony_ci	for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
90362306a36Sopenharmony_ci		if (idt_ntb_peer_link_is_up(ndev, pidx))
90462306a36Sopenharmony_ci			status |= ((u64)1 << pidx);
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	return status;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci/*
91162306a36Sopenharmony_ci * idt_ntb_link_enable() - enable local port ntb link (NTB API callback)
91262306a36Sopenharmony_ci * @ntb:	NTB device context.
91362306a36Sopenharmony_ci * @max_speed:	The maximum link speed expressed as PCIe generation number.
91462306a36Sopenharmony_ci * @max_width:	The maximum link width expressed as the number of PCIe lanes.
91562306a36Sopenharmony_ci *
91662306a36Sopenharmony_ci * Enable just local NTB link. PCIe link parameters are ignored.
91762306a36Sopenharmony_ci *
91862306a36Sopenharmony_ci * Return: always zero.
91962306a36Sopenharmony_ci */
92062306a36Sopenharmony_cistatic int idt_ntb_link_enable(struct ntb_dev *ntb, enum ntb_speed speed,
92162306a36Sopenharmony_ci			       enum ntb_width width)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* Just enable the local NTB link */
92662306a36Sopenharmony_ci	idt_ntb_local_link_enable(ndev);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "Local NTB link enabled");
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	return 0;
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci/*
93462306a36Sopenharmony_ci * idt_ntb_link_disable() - disable local port ntb link (NTB API callback)
93562306a36Sopenharmony_ci * @ntb:	NTB device context.
93662306a36Sopenharmony_ci *
93762306a36Sopenharmony_ci * Disable just local NTB link.
93862306a36Sopenharmony_ci *
93962306a36Sopenharmony_ci * Return: always zero.
94062306a36Sopenharmony_ci */
94162306a36Sopenharmony_cistatic int idt_ntb_link_disable(struct ntb_dev *ntb)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	/* Just disable the local NTB link */
94662306a36Sopenharmony_ci	idt_ntb_local_link_disable(ndev);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "Local NTB link disabled");
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return 0;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci/*=============================================================================
95462306a36Sopenharmony_ci *                         4. Memory Window operations
95562306a36Sopenharmony_ci *
95662306a36Sopenharmony_ci *    IDT PCIe-switches have two types of memory windows: MWs with direct
95762306a36Sopenharmony_ci * address translation and MWs with LUT based translation. The first type of
95862306a36Sopenharmony_ci * MWs is simple map of corresponding BAR address space to a memory space
95962306a36Sopenharmony_ci * of specified target port. So it implemets just ont-to-one mapping. Lookup
96062306a36Sopenharmony_ci * table in its turn can map one BAR address space to up to 24 different
96162306a36Sopenharmony_ci * memory spaces of different ports.
96262306a36Sopenharmony_ci *    NT-functions BARs can be turned on to implement either direct or lookup
96362306a36Sopenharmony_ci * table based address translations, so:
96462306a36Sopenharmony_ci * BAR0 - NT configuration registers space/direct address translation
96562306a36Sopenharmony_ci * BAR1 - direct address translation/upper address of BAR0x64
96662306a36Sopenharmony_ci * BAR2 - direct address translation/Lookup table with either 12 or 24 entries
96762306a36Sopenharmony_ci * BAR3 - direct address translation/upper address of BAR2x64
96862306a36Sopenharmony_ci * BAR4 - direct address translation/Lookup table with either 12 or 24 entries
96962306a36Sopenharmony_ci * BAR5 - direct address translation/upper address of BAR4x64
97062306a36Sopenharmony_ci *    Additionally BAR2 and BAR4 can't have 24-entries LUT enabled at the same
97162306a36Sopenharmony_ci * time. Since the BARs setup can be rather complicated this driver implements
97262306a36Sopenharmony_ci * a scanning algorithm to have all the possible memory windows configuration
97362306a36Sopenharmony_ci * covered.
97462306a36Sopenharmony_ci *
97562306a36Sopenharmony_ci * NOTE 1 BAR setup must be done before Linux kernel enumerated NT-function
97662306a36Sopenharmony_ci * of any port, so this driver would have memory windows configurations fixed.
97762306a36Sopenharmony_ci * In this way all initializations must be performed either by platform BIOS
97862306a36Sopenharmony_ci * or using EEPROM connected to IDT PCIe-switch master SMBus.
97962306a36Sopenharmony_ci *
98062306a36Sopenharmony_ci * NOTE 2 This driver expects BAR0 mapping NT-function configuration space.
98162306a36Sopenharmony_ci * Easy calculation can give us an upper boundary of 29 possible memory windows
98262306a36Sopenharmony_ci * per each NT-function if all the BARs are of 32bit type.
98362306a36Sopenharmony_ci *=============================================================================
98462306a36Sopenharmony_ci */
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci/*
98762306a36Sopenharmony_ci * idt_get_mw_count() - get memory window count
98862306a36Sopenharmony_ci * @mw_type:	Memory window type
98962306a36Sopenharmony_ci *
99062306a36Sopenharmony_ci * Return: number of memory windows with respect to the BAR type
99162306a36Sopenharmony_ci */
99262306a36Sopenharmony_cistatic inline unsigned char idt_get_mw_count(enum idt_mw_type mw_type)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	switch (mw_type) {
99562306a36Sopenharmony_ci	case IDT_MW_DIR:
99662306a36Sopenharmony_ci		return 1;
99762306a36Sopenharmony_ci	case IDT_MW_LUT12:
99862306a36Sopenharmony_ci		return 12;
99962306a36Sopenharmony_ci	case IDT_MW_LUT24:
100062306a36Sopenharmony_ci		return 24;
100162306a36Sopenharmony_ci	default:
100262306a36Sopenharmony_ci		break;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	return 0;
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci/*
100962306a36Sopenharmony_ci * idt_get_mw_name() - get memory window name
101062306a36Sopenharmony_ci * @mw_type:	Memory window type
101162306a36Sopenharmony_ci *
101262306a36Sopenharmony_ci * Return: pointer to a string with name
101362306a36Sopenharmony_ci */
101462306a36Sopenharmony_cistatic inline char *idt_get_mw_name(enum idt_mw_type mw_type)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	switch (mw_type) {
101762306a36Sopenharmony_ci	case IDT_MW_DIR:
101862306a36Sopenharmony_ci		return "DIR  ";
101962306a36Sopenharmony_ci	case IDT_MW_LUT12:
102062306a36Sopenharmony_ci		return "LUT12";
102162306a36Sopenharmony_ci	case IDT_MW_LUT24:
102262306a36Sopenharmony_ci		return "LUT24";
102362306a36Sopenharmony_ci	default:
102462306a36Sopenharmony_ci		break;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return "unknown";
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci/*
103162306a36Sopenharmony_ci * idt_scan_mws() - scan memory windows of the port
103262306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
103362306a36Sopenharmony_ci * @port:	Port to get number of memory windows for
103462306a36Sopenharmony_ci * @mw_cnt:	Out - number of memory windows
103562306a36Sopenharmony_ci *
103662306a36Sopenharmony_ci * It walks over BAR setup registers of the specified port and determines
103762306a36Sopenharmony_ci * the memory windows parameters if any activated.
103862306a36Sopenharmony_ci *
103962306a36Sopenharmony_ci * Return: array of memory windows
104062306a36Sopenharmony_ci */
104162306a36Sopenharmony_cistatic struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port,
104262306a36Sopenharmony_ci				       unsigned char *mw_cnt)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	struct idt_mw_cfg mws[IDT_MAX_NR_MWS], *ret_mws;
104562306a36Sopenharmony_ci	const struct idt_ntb_bar *bars;
104662306a36Sopenharmony_ci	enum idt_mw_type mw_type;
104762306a36Sopenharmony_ci	unsigned char widx, bidx, en_cnt;
104862306a36Sopenharmony_ci	bool bar_64bit = false;
104962306a36Sopenharmony_ci	int aprt_size;
105062306a36Sopenharmony_ci	u32 data;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	/* Retrieve the array of the BARs registers */
105362306a36Sopenharmony_ci	bars = portdata_tbl[port].bars;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* Scan all the BARs belonging to the port */
105662306a36Sopenharmony_ci	*mw_cnt = 0;
105762306a36Sopenharmony_ci	for (bidx = 0; bidx < IDT_BAR_CNT; bidx += 1 + bar_64bit) {
105862306a36Sopenharmony_ci		/* Read BARSETUP register value */
105962306a36Sopenharmony_ci		data = idt_sw_read(ndev, bars[bidx].setup);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci		/* Skip disabled BARs */
106262306a36Sopenharmony_ci		if (!(data & IDT_BARSETUP_EN)) {
106362306a36Sopenharmony_ci			bar_64bit = false;
106462306a36Sopenharmony_ci			continue;
106562306a36Sopenharmony_ci		}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		/* Skip next BARSETUP if current one has 64bit addressing */
106862306a36Sopenharmony_ci		bar_64bit = IS_FLD_SET(BARSETUP_TYPE, data, 64);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci		/* Skip configuration space mapping BARs */
107162306a36Sopenharmony_ci		if (data & IDT_BARSETUP_MODE_CFG)
107262306a36Sopenharmony_ci			continue;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci		/* Retrieve MW type/entries count and aperture size */
107562306a36Sopenharmony_ci		mw_type = GET_FIELD(BARSETUP_ATRAN, data);
107662306a36Sopenharmony_ci		en_cnt = idt_get_mw_count(mw_type);
107762306a36Sopenharmony_ci		aprt_size = (u64)1 << GET_FIELD(BARSETUP_SIZE, data);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		/* Save configurations of all available memory windows */
108062306a36Sopenharmony_ci		for (widx = 0; widx < en_cnt; widx++, (*mw_cnt)++) {
108162306a36Sopenharmony_ci			/*
108262306a36Sopenharmony_ci			 * IDT can expose a limited number of MWs, so it's bug
108362306a36Sopenharmony_ci			 * to have more than the driver expects
108462306a36Sopenharmony_ci			 */
108562306a36Sopenharmony_ci			if (*mw_cnt >= IDT_MAX_NR_MWS)
108662306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci			/* Save basic MW info */
108962306a36Sopenharmony_ci			mws[*mw_cnt].type = mw_type;
109062306a36Sopenharmony_ci			mws[*mw_cnt].bar = bidx;
109162306a36Sopenharmony_ci			mws[*mw_cnt].idx = widx;
109262306a36Sopenharmony_ci			/* It's always DWORD aligned */
109362306a36Sopenharmony_ci			mws[*mw_cnt].addr_align = IDT_TRANS_ALIGN;
109462306a36Sopenharmony_ci			/* DIR and LUT approachs differently configure MWs */
109562306a36Sopenharmony_ci			if (mw_type == IDT_MW_DIR)
109662306a36Sopenharmony_ci				mws[*mw_cnt].size_max = aprt_size;
109762306a36Sopenharmony_ci			else if (mw_type == IDT_MW_LUT12)
109862306a36Sopenharmony_ci				mws[*mw_cnt].size_max = aprt_size / 16;
109962306a36Sopenharmony_ci			else
110062306a36Sopenharmony_ci				mws[*mw_cnt].size_max = aprt_size / 32;
110162306a36Sopenharmony_ci			mws[*mw_cnt].size_align = (mw_type == IDT_MW_DIR) ?
110262306a36Sopenharmony_ci				IDT_DIR_SIZE_ALIGN : mws[*mw_cnt].size_max;
110362306a36Sopenharmony_ci		}
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	/* Allocate memory for memory window descriptors */
110762306a36Sopenharmony_ci	ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws),
110862306a36Sopenharmony_ci			       GFP_KERNEL);
110962306a36Sopenharmony_ci	if (!ret_mws)
111062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/* Copy the info of detected memory windows */
111362306a36Sopenharmony_ci	memcpy(ret_mws, mws, (*mw_cnt)*sizeof(*ret_mws));
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	return ret_mws;
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci/*
111962306a36Sopenharmony_ci * idt_init_mws() - initialize memory windows subsystem
112062306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
112162306a36Sopenharmony_ci *
112262306a36Sopenharmony_ci * Scan BAR setup registers of local and peer ports to determine the
112362306a36Sopenharmony_ci * outbound and inbound memory windows parameters
112462306a36Sopenharmony_ci *
112562306a36Sopenharmony_ci * Return: zero on success, otherwise a negative error number
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_cistatic int idt_init_mws(struct idt_ntb_dev *ndev)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	struct idt_ntb_peer *peer;
113062306a36Sopenharmony_ci	unsigned char pidx;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	/* Scan memory windows of the local port */
113362306a36Sopenharmony_ci	ndev->mws = idt_scan_mws(ndev, ndev->port, &ndev->mw_cnt);
113462306a36Sopenharmony_ci	if (IS_ERR(ndev->mws)) {
113562306a36Sopenharmony_ci		dev_err(&ndev->ntb.pdev->dev,
113662306a36Sopenharmony_ci			"Failed to scan mws of local port %hhu", ndev->port);
113762306a36Sopenharmony_ci		return PTR_ERR(ndev->mws);
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/* Scan memory windows of the peer ports */
114162306a36Sopenharmony_ci	for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
114262306a36Sopenharmony_ci		peer = &ndev->peers[pidx];
114362306a36Sopenharmony_ci		peer->mws = idt_scan_mws(ndev, peer->port, &peer->mw_cnt);
114462306a36Sopenharmony_ci		if (IS_ERR(peer->mws)) {
114562306a36Sopenharmony_ci			dev_err(&ndev->ntb.pdev->dev,
114662306a36Sopenharmony_ci				"Failed to scan mws of port %hhu", peer->port);
114762306a36Sopenharmony_ci			return PTR_ERR(peer->mws);
114862306a36Sopenharmony_ci		}
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	/* Initialize spin locker of the LUT registers */
115262306a36Sopenharmony_ci	spin_lock_init(&ndev->lut_lock);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "Outbound and inbound MWs initialized");
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	return 0;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci/*
116062306a36Sopenharmony_ci * idt_ntb_mw_count() - number of inbound memory windows (NTB API callback)
116162306a36Sopenharmony_ci * @ntb:	NTB device context.
116262306a36Sopenharmony_ci * @pidx:	Port index of peer device.
116362306a36Sopenharmony_ci *
116462306a36Sopenharmony_ci * The value is returned for the specified peer, so generally speaking it can
116562306a36Sopenharmony_ci * be different for different port depending on the IDT PCIe-switch
116662306a36Sopenharmony_ci * initialization.
116762306a36Sopenharmony_ci *
116862306a36Sopenharmony_ci * Return: the number of memory windows.
116962306a36Sopenharmony_ci */
117062306a36Sopenharmony_cistatic int idt_ntb_mw_count(struct ntb_dev *ntb, int pidx)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	if (pidx < 0 || ndev->peer_cnt <= pidx)
117562306a36Sopenharmony_ci		return -EINVAL;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	return ndev->peers[pidx].mw_cnt;
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci/*
118162306a36Sopenharmony_ci * idt_ntb_mw_get_align() - inbound memory window parameters (NTB API callback)
118262306a36Sopenharmony_ci * @ntb:	NTB device context.
118362306a36Sopenharmony_ci * @pidx:	Port index of peer device.
118462306a36Sopenharmony_ci * @widx:	Memory window index.
118562306a36Sopenharmony_ci * @addr_align:	OUT - the base alignment for translating the memory window
118662306a36Sopenharmony_ci * @size_align:	OUT - the size alignment for translating the memory window
118762306a36Sopenharmony_ci * @size_max:	OUT - the maximum size of the memory window
118862306a36Sopenharmony_ci *
118962306a36Sopenharmony_ci * The peer memory window parameters have already been determined, so just
119062306a36Sopenharmony_ci * return the corresponding values, which mustn't change within session.
119162306a36Sopenharmony_ci *
119262306a36Sopenharmony_ci * Return: Zero on success, otherwise a negative error number.
119362306a36Sopenharmony_ci */
119462306a36Sopenharmony_cistatic int idt_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
119562306a36Sopenharmony_ci				resource_size_t *addr_align,
119662306a36Sopenharmony_ci				resource_size_t *size_align,
119762306a36Sopenharmony_ci				resource_size_t *size_max)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
120062306a36Sopenharmony_ci	struct idt_ntb_peer *peer;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	if (pidx < 0 || ndev->peer_cnt <= pidx)
120362306a36Sopenharmony_ci		return -EINVAL;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	peer = &ndev->peers[pidx];
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (widx < 0 || peer->mw_cnt <= widx)
120862306a36Sopenharmony_ci		return -EINVAL;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (addr_align != NULL)
121162306a36Sopenharmony_ci		*addr_align = peer->mws[widx].addr_align;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (size_align != NULL)
121462306a36Sopenharmony_ci		*size_align = peer->mws[widx].size_align;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	if (size_max != NULL)
121762306a36Sopenharmony_ci		*size_max = peer->mws[widx].size_max;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return 0;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci/*
122362306a36Sopenharmony_ci * idt_ntb_peer_mw_count() - number of outbound memory windows
122462306a36Sopenharmony_ci *			     (NTB API callback)
122562306a36Sopenharmony_ci * @ntb:	NTB device context.
122662306a36Sopenharmony_ci *
122762306a36Sopenharmony_ci * Outbound memory windows parameters have been determined based on the
122862306a36Sopenharmony_ci * BAR setup registers value, which are mostly constants within one session.
122962306a36Sopenharmony_ci *
123062306a36Sopenharmony_ci * Return: the number of memory windows.
123162306a36Sopenharmony_ci */
123262306a36Sopenharmony_cistatic int idt_ntb_peer_mw_count(struct ntb_dev *ntb)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	return ndev->mw_cnt;
123762306a36Sopenharmony_ci}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci/*
124062306a36Sopenharmony_ci * idt_ntb_peer_mw_get_addr() - get map address of an outbound memory window
124162306a36Sopenharmony_ci *				(NTB API callback)
124262306a36Sopenharmony_ci * @ntb:	NTB device context.
124362306a36Sopenharmony_ci * @widx:	Memory window index (within ntb_peer_mw_count() return value).
124462306a36Sopenharmony_ci * @base:	OUT - the base address of mapping region.
124562306a36Sopenharmony_ci * @size:	OUT - the size of mapping region.
124662306a36Sopenharmony_ci *
124762306a36Sopenharmony_ci * Return just parameters of BAR resources mapping. Size reflects just the size
124862306a36Sopenharmony_ci * of the resource
124962306a36Sopenharmony_ci *
125062306a36Sopenharmony_ci * Return: Zero on success, otherwise a negative error number.
125162306a36Sopenharmony_ci */
125262306a36Sopenharmony_cistatic int idt_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
125362306a36Sopenharmony_ci				    phys_addr_t *base, resource_size_t *size)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	if (widx < 0 || ndev->mw_cnt <= widx)
125862306a36Sopenharmony_ci		return -EINVAL;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/* Mapping address is just properly shifted BAR resource start */
126162306a36Sopenharmony_ci	if (base != NULL)
126262306a36Sopenharmony_ci		*base = pci_resource_start(ntb->pdev, ndev->mws[widx].bar) +
126362306a36Sopenharmony_ci			ndev->mws[widx].idx * ndev->mws[widx].size_max;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	/* Mapping size has already been calculated at MWs scanning */
126662306a36Sopenharmony_ci	if (size != NULL)
126762306a36Sopenharmony_ci		*size = ndev->mws[widx].size_max;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	return 0;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci/*
127362306a36Sopenharmony_ci * idt_ntb_peer_mw_set_trans() - set a translation address of a memory window
127462306a36Sopenharmony_ci *				 (NTB API callback)
127562306a36Sopenharmony_ci * @ntb:	NTB device context.
127662306a36Sopenharmony_ci * @pidx:	Port index of peer device the translation address received from.
127762306a36Sopenharmony_ci * @widx:	Memory window index.
127862306a36Sopenharmony_ci * @addr:	The dma address of the shared memory to access.
127962306a36Sopenharmony_ci * @size:	The size of the shared memory to access.
128062306a36Sopenharmony_ci *
128162306a36Sopenharmony_ci * The Direct address translation and LUT base translation is initialized a
128262306a36Sopenharmony_ci * bit differenet. Although the parameters restriction are now determined by
128362306a36Sopenharmony_ci * the same code.
128462306a36Sopenharmony_ci *
128562306a36Sopenharmony_ci * Return: Zero on success, otherwise an error number.
128662306a36Sopenharmony_ci */
128762306a36Sopenharmony_cistatic int idt_ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
128862306a36Sopenharmony_ci				     u64 addr, resource_size_t size)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
129162306a36Sopenharmony_ci	struct idt_mw_cfg *mw_cfg;
129262306a36Sopenharmony_ci	u32 data = 0, lutoff = 0;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	if (pidx < 0 || ndev->peer_cnt <= pidx)
129562306a36Sopenharmony_ci		return -EINVAL;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	if (widx < 0 || ndev->mw_cnt <= widx)
129862306a36Sopenharmony_ci		return -EINVAL;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	/*
130162306a36Sopenharmony_ci	 * Retrieve the memory window config to make sure the passed arguments
130262306a36Sopenharmony_ci	 * fit it restrictions
130362306a36Sopenharmony_ci	 */
130462306a36Sopenharmony_ci	mw_cfg = &ndev->mws[widx];
130562306a36Sopenharmony_ci	if (!IS_ALIGNED(addr, mw_cfg->addr_align))
130662306a36Sopenharmony_ci		return -EINVAL;
130762306a36Sopenharmony_ci	if (!IS_ALIGNED(size, mw_cfg->size_align) || size > mw_cfg->size_max)
130862306a36Sopenharmony_ci		return -EINVAL;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	/* DIR and LUT based translations are initialized differently */
131162306a36Sopenharmony_ci	if (mw_cfg->type == IDT_MW_DIR) {
131262306a36Sopenharmony_ci		const struct idt_ntb_bar *bar = &ntdata_tbl.bars[mw_cfg->bar];
131362306a36Sopenharmony_ci		u64 limit;
131462306a36Sopenharmony_ci		/* Set destination partition of translation */
131562306a36Sopenharmony_ci		data = idt_nt_read(ndev, bar->setup);
131662306a36Sopenharmony_ci		data = SET_FIELD(BARSETUP_TPART, data, ndev->peers[pidx].part);
131762306a36Sopenharmony_ci		idt_nt_write(ndev, bar->setup, data);
131862306a36Sopenharmony_ci		/* Set translation base address */
131962306a36Sopenharmony_ci		idt_nt_write(ndev, bar->ltbase, (u32)addr);
132062306a36Sopenharmony_ci		idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32));
132162306a36Sopenharmony_ci		/* Set the custom BAR aperture limit */
132262306a36Sopenharmony_ci		limit = pci_bus_address(ntb->pdev, mw_cfg->bar) + size;
132362306a36Sopenharmony_ci		idt_nt_write(ndev, bar->limit, (u32)limit);
132462306a36Sopenharmony_ci		if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
132562306a36Sopenharmony_ci			idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32));
132662306a36Sopenharmony_ci	} else {
132762306a36Sopenharmony_ci		unsigned long irqflags;
132862306a36Sopenharmony_ci		/* Initialize corresponding LUT entry */
132962306a36Sopenharmony_ci		lutoff = SET_FIELD(LUTOFFSET_INDEX, 0, mw_cfg->idx) |
133062306a36Sopenharmony_ci			 SET_FIELD(LUTOFFSET_BAR, 0, mw_cfg->bar);
133162306a36Sopenharmony_ci		data = SET_FIELD(LUTUDATA_PART, 0, ndev->peers[pidx].part) |
133262306a36Sopenharmony_ci			IDT_LUTUDATA_VALID;
133362306a36Sopenharmony_ci		spin_lock_irqsave(&ndev->lut_lock, irqflags);
133462306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTOFFSET, lutoff);
133562306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTLDATA, (u32)addr);
133662306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTMDATA, (u32)(addr >> 32));
133762306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTUDATA, data);
133862306a36Sopenharmony_ci		spin_unlock_irqrestore(&ndev->lut_lock, irqflags);
133962306a36Sopenharmony_ci		/* Limit address isn't specified since size is fixed for LUT */
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	return 0;
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci/*
134662306a36Sopenharmony_ci * idt_ntb_peer_mw_clear_trans() - clear the outbound MW translation address
134762306a36Sopenharmony_ci *				   (NTB API callback)
134862306a36Sopenharmony_ci * @ntb:	NTB device context.
134962306a36Sopenharmony_ci * @pidx:	Port index of peer device.
135062306a36Sopenharmony_ci * @widx:	Memory window index.
135162306a36Sopenharmony_ci *
135262306a36Sopenharmony_ci * It effectively disables the translation over the specified outbound MW.
135362306a36Sopenharmony_ci *
135462306a36Sopenharmony_ci * Return: Zero on success, otherwise an error number.
135562306a36Sopenharmony_ci */
135662306a36Sopenharmony_cistatic int idt_ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
135762306a36Sopenharmony_ci					int widx)
135862306a36Sopenharmony_ci{
135962306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
136062306a36Sopenharmony_ci	struct idt_mw_cfg *mw_cfg;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	if (pidx < 0 || ndev->peer_cnt <= pidx)
136362306a36Sopenharmony_ci		return -EINVAL;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if (widx < 0 || ndev->mw_cnt <= widx)
136662306a36Sopenharmony_ci		return -EINVAL;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	mw_cfg = &ndev->mws[widx];
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	/* DIR and LUT based translations are initialized differently */
137162306a36Sopenharmony_ci	if (mw_cfg->type == IDT_MW_DIR) {
137262306a36Sopenharmony_ci		const struct idt_ntb_bar *bar = &ntdata_tbl.bars[mw_cfg->bar];
137362306a36Sopenharmony_ci		u32 data;
137462306a36Sopenharmony_ci		/* Read BARSETUP to check BAR type */
137562306a36Sopenharmony_ci		data = idt_nt_read(ndev, bar->setup);
137662306a36Sopenharmony_ci		/* Disable translation by specifying zero BAR limit */
137762306a36Sopenharmony_ci		idt_nt_write(ndev, bar->limit, 0);
137862306a36Sopenharmony_ci		if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
137962306a36Sopenharmony_ci			idt_nt_write(ndev, (bar + 1)->limit, 0);
138062306a36Sopenharmony_ci	} else {
138162306a36Sopenharmony_ci		unsigned long irqflags;
138262306a36Sopenharmony_ci		u32 lutoff;
138362306a36Sopenharmony_ci		/* Clear the corresponding LUT entry up */
138462306a36Sopenharmony_ci		lutoff = SET_FIELD(LUTOFFSET_INDEX, 0, mw_cfg->idx) |
138562306a36Sopenharmony_ci			 SET_FIELD(LUTOFFSET_BAR, 0, mw_cfg->bar);
138662306a36Sopenharmony_ci		spin_lock_irqsave(&ndev->lut_lock, irqflags);
138762306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTOFFSET, lutoff);
138862306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTLDATA, 0);
138962306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTMDATA, 0);
139062306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_LUTUDATA, 0);
139162306a36Sopenharmony_ci		spin_unlock_irqrestore(&ndev->lut_lock, irqflags);
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	return 0;
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci/*=============================================================================
139862306a36Sopenharmony_ci *                          5. Doorbell operations
139962306a36Sopenharmony_ci *
140062306a36Sopenharmony_ci *    Doorbell functionality of IDT PCIe-switches is pretty unusual. First of
140162306a36Sopenharmony_ci * all there is global doorbell register which state can be changed by any
140262306a36Sopenharmony_ci * NT-function of the IDT device in accordance with global permissions. These
140362306a36Sopenharmony_ci * permissions configs are not supported by NTB API, so it must be done by
140462306a36Sopenharmony_ci * either BIOS or EEPROM settings. In the same way the state of the global
140562306a36Sopenharmony_ci * doorbell is reflected to the NT-functions local inbound doorbell registers.
140662306a36Sopenharmony_ci * It can lead to situations when client driver sets some peer doorbell bits
140762306a36Sopenharmony_ci * and get them bounced back to local inbound doorbell if permissions are
140862306a36Sopenharmony_ci * granted.
140962306a36Sopenharmony_ci *    Secondly there is just one IRQ vector for Doorbell, Message, Temperature
141062306a36Sopenharmony_ci * and Switch events, so if client driver left any of Doorbell bits set and
141162306a36Sopenharmony_ci * some other event occurred, the driver will be notified of Doorbell event
141262306a36Sopenharmony_ci * again.
141362306a36Sopenharmony_ci *=============================================================================
141462306a36Sopenharmony_ci */
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci/*
141762306a36Sopenharmony_ci * idt_db_isr() - doorbell event ISR
141862306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
141962306a36Sopenharmony_ci * @ntint_sts:	NT-function interrupt status
142062306a36Sopenharmony_ci *
142162306a36Sopenharmony_ci * Doorbell event happans when DBELL bit of NTINTSTS switches from 0 to 1.
142262306a36Sopenharmony_ci * It happens only when unmasked doorbell bits are set to ones on completely
142362306a36Sopenharmony_ci * zeroed doorbell register.
142462306a36Sopenharmony_ci * The method is called from PCIe ISR bottom-half routine.
142562306a36Sopenharmony_ci */
142662306a36Sopenharmony_cistatic void idt_db_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
142762306a36Sopenharmony_ci{
142862306a36Sopenharmony_ci	/*
142962306a36Sopenharmony_ci	 * Doorbell IRQ status will be cleaned only when client
143062306a36Sopenharmony_ci	 * driver unsets all the doorbell bits.
143162306a36Sopenharmony_ci	 */
143262306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "DB IRQ detected %#08x", ntint_sts);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	/* Notify the client driver of possible doorbell state change */
143562306a36Sopenharmony_ci	ntb_db_event(&ndev->ntb, 0);
143662306a36Sopenharmony_ci}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci/*
143962306a36Sopenharmony_ci * idt_ntb_db_valid_mask() - get a mask of doorbell bits supported by the ntb
144062306a36Sopenharmony_ci *			     (NTB API callback)
144162306a36Sopenharmony_ci * @ntb:	NTB device context.
144262306a36Sopenharmony_ci *
144362306a36Sopenharmony_ci * IDT PCIe-switches expose just one Doorbell register of DWORD size.
144462306a36Sopenharmony_ci *
144562306a36Sopenharmony_ci * Return: A mask of doorbell bits supported by the ntb.
144662306a36Sopenharmony_ci */
144762306a36Sopenharmony_cistatic u64 idt_ntb_db_valid_mask(struct ntb_dev *ntb)
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	return IDT_DBELL_MASK;
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci/*
145362306a36Sopenharmony_ci * idt_ntb_db_read() - read the local doorbell register (NTB API callback)
145462306a36Sopenharmony_ci * @ntb:	NTB device context.
145562306a36Sopenharmony_ci *
145662306a36Sopenharmony_ci * There is just on inbound doorbell register of each NT-function, so
145762306a36Sopenharmony_ci * this method return it value.
145862306a36Sopenharmony_ci *
145962306a36Sopenharmony_ci * Return: The bits currently set in the local doorbell register.
146062306a36Sopenharmony_ci */
146162306a36Sopenharmony_cistatic u64 idt_ntb_db_read(struct ntb_dev *ntb)
146262306a36Sopenharmony_ci{
146362306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	return idt_nt_read(ndev, IDT_NT_INDBELLSTS);
146662306a36Sopenharmony_ci}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci/*
146962306a36Sopenharmony_ci * idt_ntb_db_clear() - clear bits in the local doorbell register
147062306a36Sopenharmony_ci *			(NTB API callback)
147162306a36Sopenharmony_ci * @ntb:	NTB device context.
147262306a36Sopenharmony_ci * @db_bits:	Doorbell bits to clear.
147362306a36Sopenharmony_ci *
147462306a36Sopenharmony_ci * Clear bits of inbound doorbell register by writing ones to it.
147562306a36Sopenharmony_ci *
147662306a36Sopenharmony_ci * NOTE! Invalid bits are always considered cleared so it's not an error
147762306a36Sopenharmony_ci * to clear them over.
147862306a36Sopenharmony_ci *
147962306a36Sopenharmony_ci * Return: always zero as success.
148062306a36Sopenharmony_ci */
148162306a36Sopenharmony_cistatic int idt_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
148262306a36Sopenharmony_ci{
148362306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_INDBELLSTS, (u32)db_bits);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return 0;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci/*
149162306a36Sopenharmony_ci * idt_ntb_db_read_mask() - read the local doorbell mask (NTB API callback)
149262306a36Sopenharmony_ci * @ntb:	NTB device context.
149362306a36Sopenharmony_ci *
149462306a36Sopenharmony_ci * Each inbound doorbell bit can be masked from generating IRQ by setting
149562306a36Sopenharmony_ci * the corresponding bit in inbound doorbell mask. So this method returns
149662306a36Sopenharmony_ci * the value of the register.
149762306a36Sopenharmony_ci *
149862306a36Sopenharmony_ci * Return: The bits currently set in the local doorbell mask register.
149962306a36Sopenharmony_ci */
150062306a36Sopenharmony_cistatic u64 idt_ntb_db_read_mask(struct ntb_dev *ntb)
150162306a36Sopenharmony_ci{
150262306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	return idt_nt_read(ndev, IDT_NT_INDBELLMSK);
150562306a36Sopenharmony_ci}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci/*
150862306a36Sopenharmony_ci * idt_ntb_db_set_mask() - set bits in the local doorbell mask
150962306a36Sopenharmony_ci *			   (NTB API callback)
151062306a36Sopenharmony_ci * @ntb:	NTB device context.
151162306a36Sopenharmony_ci * @db_bits:	Doorbell mask bits to set.
151262306a36Sopenharmony_ci *
151362306a36Sopenharmony_ci * The inbound doorbell register mask value must be read, then OR'ed with
151462306a36Sopenharmony_ci * passed field and only then set back.
151562306a36Sopenharmony_ci *
151662306a36Sopenharmony_ci * Return: zero on success, negative error if invalid argument passed.
151762306a36Sopenharmony_ci */
151862306a36Sopenharmony_cistatic int idt_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	return idt_reg_set_bits(ndev, IDT_NT_INDBELLMSK, &ndev->db_mask_lock,
152362306a36Sopenharmony_ci				IDT_DBELL_MASK, db_bits);
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci/*
152762306a36Sopenharmony_ci * idt_ntb_db_clear_mask() - clear bits in the local doorbell mask
152862306a36Sopenharmony_ci *			     (NTB API callback)
152962306a36Sopenharmony_ci * @ntb:	NTB device context.
153062306a36Sopenharmony_ci * @db_bits:	Doorbell bits to clear.
153162306a36Sopenharmony_ci *
153262306a36Sopenharmony_ci * The method just clears the set bits up in accordance with the passed
153362306a36Sopenharmony_ci * bitfield. IDT PCIe-switch shall generate an interrupt if there hasn't
153462306a36Sopenharmony_ci * been any unmasked bit set before current unmasking. Otherwise IRQ won't
153562306a36Sopenharmony_ci * be generated since there is only one IRQ vector for all doorbells.
153662306a36Sopenharmony_ci *
153762306a36Sopenharmony_ci * Return: always zero as success
153862306a36Sopenharmony_ci */
153962306a36Sopenharmony_cistatic int idt_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	idt_reg_clear_bits(ndev, IDT_NT_INDBELLMSK, &ndev->db_mask_lock,
154462306a36Sopenharmony_ci			   db_bits);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	return 0;
154762306a36Sopenharmony_ci}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci/*
155062306a36Sopenharmony_ci * idt_ntb_peer_db_set() - set bits in the peer doorbell register
155162306a36Sopenharmony_ci *			   (NTB API callback)
155262306a36Sopenharmony_ci * @ntb:	NTB device context.
155362306a36Sopenharmony_ci * @db_bits:	Doorbell bits to set.
155462306a36Sopenharmony_ci *
155562306a36Sopenharmony_ci * IDT PCIe-switches exposes local outbound doorbell register to change peer
155662306a36Sopenharmony_ci * inbound doorbell register state.
155762306a36Sopenharmony_ci *
155862306a36Sopenharmony_ci * Return: zero on success, negative error if invalid argument passed.
155962306a36Sopenharmony_ci */
156062306a36Sopenharmony_cistatic int idt_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	if (db_bits & ~(u64)IDT_DBELL_MASK)
156562306a36Sopenharmony_ci		return -EINVAL;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_OUTDBELLSET, (u32)db_bits);
156862306a36Sopenharmony_ci	return 0;
156962306a36Sopenharmony_ci}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci/*=============================================================================
157262306a36Sopenharmony_ci *                          6. Messaging operations
157362306a36Sopenharmony_ci *
157462306a36Sopenharmony_ci *    Each NT-function of IDT PCIe-switch has four inbound and four outbound
157562306a36Sopenharmony_ci * message registers. Each outbound message register can be connected to one or
157662306a36Sopenharmony_ci * even more than one peer inbound message registers by setting global
157762306a36Sopenharmony_ci * configurations. Since NTB API permits one-on-one message registers mapping
157862306a36Sopenharmony_ci * only, the driver acts in according with that restriction.
157962306a36Sopenharmony_ci *=============================================================================
158062306a36Sopenharmony_ci */
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci/*
158362306a36Sopenharmony_ci * idt_init_msg() - initialize messaging interface
158462306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
158562306a36Sopenharmony_ci *
158662306a36Sopenharmony_ci * Just initialize the message registers routing tables locker.
158762306a36Sopenharmony_ci */
158862306a36Sopenharmony_cistatic void idt_init_msg(struct idt_ntb_dev *ndev)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	unsigned char midx;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	/* Init the messages routing table lockers */
159362306a36Sopenharmony_ci	for (midx = 0; midx < IDT_MSG_CNT; midx++)
159462306a36Sopenharmony_ci		spin_lock_init(&ndev->msg_locks[midx]);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "NTB Messaging initialized");
159762306a36Sopenharmony_ci}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci/*
160062306a36Sopenharmony_ci * idt_msg_isr() - message event ISR
160162306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
160262306a36Sopenharmony_ci * @ntint_sts:	NT-function interrupt status
160362306a36Sopenharmony_ci *
160462306a36Sopenharmony_ci * Message event happens when MSG bit of NTINTSTS switches from 0 to 1.
160562306a36Sopenharmony_ci * It happens only when unmasked message status bits are set to ones on
160662306a36Sopenharmony_ci * completely zeroed message status register.
160762306a36Sopenharmony_ci * The method is called from PCIe ISR bottom-half routine.
160862306a36Sopenharmony_ci */
160962306a36Sopenharmony_cistatic void idt_msg_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
161062306a36Sopenharmony_ci{
161162306a36Sopenharmony_ci	/*
161262306a36Sopenharmony_ci	 * Message IRQ status will be cleaned only when client
161362306a36Sopenharmony_ci	 * driver unsets all the message status bits.
161462306a36Sopenharmony_ci	 */
161562306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "Message IRQ detected %#08x", ntint_sts);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	/* Notify the client driver of possible message status change */
161862306a36Sopenharmony_ci	ntb_msg_event(&ndev->ntb);
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci/*
162262306a36Sopenharmony_ci * idt_ntb_msg_count() - get the number of message registers (NTB API callback)
162362306a36Sopenharmony_ci * @ntb:	NTB device context.
162462306a36Sopenharmony_ci *
162562306a36Sopenharmony_ci * IDT PCIe-switches support four message registers.
162662306a36Sopenharmony_ci *
162762306a36Sopenharmony_ci * Return: the number of message registers.
162862306a36Sopenharmony_ci */
162962306a36Sopenharmony_cistatic int idt_ntb_msg_count(struct ntb_dev *ntb)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	return IDT_MSG_CNT;
163262306a36Sopenharmony_ci}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci/*
163562306a36Sopenharmony_ci * idt_ntb_msg_inbits() - get a bitfield of inbound message registers status
163662306a36Sopenharmony_ci *			  (NTB API callback)
163762306a36Sopenharmony_ci * @ntb:	NTB device context.
163862306a36Sopenharmony_ci *
163962306a36Sopenharmony_ci * NT message status register is shared between inbound and outbound message
164062306a36Sopenharmony_ci * registers status
164162306a36Sopenharmony_ci *
164262306a36Sopenharmony_ci * Return: bitfield of inbound message registers.
164362306a36Sopenharmony_ci */
164462306a36Sopenharmony_cistatic u64 idt_ntb_msg_inbits(struct ntb_dev *ntb)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	return (u64)IDT_INMSG_MASK;
164762306a36Sopenharmony_ci}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci/*
165062306a36Sopenharmony_ci * idt_ntb_msg_outbits() - get a bitfield of outbound message registers status
165162306a36Sopenharmony_ci *			  (NTB API callback)
165262306a36Sopenharmony_ci * @ntb:	NTB device context.
165362306a36Sopenharmony_ci *
165462306a36Sopenharmony_ci * NT message status register is shared between inbound and outbound message
165562306a36Sopenharmony_ci * registers status
165662306a36Sopenharmony_ci *
165762306a36Sopenharmony_ci * Return: bitfield of outbound message registers.
165862306a36Sopenharmony_ci */
165962306a36Sopenharmony_cistatic u64 idt_ntb_msg_outbits(struct ntb_dev *ntb)
166062306a36Sopenharmony_ci{
166162306a36Sopenharmony_ci	return (u64)IDT_OUTMSG_MASK;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci/*
166562306a36Sopenharmony_ci * idt_ntb_msg_read_sts() - read the message registers status (NTB API callback)
166662306a36Sopenharmony_ci * @ntb:	NTB device context.
166762306a36Sopenharmony_ci *
166862306a36Sopenharmony_ci * IDT PCIe-switches expose message status registers to notify drivers of
166962306a36Sopenharmony_ci * incoming data and failures in case if peer message register isn't freed.
167062306a36Sopenharmony_ci *
167162306a36Sopenharmony_ci * Return: status bits of message registers
167262306a36Sopenharmony_ci */
167362306a36Sopenharmony_cistatic u64 idt_ntb_msg_read_sts(struct ntb_dev *ntb)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	return idt_nt_read(ndev, IDT_NT_MSGSTS);
167862306a36Sopenharmony_ci}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci/*
168162306a36Sopenharmony_ci * idt_ntb_msg_clear_sts() - clear status bits of message registers
168262306a36Sopenharmony_ci *			     (NTB API callback)
168362306a36Sopenharmony_ci * @ntb:	NTB device context.
168462306a36Sopenharmony_ci * @sts_bits:	Status bits to clear.
168562306a36Sopenharmony_ci *
168662306a36Sopenharmony_ci * Clear bits in the status register by writing ones.
168762306a36Sopenharmony_ci *
168862306a36Sopenharmony_ci * NOTE! Invalid bits are always considered cleared so it's not an error
168962306a36Sopenharmony_ci * to clear them over.
169062306a36Sopenharmony_ci *
169162306a36Sopenharmony_ci * Return: always zero as success.
169262306a36Sopenharmony_ci */
169362306a36Sopenharmony_cistatic int idt_ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits)
169462306a36Sopenharmony_ci{
169562306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_MSGSTS, sts_bits);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	return 0;
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci/*
170362306a36Sopenharmony_ci * idt_ntb_msg_set_mask() - set mask of message register status bits
170462306a36Sopenharmony_ci *			    (NTB API callback)
170562306a36Sopenharmony_ci * @ntb:	NTB device context.
170662306a36Sopenharmony_ci * @mask_bits:	Mask bits.
170762306a36Sopenharmony_ci *
170862306a36Sopenharmony_ci * Mask the message status bits from raising an IRQ.
170962306a36Sopenharmony_ci *
171062306a36Sopenharmony_ci * Return: zero on success, negative error if invalid argument passed.
171162306a36Sopenharmony_ci */
171262306a36Sopenharmony_cistatic int idt_ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	return idt_reg_set_bits(ndev, IDT_NT_MSGSTSMSK, &ndev->msg_mask_lock,
171762306a36Sopenharmony_ci				IDT_MSG_MASK, mask_bits);
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci/*
172162306a36Sopenharmony_ci * idt_ntb_msg_clear_mask() - clear message registers mask
172262306a36Sopenharmony_ci *			      (NTB API callback)
172362306a36Sopenharmony_ci * @ntb:	NTB device context.
172462306a36Sopenharmony_ci * @mask_bits:	Mask bits.
172562306a36Sopenharmony_ci *
172662306a36Sopenharmony_ci * Clear mask of message status bits IRQs.
172762306a36Sopenharmony_ci *
172862306a36Sopenharmony_ci * Return: always zero as success.
172962306a36Sopenharmony_ci */
173062306a36Sopenharmony_cistatic int idt_ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits)
173162306a36Sopenharmony_ci{
173262306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	idt_reg_clear_bits(ndev, IDT_NT_MSGSTSMSK, &ndev->msg_mask_lock,
173562306a36Sopenharmony_ci			   mask_bits);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	return 0;
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci/*
174162306a36Sopenharmony_ci * idt_ntb_msg_read() - read message register with specified index
174262306a36Sopenharmony_ci *			(NTB API callback)
174362306a36Sopenharmony_ci * @ntb:	NTB device context.
174462306a36Sopenharmony_ci * @pidx:	OUT - Port index of peer device a message retrieved from
174562306a36Sopenharmony_ci * @midx:	Message register index
174662306a36Sopenharmony_ci *
174762306a36Sopenharmony_ci * Read data from the specified message register and source register.
174862306a36Sopenharmony_ci *
174962306a36Sopenharmony_ci * Return: inbound message register value.
175062306a36Sopenharmony_ci */
175162306a36Sopenharmony_cistatic u32 idt_ntb_msg_read(struct ntb_dev *ntb, int *pidx, int midx)
175262306a36Sopenharmony_ci{
175362306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	if (midx < 0 || IDT_MSG_CNT <= midx)
175662306a36Sopenharmony_ci		return ~(u32)0;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	/* Retrieve source port index of the message */
175962306a36Sopenharmony_ci	if (pidx != NULL) {
176062306a36Sopenharmony_ci		u32 srcpart;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci		srcpart = idt_nt_read(ndev, ntdata_tbl.msgs[midx].src);
176362306a36Sopenharmony_ci		*pidx = ndev->part_idx_map[srcpart];
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci		/* Sanity check partition index (for initial case) */
176662306a36Sopenharmony_ci		if (*pidx == -EINVAL)
176762306a36Sopenharmony_ci			*pidx = 0;
176862306a36Sopenharmony_ci	}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	/* Retrieve data of the corresponding message register */
177162306a36Sopenharmony_ci	return idt_nt_read(ndev, ntdata_tbl.msgs[midx].in);
177262306a36Sopenharmony_ci}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci/*
177562306a36Sopenharmony_ci * idt_ntb_peer_msg_write() - write data to the specified message register
177662306a36Sopenharmony_ci *			      (NTB API callback)
177762306a36Sopenharmony_ci * @ntb:	NTB device context.
177862306a36Sopenharmony_ci * @pidx:	Port index of peer device a message being sent to
177962306a36Sopenharmony_ci * @midx:	Message register index
178062306a36Sopenharmony_ci * @msg:	Data to send
178162306a36Sopenharmony_ci *
178262306a36Sopenharmony_ci * Just try to send data to a peer. Message status register should be
178362306a36Sopenharmony_ci * checked by client driver.
178462306a36Sopenharmony_ci *
178562306a36Sopenharmony_ci * Return: zero on success, negative error if invalid argument passed.
178662306a36Sopenharmony_ci */
178762306a36Sopenharmony_cistatic int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
178862306a36Sopenharmony_ci				  u32 msg)
178962306a36Sopenharmony_ci{
179062306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
179162306a36Sopenharmony_ci	unsigned long irqflags;
179262306a36Sopenharmony_ci	u32 swpmsgctl = 0;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (midx < 0 || IDT_MSG_CNT <= midx)
179562306a36Sopenharmony_ci		return -EINVAL;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	if (pidx < 0 || ndev->peer_cnt <= pidx)
179862306a36Sopenharmony_ci		return -EINVAL;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	/* Collect the routing information */
180162306a36Sopenharmony_ci	swpmsgctl = SET_FIELD(SWPxMSGCTL_REG, 0, midx) |
180262306a36Sopenharmony_ci		    SET_FIELD(SWPxMSGCTL_PART, 0, ndev->peers[pidx].part);
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	/* Lock the messages routing table of the specified register */
180562306a36Sopenharmony_ci	spin_lock_irqsave(&ndev->msg_locks[midx], irqflags);
180662306a36Sopenharmony_ci	/* Set the route and send the data */
180762306a36Sopenharmony_ci	idt_sw_write(ndev, partdata_tbl[ndev->part].msgctl[midx], swpmsgctl);
180862306a36Sopenharmony_ci	idt_nt_write(ndev, ntdata_tbl.msgs[midx].out, msg);
180962306a36Sopenharmony_ci	/* Unlock the messages routing table */
181062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ndev->msg_locks[midx], irqflags);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	/* Client driver shall check the status register */
181362306a36Sopenharmony_ci	return 0;
181462306a36Sopenharmony_ci}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci/*=============================================================================
181762306a36Sopenharmony_ci *                      7. Temperature sensor operations
181862306a36Sopenharmony_ci *
181962306a36Sopenharmony_ci *    IDT PCIe-switch has an embedded temperature sensor, which can be used to
182062306a36Sopenharmony_ci * check current chip core temperature. Since a workload environment can be
182162306a36Sopenharmony_ci * different on different platforms, an offset and ADC/filter settings can be
182262306a36Sopenharmony_ci * specified. Although the offset configuration is only exposed to the sysfs
182362306a36Sopenharmony_ci * hwmon interface at the moment. The rest of the settings can be adjusted
182462306a36Sopenharmony_ci * for instance by the BIOS/EEPROM firmware.
182562306a36Sopenharmony_ci *=============================================================================
182662306a36Sopenharmony_ci */
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci/*
182962306a36Sopenharmony_ci * idt_get_deg() - convert millidegree Celsius value to just degree
183062306a36Sopenharmony_ci * @mdegC:	IN - millidegree Celsius value
183162306a36Sopenharmony_ci *
183262306a36Sopenharmony_ci * Return: Degree corresponding to the passed millidegree value
183362306a36Sopenharmony_ci */
183462306a36Sopenharmony_cistatic inline s8 idt_get_deg(long mdegC)
183562306a36Sopenharmony_ci{
183662306a36Sopenharmony_ci	return mdegC / 1000;
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci/*
184062306a36Sopenharmony_ci * idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value
184162306a36Sopenharmony_ci * @mdegC:	IN - millidegree Celsius value
184262306a36Sopenharmony_ci *
184362306a36Sopenharmony_ci * Return: 0/0.5 degree fraction of the passed millidegree value
184462306a36Sopenharmony_ci */
184562306a36Sopenharmony_cistatic inline u8 idt_get_deg_frac(long mdegC)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	return (mdegC % 1000) >= 500 ? 5 : 0;
184862306a36Sopenharmony_ci}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci/*
185162306a36Sopenharmony_ci * idt_get_temp_fmt() - convert millidegree Celsius value to 0:7:1 format
185262306a36Sopenharmony_ci * @mdegC:	IN - millidegree Celsius value
185362306a36Sopenharmony_ci *
185462306a36Sopenharmony_ci * Return: 0:7:1 format acceptable by the IDT temperature sensor
185562306a36Sopenharmony_ci */
185662306a36Sopenharmony_cistatic inline u8 idt_temp_get_fmt(long mdegC)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	return (idt_get_deg(mdegC) << 1) | (idt_get_deg_frac(mdegC) ? 1 : 0);
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci/*
186262306a36Sopenharmony_ci * idt_get_temp_sval() - convert temp sample to signed millidegree Celsius
186362306a36Sopenharmony_ci * @data:	IN - shifted to LSB 8-bits temperature sample
186462306a36Sopenharmony_ci *
186562306a36Sopenharmony_ci * Return: signed millidegree Celsius
186662306a36Sopenharmony_ci */
186762306a36Sopenharmony_cistatic inline long idt_get_temp_sval(u32 data)
186862306a36Sopenharmony_ci{
186962306a36Sopenharmony_ci	return ((s8)data / 2) * 1000 + (data & 0x1 ? 500 : 0);
187062306a36Sopenharmony_ci}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci/*
187362306a36Sopenharmony_ci * idt_get_temp_sval() - convert temp sample to unsigned millidegree Celsius
187462306a36Sopenharmony_ci * @data:	IN - shifted to LSB 8-bits temperature sample
187562306a36Sopenharmony_ci *
187662306a36Sopenharmony_ci * Return: unsigned millidegree Celsius
187762306a36Sopenharmony_ci */
187862306a36Sopenharmony_cistatic inline long idt_get_temp_uval(u32 data)
187962306a36Sopenharmony_ci{
188062306a36Sopenharmony_ci	return (data / 2) * 1000 + (data & 0x1 ? 500 : 0);
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci/*
188462306a36Sopenharmony_ci * idt_read_temp() - read temperature from chip sensor
188562306a36Sopenharmony_ci * @ntb:	NTB device context.
188662306a36Sopenharmony_ci * @type:	IN - type of the temperature value to read
188762306a36Sopenharmony_ci * @val:	OUT - integer value of temperature in millidegree Celsius
188862306a36Sopenharmony_ci */
188962306a36Sopenharmony_cistatic void idt_read_temp(struct idt_ntb_dev *ndev,
189062306a36Sopenharmony_ci			  const enum idt_temp_val type, long *val)
189162306a36Sopenharmony_ci{
189262306a36Sopenharmony_ci	u32 data;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	/* Alter the temperature field in accordance with the passed type */
189562306a36Sopenharmony_ci	switch (type) {
189662306a36Sopenharmony_ci	case IDT_TEMP_CUR:
189762306a36Sopenharmony_ci		data = GET_FIELD(TMPSTS_TEMP,
189862306a36Sopenharmony_ci				 idt_sw_read(ndev, IDT_SW_TMPSTS));
189962306a36Sopenharmony_ci		break;
190062306a36Sopenharmony_ci	case IDT_TEMP_LOW:
190162306a36Sopenharmony_ci		data = GET_FIELD(TMPSTS_LTEMP,
190262306a36Sopenharmony_ci				 idt_sw_read(ndev, IDT_SW_TMPSTS));
190362306a36Sopenharmony_ci		break;
190462306a36Sopenharmony_ci	case IDT_TEMP_HIGH:
190562306a36Sopenharmony_ci		data = GET_FIELD(TMPSTS_HTEMP,
190662306a36Sopenharmony_ci				 idt_sw_read(ndev, IDT_SW_TMPSTS));
190762306a36Sopenharmony_ci		break;
190862306a36Sopenharmony_ci	case IDT_TEMP_OFFSET:
190962306a36Sopenharmony_ci		/* This is the only field with signed 0:7:1 format */
191062306a36Sopenharmony_ci		data = GET_FIELD(TMPADJ_OFFSET,
191162306a36Sopenharmony_ci				 idt_sw_read(ndev, IDT_SW_TMPADJ));
191262306a36Sopenharmony_ci		*val = idt_get_temp_sval(data);
191362306a36Sopenharmony_ci		return;
191462306a36Sopenharmony_ci	default:
191562306a36Sopenharmony_ci		data = GET_FIELD(TMPSTS_TEMP,
191662306a36Sopenharmony_ci				 idt_sw_read(ndev, IDT_SW_TMPSTS));
191762306a36Sopenharmony_ci		break;
191862306a36Sopenharmony_ci	}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	/* The rest of the fields accept unsigned 0:7:1 format */
192162306a36Sopenharmony_ci	*val = idt_get_temp_uval(data);
192262306a36Sopenharmony_ci}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci/*
192562306a36Sopenharmony_ci * idt_write_temp() - write temperature to the chip sensor register
192662306a36Sopenharmony_ci * @ntb:	NTB device context.
192762306a36Sopenharmony_ci * @type:	IN - type of the temperature value to change
192862306a36Sopenharmony_ci * @val:	IN - integer value of temperature in millidegree Celsius
192962306a36Sopenharmony_ci */
193062306a36Sopenharmony_cistatic void idt_write_temp(struct idt_ntb_dev *ndev,
193162306a36Sopenharmony_ci			   const enum idt_temp_val type, const long val)
193262306a36Sopenharmony_ci{
193362306a36Sopenharmony_ci	unsigned int reg;
193462306a36Sopenharmony_ci	u32 data;
193562306a36Sopenharmony_ci	u8 fmt;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	/* Retrieve the properly formatted temperature value */
193862306a36Sopenharmony_ci	fmt = idt_temp_get_fmt(val);
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	mutex_lock(&ndev->hwmon_mtx);
194162306a36Sopenharmony_ci	switch (type) {
194262306a36Sopenharmony_ci	case IDT_TEMP_LOW:
194362306a36Sopenharmony_ci		reg = IDT_SW_TMPALARM;
194462306a36Sopenharmony_ci		data = SET_FIELD(TMPALARM_LTEMP, idt_sw_read(ndev, reg), fmt) &
194562306a36Sopenharmony_ci			~IDT_TMPALARM_IRQ_MASK;
194662306a36Sopenharmony_ci		break;
194762306a36Sopenharmony_ci	case IDT_TEMP_HIGH:
194862306a36Sopenharmony_ci		reg = IDT_SW_TMPALARM;
194962306a36Sopenharmony_ci		data = SET_FIELD(TMPALARM_HTEMP, idt_sw_read(ndev, reg), fmt) &
195062306a36Sopenharmony_ci			~IDT_TMPALARM_IRQ_MASK;
195162306a36Sopenharmony_ci		break;
195262306a36Sopenharmony_ci	case IDT_TEMP_OFFSET:
195362306a36Sopenharmony_ci		reg = IDT_SW_TMPADJ;
195462306a36Sopenharmony_ci		data = SET_FIELD(TMPADJ_OFFSET, idt_sw_read(ndev, reg), fmt);
195562306a36Sopenharmony_ci		break;
195662306a36Sopenharmony_ci	default:
195762306a36Sopenharmony_ci		goto inval_spin_unlock;
195862306a36Sopenharmony_ci	}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	idt_sw_write(ndev, reg, data);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ciinval_spin_unlock:
196362306a36Sopenharmony_ci	mutex_unlock(&ndev->hwmon_mtx);
196462306a36Sopenharmony_ci}
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci/*
196762306a36Sopenharmony_ci * idt_sysfs_show_temp() - printout corresponding temperature value
196862306a36Sopenharmony_ci * @dev:	Pointer to the NTB device structure
196962306a36Sopenharmony_ci * @da:		Sensor device attribute structure
197062306a36Sopenharmony_ci * @buf:	Buffer to print temperature out
197162306a36Sopenharmony_ci *
197262306a36Sopenharmony_ci * Return: Number of written symbols or negative error
197362306a36Sopenharmony_ci */
197462306a36Sopenharmony_cistatic ssize_t idt_sysfs_show_temp(struct device *dev,
197562306a36Sopenharmony_ci				   struct device_attribute *da, char *buf)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
197862306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
197962306a36Sopenharmony_ci	enum idt_temp_val type = attr->index;
198062306a36Sopenharmony_ci	long mdeg;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	idt_read_temp(ndev, type, &mdeg);
198362306a36Sopenharmony_ci	return sprintf(buf, "%ld\n", mdeg);
198462306a36Sopenharmony_ci}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci/*
198762306a36Sopenharmony_ci * idt_sysfs_set_temp() - set corresponding temperature value
198862306a36Sopenharmony_ci * @dev:	Pointer to the NTB device structure
198962306a36Sopenharmony_ci * @da:		Sensor device attribute structure
199062306a36Sopenharmony_ci * @buf:	Buffer to print temperature out
199162306a36Sopenharmony_ci * @count:	Size of the passed buffer
199262306a36Sopenharmony_ci *
199362306a36Sopenharmony_ci * Return: Number of written symbols or negative error
199462306a36Sopenharmony_ci */
199562306a36Sopenharmony_cistatic ssize_t idt_sysfs_set_temp(struct device *dev,
199662306a36Sopenharmony_ci				  struct device_attribute *da, const char *buf,
199762306a36Sopenharmony_ci				  size_t count)
199862306a36Sopenharmony_ci{
199962306a36Sopenharmony_ci	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
200062306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
200162306a36Sopenharmony_ci	enum idt_temp_val type = attr->index;
200262306a36Sopenharmony_ci	long mdeg;
200362306a36Sopenharmony_ci	int ret;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	ret = kstrtol(buf, 10, &mdeg);
200662306a36Sopenharmony_ci	if (ret)
200762306a36Sopenharmony_ci		return ret;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	/* Clamp the passed value in accordance with the type */
201062306a36Sopenharmony_ci	if (type == IDT_TEMP_OFFSET)
201162306a36Sopenharmony_ci		mdeg = clamp_val(mdeg, IDT_TEMP_MIN_OFFSET,
201262306a36Sopenharmony_ci				 IDT_TEMP_MAX_OFFSET);
201362306a36Sopenharmony_ci	else
201462306a36Sopenharmony_ci		mdeg = clamp_val(mdeg, IDT_TEMP_MIN_MDEG, IDT_TEMP_MAX_MDEG);
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	idt_write_temp(ndev, type, mdeg);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	return count;
201962306a36Sopenharmony_ci}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci/*
202262306a36Sopenharmony_ci * idt_sysfs_reset_hist() - reset temperature history
202362306a36Sopenharmony_ci * @dev:	Pointer to the NTB device structure
202462306a36Sopenharmony_ci * @da:		Sensor device attribute structure
202562306a36Sopenharmony_ci * @buf:	Buffer to print temperature out
202662306a36Sopenharmony_ci * @count:	Size of the passed buffer
202762306a36Sopenharmony_ci *
202862306a36Sopenharmony_ci * Return: Number of written symbols or negative error
202962306a36Sopenharmony_ci */
203062306a36Sopenharmony_cistatic ssize_t idt_sysfs_reset_hist(struct device *dev,
203162306a36Sopenharmony_ci				    struct device_attribute *da,
203262306a36Sopenharmony_ci				    const char *buf, size_t count)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	/* Just set the maximal value to the lowest temperature field and
203762306a36Sopenharmony_ci	 * minimal value to the highest temperature field
203862306a36Sopenharmony_ci	 */
203962306a36Sopenharmony_ci	idt_write_temp(ndev, IDT_TEMP_LOW, IDT_TEMP_MAX_MDEG);
204062306a36Sopenharmony_ci	idt_write_temp(ndev, IDT_TEMP_HIGH, IDT_TEMP_MIN_MDEG);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	return count;
204362306a36Sopenharmony_ci}
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci/*
204662306a36Sopenharmony_ci * Hwmon IDT sysfs attributes
204762306a36Sopenharmony_ci */
204862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_input, 0444, idt_sysfs_show_temp, NULL,
204962306a36Sopenharmony_ci			  IDT_TEMP_CUR);
205062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_lowest, 0444, idt_sysfs_show_temp, NULL,
205162306a36Sopenharmony_ci			  IDT_TEMP_LOW);
205262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_highest, 0444, idt_sysfs_show_temp, NULL,
205362306a36Sopenharmony_ci			  IDT_TEMP_HIGH);
205462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_offset, 0644, idt_sysfs_show_temp,
205562306a36Sopenharmony_ci			  idt_sysfs_set_temp, IDT_TEMP_OFFSET);
205662306a36Sopenharmony_cistatic DEVICE_ATTR(temp1_reset_history, 0200, NULL, idt_sysfs_reset_hist);
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci/*
205962306a36Sopenharmony_ci * Hwmon IDT sysfs attributes group
206062306a36Sopenharmony_ci */
206162306a36Sopenharmony_cistatic struct attribute *idt_temp_attrs[] = {
206262306a36Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
206362306a36Sopenharmony_ci	&sensor_dev_attr_temp1_lowest.dev_attr.attr,
206462306a36Sopenharmony_ci	&sensor_dev_attr_temp1_highest.dev_attr.attr,
206562306a36Sopenharmony_ci	&sensor_dev_attr_temp1_offset.dev_attr.attr,
206662306a36Sopenharmony_ci	&dev_attr_temp1_reset_history.attr,
206762306a36Sopenharmony_ci	NULL
206862306a36Sopenharmony_ci};
206962306a36Sopenharmony_ciATTRIBUTE_GROUPS(idt_temp);
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci/*
207262306a36Sopenharmony_ci * idt_init_temp() - initialize temperature sensor interface
207362306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
207462306a36Sopenharmony_ci *
207562306a36Sopenharmony_ci * Simple sensor initializarion method is responsible for device switching
207662306a36Sopenharmony_ci * on and resource management based hwmon interface registration. Note, that
207762306a36Sopenharmony_ci * since the device is shared we won't disable it on remove, but leave it
207862306a36Sopenharmony_ci * working until the system is powered off.
207962306a36Sopenharmony_ci */
208062306a36Sopenharmony_cistatic void idt_init_temp(struct idt_ntb_dev *ndev)
208162306a36Sopenharmony_ci{
208262306a36Sopenharmony_ci	struct device *hwmon;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	/* Enable sensor if it hasn't been already */
208562306a36Sopenharmony_ci	idt_sw_write(ndev, IDT_SW_TMPCTL, 0x0);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	/* Initialize hwmon interface fields */
208862306a36Sopenharmony_ci	mutex_init(&ndev->hwmon_mtx);
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	hwmon = devm_hwmon_device_register_with_groups(&ndev->ntb.pdev->dev,
209162306a36Sopenharmony_ci		ndev->swcfg->name, ndev, idt_temp_groups);
209262306a36Sopenharmony_ci	if (IS_ERR(hwmon)) {
209362306a36Sopenharmony_ci		dev_err(&ndev->ntb.pdev->dev, "Couldn't create hwmon device");
209462306a36Sopenharmony_ci		return;
209562306a36Sopenharmony_ci	}
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "Temperature HWmon interface registered");
209862306a36Sopenharmony_ci}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci/*=============================================================================
210162306a36Sopenharmony_ci *                           8. ISRs related operations
210262306a36Sopenharmony_ci *
210362306a36Sopenharmony_ci *    IDT PCIe-switch has strangely developed IRQ system. There is just one
210462306a36Sopenharmony_ci * interrupt vector for doorbell and message registers. So the hardware driver
210562306a36Sopenharmony_ci * can't determine actual source of IRQ if, for example, message event happened
210662306a36Sopenharmony_ci * while any of unmasked doorbell is still set. The similar situation may be if
210762306a36Sopenharmony_ci * switch or temperature sensor events pop up. The difference is that SEVENT
210862306a36Sopenharmony_ci * and TMPSENSOR bits of NT interrupt status register can be cleaned by
210962306a36Sopenharmony_ci * IRQ handler so a next interrupt request won't have false handling of
211062306a36Sopenharmony_ci * corresponding events.
211162306a36Sopenharmony_ci *    The hardware driver has only bottom-half handler of the IRQ, since if any
211262306a36Sopenharmony_ci * of events happened the device won't raise it again before the last one is
211362306a36Sopenharmony_ci * handled by clearing of corresponding NTINTSTS bit.
211462306a36Sopenharmony_ci *=============================================================================
211562306a36Sopenharmony_ci */
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_cistatic irqreturn_t idt_thread_isr(int irq, void *devid);
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci/*
212062306a36Sopenharmony_ci * idt_init_isr() - initialize PCIe interrupt handler
212162306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
212262306a36Sopenharmony_ci *
212362306a36Sopenharmony_ci * Return: zero on success, otherwise a negative error number.
212462306a36Sopenharmony_ci */
212562306a36Sopenharmony_cistatic int idt_init_isr(struct idt_ntb_dev *ndev)
212662306a36Sopenharmony_ci{
212762306a36Sopenharmony_ci	struct pci_dev *pdev = ndev->ntb.pdev;
212862306a36Sopenharmony_ci	u32 ntint_mask;
212962306a36Sopenharmony_ci	int ret;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	/* Allocate just one interrupt vector for the ISR */
213262306a36Sopenharmony_ci	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY);
213362306a36Sopenharmony_ci	if (ret != 1) {
213462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to allocate IRQ vector");
213562306a36Sopenharmony_ci		return ret;
213662306a36Sopenharmony_ci	}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	/* Retrieve the IRQ vector */
213962306a36Sopenharmony_ci	ret = pci_irq_vector(pdev, 0);
214062306a36Sopenharmony_ci	if (ret < 0) {
214162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get IRQ vector");
214262306a36Sopenharmony_ci		goto err_free_vectors;
214362306a36Sopenharmony_ci	}
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	/* Set the IRQ handler */
214662306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, ret, NULL, idt_thread_isr,
214762306a36Sopenharmony_ci					IRQF_ONESHOT, NTB_IRQNAME, ndev);
214862306a36Sopenharmony_ci	if (ret != 0) {
214962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to set MSI IRQ handler, %d", ret);
215062306a36Sopenharmony_ci		goto err_free_vectors;
215162306a36Sopenharmony_ci	}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	/* Unmask Message/Doorbell/SE interrupts */
215462306a36Sopenharmony_ci	ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) & ~IDT_NTINTMSK_ALL;
215562306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	/* From now on the interrupts are enabled */
215862306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "NTB interrupts initialized");
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	return 0;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_cierr_free_vectors:
216362306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	return ret;
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci/*
216962306a36Sopenharmony_ci * idt_deinit_ist() - deinitialize PCIe interrupt handler
217062306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
217162306a36Sopenharmony_ci *
217262306a36Sopenharmony_ci * Disable corresponding interrupts and free allocated IRQ vectors.
217362306a36Sopenharmony_ci */
217462306a36Sopenharmony_cistatic void idt_deinit_isr(struct idt_ntb_dev *ndev)
217562306a36Sopenharmony_ci{
217662306a36Sopenharmony_ci	struct pci_dev *pdev = ndev->ntb.pdev;
217762306a36Sopenharmony_ci	u32 ntint_mask;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	/* Mask interrupts back */
218062306a36Sopenharmony_ci	ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) | IDT_NTINTMSK_ALL;
218162306a36Sopenharmony_ci	idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	/* Manually free IRQ otherwise PCI free irq vectors will fail */
218462306a36Sopenharmony_ci	devm_free_irq(&pdev->dev, pci_irq_vector(pdev, 0), ndev);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	/* Free allocated IRQ vectors */
218762306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "NTB interrupts deinitialized");
219062306a36Sopenharmony_ci}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci/*
219362306a36Sopenharmony_ci * idt_thread_isr() - NT function interrupts handler
219462306a36Sopenharmony_ci * @irq:	IRQ number
219562306a36Sopenharmony_ci * @devid:	Custom buffer
219662306a36Sopenharmony_ci *
219762306a36Sopenharmony_ci * It reads current NT interrupts state register and handles all the event
219862306a36Sopenharmony_ci * it declares.
219962306a36Sopenharmony_ci * The method is bottom-half routine of actual default PCIe IRQ handler.
220062306a36Sopenharmony_ci */
220162306a36Sopenharmony_cistatic irqreturn_t idt_thread_isr(int irq, void *devid)
220262306a36Sopenharmony_ci{
220362306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = devid;
220462306a36Sopenharmony_ci	bool handled = false;
220562306a36Sopenharmony_ci	u32 ntint_sts;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	/* Read the NT interrupts status register */
220862306a36Sopenharmony_ci	ntint_sts = idt_nt_read(ndev, IDT_NT_NTINTSTS);
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	/* Handle messaging interrupts */
221162306a36Sopenharmony_ci	if (ntint_sts & IDT_NTINTSTS_MSG) {
221262306a36Sopenharmony_ci		idt_msg_isr(ndev, ntint_sts);
221362306a36Sopenharmony_ci		handled = true;
221462306a36Sopenharmony_ci	}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	/* Handle doorbell interrupts */
221762306a36Sopenharmony_ci	if (ntint_sts & IDT_NTINTSTS_DBELL) {
221862306a36Sopenharmony_ci		idt_db_isr(ndev, ntint_sts);
221962306a36Sopenharmony_ci		handled = true;
222062306a36Sopenharmony_ci	}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	/* Handle switch event interrupts */
222362306a36Sopenharmony_ci	if (ntint_sts & IDT_NTINTSTS_SEVENT) {
222462306a36Sopenharmony_ci		idt_se_isr(ndev, ntint_sts);
222562306a36Sopenharmony_ci		handled = true;
222662306a36Sopenharmony_ci	}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "IDT IRQs 0x%08x handled", ntint_sts);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	return handled ? IRQ_HANDLED : IRQ_NONE;
223162306a36Sopenharmony_ci}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci/*===========================================================================
223462306a36Sopenharmony_ci *                     9. NTB hardware driver initialization
223562306a36Sopenharmony_ci *===========================================================================
223662306a36Sopenharmony_ci */
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci/*
223962306a36Sopenharmony_ci * NTB API operations
224062306a36Sopenharmony_ci */
224162306a36Sopenharmony_cistatic const struct ntb_dev_ops idt_ntb_ops = {
224262306a36Sopenharmony_ci	.port_number		= idt_ntb_port_number,
224362306a36Sopenharmony_ci	.peer_port_count	= idt_ntb_peer_port_count,
224462306a36Sopenharmony_ci	.peer_port_number	= idt_ntb_peer_port_number,
224562306a36Sopenharmony_ci	.peer_port_idx		= idt_ntb_peer_port_idx,
224662306a36Sopenharmony_ci	.link_is_up		= idt_ntb_link_is_up,
224762306a36Sopenharmony_ci	.link_enable		= idt_ntb_link_enable,
224862306a36Sopenharmony_ci	.link_disable		= idt_ntb_link_disable,
224962306a36Sopenharmony_ci	.mw_count		= idt_ntb_mw_count,
225062306a36Sopenharmony_ci	.mw_get_align		= idt_ntb_mw_get_align,
225162306a36Sopenharmony_ci	.peer_mw_count		= idt_ntb_peer_mw_count,
225262306a36Sopenharmony_ci	.peer_mw_get_addr	= idt_ntb_peer_mw_get_addr,
225362306a36Sopenharmony_ci	.peer_mw_set_trans	= idt_ntb_peer_mw_set_trans,
225462306a36Sopenharmony_ci	.peer_mw_clear_trans	= idt_ntb_peer_mw_clear_trans,
225562306a36Sopenharmony_ci	.db_valid_mask		= idt_ntb_db_valid_mask,
225662306a36Sopenharmony_ci	.db_read		= idt_ntb_db_read,
225762306a36Sopenharmony_ci	.db_clear		= idt_ntb_db_clear,
225862306a36Sopenharmony_ci	.db_read_mask		= idt_ntb_db_read_mask,
225962306a36Sopenharmony_ci	.db_set_mask		= idt_ntb_db_set_mask,
226062306a36Sopenharmony_ci	.db_clear_mask		= idt_ntb_db_clear_mask,
226162306a36Sopenharmony_ci	.peer_db_set		= idt_ntb_peer_db_set,
226262306a36Sopenharmony_ci	.msg_count		= idt_ntb_msg_count,
226362306a36Sopenharmony_ci	.msg_inbits		= idt_ntb_msg_inbits,
226462306a36Sopenharmony_ci	.msg_outbits		= idt_ntb_msg_outbits,
226562306a36Sopenharmony_ci	.msg_read_sts		= idt_ntb_msg_read_sts,
226662306a36Sopenharmony_ci	.msg_clear_sts		= idt_ntb_msg_clear_sts,
226762306a36Sopenharmony_ci	.msg_set_mask		= idt_ntb_msg_set_mask,
226862306a36Sopenharmony_ci	.msg_clear_mask		= idt_ntb_msg_clear_mask,
226962306a36Sopenharmony_ci	.msg_read		= idt_ntb_msg_read,
227062306a36Sopenharmony_ci	.peer_msg_write		= idt_ntb_peer_msg_write
227162306a36Sopenharmony_ci};
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci/*
227462306a36Sopenharmony_ci * idt_register_device() - register IDT NTB device
227562306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
227662306a36Sopenharmony_ci *
227762306a36Sopenharmony_ci * Return: zero on success, otherwise a negative error number.
227862306a36Sopenharmony_ci */
227962306a36Sopenharmony_cistatic int idt_register_device(struct idt_ntb_dev *ndev)
228062306a36Sopenharmony_ci{
228162306a36Sopenharmony_ci	int ret;
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	/* Initialize the rest of NTB device structure and register it */
228462306a36Sopenharmony_ci	ndev->ntb.ops = &idt_ntb_ops;
228562306a36Sopenharmony_ci	ndev->ntb.topo = NTB_TOPO_SWITCH;
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	ret = ntb_register_device(&ndev->ntb);
228862306a36Sopenharmony_ci	if (ret != 0) {
228962306a36Sopenharmony_ci		dev_err(&ndev->ntb.pdev->dev, "Failed to register NTB device");
229062306a36Sopenharmony_ci		return ret;
229162306a36Sopenharmony_ci	}
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "NTB device successfully registered");
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	return 0;
229662306a36Sopenharmony_ci}
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci/*
229962306a36Sopenharmony_ci * idt_unregister_device() - unregister IDT NTB device
230062306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
230162306a36Sopenharmony_ci */
230262306a36Sopenharmony_cistatic void idt_unregister_device(struct idt_ntb_dev *ndev)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	/* Just unregister the NTB device */
230562306a36Sopenharmony_ci	ntb_unregister_device(&ndev->ntb);
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "NTB device unregistered");
230862306a36Sopenharmony_ci}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci/*=============================================================================
231162306a36Sopenharmony_ci *                        10. DebugFS node initialization
231262306a36Sopenharmony_ci *=============================================================================
231362306a36Sopenharmony_ci */
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_cistatic ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
231662306a36Sopenharmony_ci				   size_t count, loff_t *offp);
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci/*
231962306a36Sopenharmony_ci * Driver DebugFS info file operations
232062306a36Sopenharmony_ci */
232162306a36Sopenharmony_cistatic const struct file_operations idt_dbgfs_info_ops = {
232262306a36Sopenharmony_ci	.owner = THIS_MODULE,
232362306a36Sopenharmony_ci	.open = simple_open,
232462306a36Sopenharmony_ci	.read = idt_dbgfs_info_read
232562306a36Sopenharmony_ci};
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci/*
232862306a36Sopenharmony_ci * idt_dbgfs_info_read() - DebugFS read info node callback
232962306a36Sopenharmony_ci * @file:	File node descriptor.
233062306a36Sopenharmony_ci * @ubuf:	User-space buffer to put data to
233162306a36Sopenharmony_ci * @count:	Size of the buffer
233262306a36Sopenharmony_ci * @offp:	Offset within the buffer
233362306a36Sopenharmony_ci */
233462306a36Sopenharmony_cistatic ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
233562306a36Sopenharmony_ci				   size_t count, loff_t *offp)
233662306a36Sopenharmony_ci{
233762306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = filp->private_data;
233862306a36Sopenharmony_ci	unsigned char idx, pidx, cnt;
233962306a36Sopenharmony_ci	unsigned long irqflags, mdeg;
234062306a36Sopenharmony_ci	ssize_t ret = 0, off = 0;
234162306a36Sopenharmony_ci	enum ntb_speed speed;
234262306a36Sopenharmony_ci	enum ntb_width width;
234362306a36Sopenharmony_ci	char *strbuf;
234462306a36Sopenharmony_ci	size_t size;
234562306a36Sopenharmony_ci	u32 data;
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	/* Lets limit the buffer size the way the Intel/AMD drivers do */
234862306a36Sopenharmony_ci	size = min_t(size_t, count, 0x1000U);
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	/* Allocate the memory for the buffer */
235162306a36Sopenharmony_ci	strbuf = kmalloc(size, GFP_KERNEL);
235262306a36Sopenharmony_ci	if (strbuf == NULL)
235362306a36Sopenharmony_ci		return -ENOMEM;
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	/* Put the data into the string buffer */
235662306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
235762306a36Sopenharmony_ci		"\n\t\tIDT NTB device Information:\n\n");
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	/* General local device configurations */
236062306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
236162306a36Sopenharmony_ci		"Local Port %hhu, Partition %hhu\n", ndev->port, ndev->part);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	/* Peer ports information */
236462306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off, "Peers:\n");
236562306a36Sopenharmony_ci	for (idx = 0; idx < ndev->peer_cnt; idx++) {
236662306a36Sopenharmony_ci		off += scnprintf(strbuf + off, size - off,
236762306a36Sopenharmony_ci			"\t%hhu. Port %hhu, Partition %hhu\n",
236862306a36Sopenharmony_ci			idx, ndev->peers[idx].port, ndev->peers[idx].part);
236962306a36Sopenharmony_ci	}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	/* Links status */
237262306a36Sopenharmony_ci	data = idt_ntb_link_is_up(&ndev->ntb, &speed, &width);
237362306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
237462306a36Sopenharmony_ci		"NTB link status\t- 0x%08x, ", data);
237562306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off, "PCIe Gen %d x%d lanes\n",
237662306a36Sopenharmony_ci		speed, width);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	/* Mapping table entries */
237962306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off, "NTB Mapping Table:\n");
238062306a36Sopenharmony_ci	for (idx = 0; idx < IDT_MTBL_ENTRY_CNT; idx++) {
238162306a36Sopenharmony_ci		spin_lock_irqsave(&ndev->mtbl_lock, irqflags);
238262306a36Sopenharmony_ci		idt_nt_write(ndev, IDT_NT_NTMTBLADDR, idx);
238362306a36Sopenharmony_ci		data = idt_nt_read(ndev, IDT_NT_NTMTBLDATA);
238462306a36Sopenharmony_ci		spin_unlock_irqrestore(&ndev->mtbl_lock, irqflags);
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci		/* Print valid entries only */
238762306a36Sopenharmony_ci		if (data & IDT_NTMTBLDATA_VALID) {
238862306a36Sopenharmony_ci			off += scnprintf(strbuf + off, size - off,
238962306a36Sopenharmony_ci				"\t%hhu. Partition %d, Requester ID 0x%04x\n",
239062306a36Sopenharmony_ci				idx, GET_FIELD(NTMTBLDATA_PART, data),
239162306a36Sopenharmony_ci				GET_FIELD(NTMTBLDATA_REQID, data));
239262306a36Sopenharmony_ci		}
239362306a36Sopenharmony_ci	}
239462306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off, "\n");
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	/* Outbound memory windows information */
239762306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
239862306a36Sopenharmony_ci		"Outbound Memory Windows:\n");
239962306a36Sopenharmony_ci	for (idx = 0; idx < ndev->mw_cnt; idx += cnt) {
240062306a36Sopenharmony_ci		data = ndev->mws[idx].type;
240162306a36Sopenharmony_ci		cnt = idt_get_mw_count(data);
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci		/* Print Memory Window information */
240462306a36Sopenharmony_ci		if (data == IDT_MW_DIR)
240562306a36Sopenharmony_ci			off += scnprintf(strbuf + off, size - off,
240662306a36Sopenharmony_ci				"\t%hhu.\t", idx);
240762306a36Sopenharmony_ci		else
240862306a36Sopenharmony_ci			off += scnprintf(strbuf + off, size - off,
240962306a36Sopenharmony_ci				"\t%hhu-%d.\t", idx, idx + cnt - 1);
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci		off += scnprintf(strbuf + off, size - off, "%s BAR%hhu, ",
241262306a36Sopenharmony_ci			idt_get_mw_name(data), ndev->mws[idx].bar);
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci		off += scnprintf(strbuf + off, size - off,
241562306a36Sopenharmony_ci			"Address align 0x%08llx, ", ndev->mws[idx].addr_align);
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci		off += scnprintf(strbuf + off, size - off,
241862306a36Sopenharmony_ci			"Size align 0x%08llx, Size max %llu\n",
241962306a36Sopenharmony_ci			ndev->mws[idx].size_align, ndev->mws[idx].size_max);
242062306a36Sopenharmony_ci	}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	/* Inbound memory windows information */
242362306a36Sopenharmony_ci	for (pidx = 0; pidx < ndev->peer_cnt; pidx++) {
242462306a36Sopenharmony_ci		off += scnprintf(strbuf + off, size - off,
242562306a36Sopenharmony_ci			"Inbound Memory Windows for peer %hhu (Port %hhu):\n",
242662306a36Sopenharmony_ci			pidx, ndev->peers[pidx].port);
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci		/* Print Memory Windows information */
242962306a36Sopenharmony_ci		for (idx = 0; idx < ndev->peers[pidx].mw_cnt; idx += cnt) {
243062306a36Sopenharmony_ci			data = ndev->peers[pidx].mws[idx].type;
243162306a36Sopenharmony_ci			cnt = idt_get_mw_count(data);
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci			if (data == IDT_MW_DIR)
243462306a36Sopenharmony_ci				off += scnprintf(strbuf + off, size - off,
243562306a36Sopenharmony_ci					"\t%hhu.\t", idx);
243662306a36Sopenharmony_ci			else
243762306a36Sopenharmony_ci				off += scnprintf(strbuf + off, size - off,
243862306a36Sopenharmony_ci					"\t%hhu-%d.\t", idx, idx + cnt - 1);
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci			off += scnprintf(strbuf + off, size - off,
244162306a36Sopenharmony_ci				"%s BAR%hhu, ", idt_get_mw_name(data),
244262306a36Sopenharmony_ci				ndev->peers[pidx].mws[idx].bar);
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci			off += scnprintf(strbuf + off, size - off,
244562306a36Sopenharmony_ci				"Address align 0x%08llx, ",
244662306a36Sopenharmony_ci				ndev->peers[pidx].mws[idx].addr_align);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci			off += scnprintf(strbuf + off, size - off,
244962306a36Sopenharmony_ci				"Size align 0x%08llx, Size max %llu\n",
245062306a36Sopenharmony_ci				ndev->peers[pidx].mws[idx].size_align,
245162306a36Sopenharmony_ci				ndev->peers[pidx].mws[idx].size_max);
245262306a36Sopenharmony_ci		}
245362306a36Sopenharmony_ci	}
245462306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off, "\n");
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	/* Doorbell information */
245762306a36Sopenharmony_ci	data = idt_sw_read(ndev, IDT_SW_GDBELLSTS);
245862306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
245962306a36Sopenharmony_ci		 "Global Doorbell state\t- 0x%08x\n", data);
246062306a36Sopenharmony_ci	data = idt_ntb_db_read(&ndev->ntb);
246162306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
246262306a36Sopenharmony_ci		 "Local  Doorbell state\t- 0x%08x\n", data);
246362306a36Sopenharmony_ci	data = idt_nt_read(ndev, IDT_NT_INDBELLMSK);
246462306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
246562306a36Sopenharmony_ci		 "Local  Doorbell mask\t- 0x%08x\n", data);
246662306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off, "\n");
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	/* Messaging information */
246962306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
247062306a36Sopenharmony_ci		 "Message event valid\t- 0x%08x\n", IDT_MSG_MASK);
247162306a36Sopenharmony_ci	data = idt_ntb_msg_read_sts(&ndev->ntb);
247262306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
247362306a36Sopenharmony_ci		 "Message event status\t- 0x%08x\n", data);
247462306a36Sopenharmony_ci	data = idt_nt_read(ndev, IDT_NT_MSGSTSMSK);
247562306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
247662306a36Sopenharmony_ci		 "Message event mask\t- 0x%08x\n", data);
247762306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
247862306a36Sopenharmony_ci		 "Message data:\n");
247962306a36Sopenharmony_ci	for (idx = 0; idx < IDT_MSG_CNT; idx++) {
248062306a36Sopenharmony_ci		int src;
248162306a36Sopenharmony_ci		data = idt_ntb_msg_read(&ndev->ntb, &src, idx);
248262306a36Sopenharmony_ci		off += scnprintf(strbuf + off, size - off,
248362306a36Sopenharmony_ci			"\t%hhu. 0x%08x from peer %d (Port %hhu)\n",
248462306a36Sopenharmony_ci			idx, data, src, ndev->peers[src].port);
248562306a36Sopenharmony_ci	}
248662306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off, "\n");
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	/* Current temperature */
248962306a36Sopenharmony_ci	idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
249062306a36Sopenharmony_ci	off += scnprintf(strbuf + off, size - off,
249162306a36Sopenharmony_ci		"Switch temperature\t\t- %hhd.%hhuC\n",
249262306a36Sopenharmony_ci		idt_get_deg(mdeg), idt_get_deg_frac(mdeg));
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	/* Copy the buffer to the User Space */
249562306a36Sopenharmony_ci	ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off);
249662306a36Sopenharmony_ci	kfree(strbuf);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	return ret;
249962306a36Sopenharmony_ci}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci/*
250262306a36Sopenharmony_ci * idt_init_dbgfs() - initialize DebugFS node
250362306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
250462306a36Sopenharmony_ci *
250562306a36Sopenharmony_ci * Return: zero on success, otherwise a negative error number.
250662306a36Sopenharmony_ci */
250762306a36Sopenharmony_cistatic int idt_init_dbgfs(struct idt_ntb_dev *ndev)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci	char devname[64];
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	/* If the top directory is not created then do nothing */
251262306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(dbgfs_topdir)) {
251362306a36Sopenharmony_ci		dev_info(&ndev->ntb.pdev->dev, "Top DebugFS directory absent");
251462306a36Sopenharmony_ci		return PTR_ERR_OR_ZERO(dbgfs_topdir);
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	/* Create the info file node */
251862306a36Sopenharmony_ci	snprintf(devname, 64, "info:%s", pci_name(ndev->ntb.pdev));
251962306a36Sopenharmony_ci	ndev->dbgfs_info = debugfs_create_file(devname, 0400, dbgfs_topdir,
252062306a36Sopenharmony_ci		ndev, &idt_dbgfs_info_ops);
252162306a36Sopenharmony_ci	if (IS_ERR(ndev->dbgfs_info)) {
252262306a36Sopenharmony_ci		dev_dbg(&ndev->ntb.pdev->dev, "Failed to create DebugFS node");
252362306a36Sopenharmony_ci		return PTR_ERR(ndev->dbgfs_info);
252462306a36Sopenharmony_ci	}
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "NTB device DebugFS node created");
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	return 0;
252962306a36Sopenharmony_ci}
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci/*
253262306a36Sopenharmony_ci * idt_deinit_dbgfs() - deinitialize DebugFS node
253362306a36Sopenharmony_ci * @ndev:	IDT NTB hardware driver descriptor
253462306a36Sopenharmony_ci *
253562306a36Sopenharmony_ci * Just discard the info node from DebugFS
253662306a36Sopenharmony_ci */
253762306a36Sopenharmony_cistatic void idt_deinit_dbgfs(struct idt_ntb_dev *ndev)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	debugfs_remove(ndev->dbgfs_info);
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	dev_dbg(&ndev->ntb.pdev->dev, "NTB device DebugFS node discarded");
254262306a36Sopenharmony_ci}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci/*=============================================================================
254562306a36Sopenharmony_ci *                     11. Basic PCIe device initialization
254662306a36Sopenharmony_ci *=============================================================================
254762306a36Sopenharmony_ci */
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci/*
255062306a36Sopenharmony_ci * idt_check_setup() - Check whether the IDT PCIe-swtich is properly
255162306a36Sopenharmony_ci *		       pre-initialized
255262306a36Sopenharmony_ci * @pdev:	Pointer to the PCI device descriptor
255362306a36Sopenharmony_ci *
255462306a36Sopenharmony_ci * Return: zero on success, otherwise a negative error number.
255562306a36Sopenharmony_ci */
255662306a36Sopenharmony_cistatic int idt_check_setup(struct pci_dev *pdev)
255762306a36Sopenharmony_ci{
255862306a36Sopenharmony_ci	u32 data;
255962306a36Sopenharmony_ci	int ret;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	/* Read the BARSETUP0 */
256262306a36Sopenharmony_ci	ret = pci_read_config_dword(pdev, IDT_NT_BARSETUP0, &data);
256362306a36Sopenharmony_ci	if (ret != 0) {
256462306a36Sopenharmony_ci		dev_err(&pdev->dev,
256562306a36Sopenharmony_ci			"Failed to read BARSETUP0 config register");
256662306a36Sopenharmony_ci		return ret;
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	/* Check whether the BAR0 register is enabled to be of config space */
257062306a36Sopenharmony_ci	if (!(data & IDT_BARSETUP_EN) || !(data & IDT_BARSETUP_MODE_CFG)) {
257162306a36Sopenharmony_ci		dev_err(&pdev->dev, "BAR0 doesn't map config space");
257262306a36Sopenharmony_ci		return -EINVAL;
257362306a36Sopenharmony_ci	}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	/* Configuration space BAR0 must have certain size */
257662306a36Sopenharmony_ci	if ((data & IDT_BARSETUP_SIZE_MASK) != IDT_BARSETUP_SIZE_CFG) {
257762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Invalid size of config space");
257862306a36Sopenharmony_ci		return -EINVAL;
257962306a36Sopenharmony_ci	}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "NTB device pre-initialized correctly");
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	return 0;
258462306a36Sopenharmony_ci}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci/*
258762306a36Sopenharmony_ci * Create the IDT PCIe-switch driver descriptor
258862306a36Sopenharmony_ci * @pdev:	Pointer to the PCI device descriptor
258962306a36Sopenharmony_ci * @id:		IDT PCIe-device configuration
259062306a36Sopenharmony_ci *
259162306a36Sopenharmony_ci * It just allocates a memory for IDT PCIe-switch device structure and
259262306a36Sopenharmony_ci * initializes some commonly used fields.
259362306a36Sopenharmony_ci *
259462306a36Sopenharmony_ci * No need of release method, since managed device resource is used for
259562306a36Sopenharmony_ci * memory allocation.
259662306a36Sopenharmony_ci *
259762306a36Sopenharmony_ci * Return: pointer to the descriptor, otherwise a negative error number.
259862306a36Sopenharmony_ci */
259962306a36Sopenharmony_cistatic struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev,
260062306a36Sopenharmony_ci					  const struct pci_device_id *id)
260162306a36Sopenharmony_ci{
260262306a36Sopenharmony_ci	struct idt_ntb_dev *ndev;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	/* Allocate memory for the IDT PCIe-device descriptor */
260562306a36Sopenharmony_ci	ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL);
260662306a36Sopenharmony_ci	if (!ndev) {
260762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Memory allocation failed for descriptor");
260862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
260962306a36Sopenharmony_ci	}
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	/* Save the IDT PCIe-switch ports configuration */
261262306a36Sopenharmony_ci	ndev->swcfg = (struct idt_89hpes_cfg *)id->driver_data;
261362306a36Sopenharmony_ci	/* Save the PCI-device pointer inside the NTB device structure */
261462306a36Sopenharmony_ci	ndev->ntb.pdev = pdev;
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	/* Initialize spin locker of Doorbell, Message and GASA registers */
261762306a36Sopenharmony_ci	spin_lock_init(&ndev->db_mask_lock);
261862306a36Sopenharmony_ci	spin_lock_init(&ndev->msg_mask_lock);
261962306a36Sopenharmony_ci	spin_lock_init(&ndev->gasa_lock);
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	dev_info(&pdev->dev, "IDT %s discovered", ndev->swcfg->name);
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "NTB device descriptor created");
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	return ndev;
262662306a36Sopenharmony_ci}
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci/*
262962306a36Sopenharmony_ci * idt_init_pci() - initialize the basic PCI-related subsystem
263062306a36Sopenharmony_ci * @ndev:	Pointer to the IDT PCIe-switch driver descriptor
263162306a36Sopenharmony_ci *
263262306a36Sopenharmony_ci * Managed device resources will be freed automatically in case of failure or
263362306a36Sopenharmony_ci * driver detachment.
263462306a36Sopenharmony_ci *
263562306a36Sopenharmony_ci * Return: zero on success, otherwise negative error number.
263662306a36Sopenharmony_ci */
263762306a36Sopenharmony_cistatic int idt_init_pci(struct idt_ntb_dev *ndev)
263862306a36Sopenharmony_ci{
263962306a36Sopenharmony_ci	struct pci_dev *pdev = ndev->ntb.pdev;
264062306a36Sopenharmony_ci	int ret;
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci	/* Initialize the bit mask of PCI/NTB DMA */
264362306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
264462306a36Sopenharmony_ci	if (ret != 0) {
264562306a36Sopenharmony_ci		ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
264662306a36Sopenharmony_ci		if (ret != 0) {
264762306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to set DMA bit mask\n");
264862306a36Sopenharmony_ci			return ret;
264962306a36Sopenharmony_ci		}
265062306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Cannot set DMA highmem bit mask\n");
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	/*
265462306a36Sopenharmony_ci	 * The PCI core enables device error reporting. It's not critical to
265562306a36Sopenharmony_ci	 * have AER disabled in the kernel.
265662306a36Sopenharmony_ci	 *
265762306a36Sopenharmony_ci	 * Cleanup nonfatal error status before getting to init.
265862306a36Sopenharmony_ci	 */
265962306a36Sopenharmony_ci	pci_aer_clear_nonfatal_status(pdev);
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	/* First enable the PCI device */
266262306a36Sopenharmony_ci	ret = pcim_enable_device(pdev);
266362306a36Sopenharmony_ci	if (ret != 0) {
266462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to enable PCIe device\n");
266562306a36Sopenharmony_ci		return ret;
266662306a36Sopenharmony_ci	}
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	/*
266962306a36Sopenharmony_ci	 * Enable the bus mastering, which effectively enables MSI IRQs and
267062306a36Sopenharmony_ci	 * Request TLPs translation
267162306a36Sopenharmony_ci	 */
267262306a36Sopenharmony_ci	pci_set_master(pdev);
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	/* Request all BARs resources and map BAR0 only */
267562306a36Sopenharmony_ci	ret = pcim_iomap_regions_request_all(pdev, 1, NTB_NAME);
267662306a36Sopenharmony_ci	if (ret != 0) {
267762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request resources\n");
267862306a36Sopenharmony_ci		goto err_clear_master;
267962306a36Sopenharmony_ci	}
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	/* Retrieve virtual address of BAR0 - PCI configuration space */
268262306a36Sopenharmony_ci	ndev->cfgspc = pcim_iomap_table(pdev)[0];
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	/* Put the IDT driver data pointer to the PCI-device private pointer */
268562306a36Sopenharmony_ci	pci_set_drvdata(pdev, ndev);
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "NT-function PCIe interface initialized");
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	return 0;
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_cierr_clear_master:
269262306a36Sopenharmony_ci	pci_clear_master(pdev);
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	return ret;
269562306a36Sopenharmony_ci}
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci/*
269862306a36Sopenharmony_ci * idt_deinit_pci() - deinitialize the basic PCI-related subsystem
269962306a36Sopenharmony_ci * @ndev:	Pointer to the IDT PCIe-switch driver descriptor
270062306a36Sopenharmony_ci *
270162306a36Sopenharmony_ci * Managed resources will be freed on the driver detachment
270262306a36Sopenharmony_ci */
270362306a36Sopenharmony_cistatic void idt_deinit_pci(struct idt_ntb_dev *ndev)
270462306a36Sopenharmony_ci{
270562306a36Sopenharmony_ci	struct pci_dev *pdev = ndev->ntb.pdev;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	/* Clean up the PCI-device private data pointer */
270862306a36Sopenharmony_ci	pci_set_drvdata(pdev, NULL);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	/* Clear the bus master disabling the Request TLPs translation */
271162306a36Sopenharmony_ci	pci_clear_master(pdev);
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "NT-function PCIe interface cleared");
271462306a36Sopenharmony_ci}
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci/*===========================================================================
271762306a36Sopenharmony_ci *                       12. PCI bus callback functions
271862306a36Sopenharmony_ci *===========================================================================
271962306a36Sopenharmony_ci */
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci/*
272262306a36Sopenharmony_ci * idt_pci_probe() - PCI device probe callback
272362306a36Sopenharmony_ci * @pdev:	Pointer to PCI device structure
272462306a36Sopenharmony_ci * @id:		PCIe device custom descriptor
272562306a36Sopenharmony_ci *
272662306a36Sopenharmony_ci * Return: zero on success, otherwise negative error number
272762306a36Sopenharmony_ci */
272862306a36Sopenharmony_cistatic int idt_pci_probe(struct pci_dev *pdev,
272962306a36Sopenharmony_ci			 const struct pci_device_id *id)
273062306a36Sopenharmony_ci{
273162306a36Sopenharmony_ci	struct idt_ntb_dev *ndev;
273262306a36Sopenharmony_ci	int ret;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	/* Check whether IDT PCIe-switch is properly pre-initialized */
273562306a36Sopenharmony_ci	ret = idt_check_setup(pdev);
273662306a36Sopenharmony_ci	if (ret != 0)
273762306a36Sopenharmony_ci		return ret;
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	/* Allocate the memory for IDT NTB device data */
274062306a36Sopenharmony_ci	ndev = idt_create_dev(pdev, id);
274162306a36Sopenharmony_ci	if (IS_ERR(ndev))
274262306a36Sopenharmony_ci		return PTR_ERR(ndev);
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	/* Initialize the basic PCI subsystem of the device */
274562306a36Sopenharmony_ci	ret = idt_init_pci(ndev);
274662306a36Sopenharmony_ci	if (ret != 0)
274762306a36Sopenharmony_ci		return ret;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	/* Scan ports of the IDT PCIe-switch */
275062306a36Sopenharmony_ci	(void)idt_scan_ports(ndev);
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	/* Initialize NTB link events subsystem */
275362306a36Sopenharmony_ci	idt_init_link(ndev);
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	/* Initialize MWs subsystem */
275662306a36Sopenharmony_ci	ret = idt_init_mws(ndev);
275762306a36Sopenharmony_ci	if (ret != 0)
275862306a36Sopenharmony_ci		goto err_deinit_link;
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	/* Initialize Messaging subsystem */
276162306a36Sopenharmony_ci	idt_init_msg(ndev);
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	/* Initialize hwmon interface */
276462306a36Sopenharmony_ci	idt_init_temp(ndev);
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	/* Initialize IDT interrupts handler */
276762306a36Sopenharmony_ci	ret = idt_init_isr(ndev);
276862306a36Sopenharmony_ci	if (ret != 0)
276962306a36Sopenharmony_ci		goto err_deinit_link;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	/* Register IDT NTB devices on the NTB bus */
277262306a36Sopenharmony_ci	ret = idt_register_device(ndev);
277362306a36Sopenharmony_ci	if (ret != 0)
277462306a36Sopenharmony_ci		goto err_deinit_isr;
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	/* Initialize DebugFS info node */
277762306a36Sopenharmony_ci	(void)idt_init_dbgfs(ndev);
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	/* IDT PCIe-switch NTB driver is finally initialized */
278062306a36Sopenharmony_ci	dev_info(&pdev->dev, "IDT NTB device is ready");
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	/* May the force be with us... */
278362306a36Sopenharmony_ci	return 0;
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_cierr_deinit_isr:
278662306a36Sopenharmony_ci	idt_deinit_isr(ndev);
278762306a36Sopenharmony_cierr_deinit_link:
278862306a36Sopenharmony_ci	idt_deinit_link(ndev);
278962306a36Sopenharmony_ci	idt_deinit_pci(ndev);
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	return ret;
279262306a36Sopenharmony_ci}
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci/*
279562306a36Sopenharmony_ci * idt_pci_probe() - PCI device remove callback
279662306a36Sopenharmony_ci * @pdev:	Pointer to PCI device structure
279762306a36Sopenharmony_ci */
279862306a36Sopenharmony_cistatic void idt_pci_remove(struct pci_dev *pdev)
279962306a36Sopenharmony_ci{
280062306a36Sopenharmony_ci	struct idt_ntb_dev *ndev = pci_get_drvdata(pdev);
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	/* Deinit the DebugFS node */
280362306a36Sopenharmony_ci	idt_deinit_dbgfs(ndev);
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	/* Unregister NTB device */
280662306a36Sopenharmony_ci	idt_unregister_device(ndev);
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	/* Stop the interrupts handling */
280962306a36Sopenharmony_ci	idt_deinit_isr(ndev);
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	/* Deinitialize link event subsystem */
281262306a36Sopenharmony_ci	idt_deinit_link(ndev);
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	/* Deinit basic PCI subsystem */
281562306a36Sopenharmony_ci	idt_deinit_pci(ndev);
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	/* IDT PCIe-switch NTB driver is finally initialized */
281862306a36Sopenharmony_ci	dev_info(&pdev->dev, "IDT NTB device is removed");
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	/* Sayonara... */
282162306a36Sopenharmony_ci}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci/*
282462306a36Sopenharmony_ci * IDT PCIe-switch models ports configuration structures
282562306a36Sopenharmony_ci */
282662306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes24nt6ag2_config = {
282762306a36Sopenharmony_ci	.name = "89HPES24NT6AG2",
282862306a36Sopenharmony_ci	.port_cnt = 6, .ports = {0, 2, 4, 6, 8, 12}
282962306a36Sopenharmony_ci};
283062306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes32nt8ag2_config = {
283162306a36Sopenharmony_ci	.name = "89HPES32NT8AG2",
283262306a36Sopenharmony_ci	.port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
283362306a36Sopenharmony_ci};
283462306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes32nt8bg2_config = {
283562306a36Sopenharmony_ci	.name = "89HPES32NT8BG2",
283662306a36Sopenharmony_ci	.port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
283762306a36Sopenharmony_ci};
283862306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes12nt12g2_config = {
283962306a36Sopenharmony_ci	.name = "89HPES12NT12G2",
284062306a36Sopenharmony_ci	.port_cnt = 3, .ports = {0, 8, 16}
284162306a36Sopenharmony_ci};
284262306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes16nt16g2_config = {
284362306a36Sopenharmony_ci	.name = "89HPES16NT16G2",
284462306a36Sopenharmony_ci	.port_cnt = 4, .ports = {0, 8, 12, 16}
284562306a36Sopenharmony_ci};
284662306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes24nt24g2_config = {
284762306a36Sopenharmony_ci	.name = "89HPES24NT24G2",
284862306a36Sopenharmony_ci	.port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
284962306a36Sopenharmony_ci};
285062306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes32nt24ag2_config = {
285162306a36Sopenharmony_ci	.name = "89HPES32NT24AG2",
285262306a36Sopenharmony_ci	.port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
285362306a36Sopenharmony_ci};
285462306a36Sopenharmony_cistatic const struct idt_89hpes_cfg idt_89hpes32nt24bg2_config = {
285562306a36Sopenharmony_ci	.name = "89HPES32NT24BG2",
285662306a36Sopenharmony_ci	.port_cnt = 8, .ports = {0, 2, 4, 6, 8, 12, 16, 20}
285762306a36Sopenharmony_ci};
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci/*
286062306a36Sopenharmony_ci * PCI-ids table of the supported IDT PCIe-switch devices
286162306a36Sopenharmony_ci */
286262306a36Sopenharmony_cistatic const struct pci_device_id idt_pci_tbl[] = {
286362306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES24NT6AG2,  idt_89hpes24nt6ag2_config)},
286462306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES32NT8AG2,  idt_89hpes32nt8ag2_config)},
286562306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES32NT8BG2,  idt_89hpes32nt8bg2_config)},
286662306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES12NT12G2,  idt_89hpes12nt12g2_config)},
286762306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES16NT16G2,  idt_89hpes16nt16g2_config)},
286862306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES24NT24G2,  idt_89hpes24nt24g2_config)},
286962306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES32NT24AG2, idt_89hpes32nt24ag2_config)},
287062306a36Sopenharmony_ci	{IDT_PCI_DEVICE_IDS(89HPES32NT24BG2, idt_89hpes32nt24bg2_config)},
287162306a36Sopenharmony_ci	{0}
287262306a36Sopenharmony_ci};
287362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, idt_pci_tbl);
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci/*
287662306a36Sopenharmony_ci * IDT PCIe-switch NT-function device driver structure definition
287762306a36Sopenharmony_ci */
287862306a36Sopenharmony_cistatic struct pci_driver idt_pci_driver = {
287962306a36Sopenharmony_ci	.name		= KBUILD_MODNAME,
288062306a36Sopenharmony_ci	.probe		= idt_pci_probe,
288162306a36Sopenharmony_ci	.remove		= idt_pci_remove,
288262306a36Sopenharmony_ci	.id_table	= idt_pci_tbl,
288362306a36Sopenharmony_ci};
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_cistatic int __init idt_pci_driver_init(void)
288662306a36Sopenharmony_ci{
288762306a36Sopenharmony_ci	int ret;
288862306a36Sopenharmony_ci	pr_info("%s %s\n", NTB_DESC, NTB_VER);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	/* Create the top DebugFS directory if the FS is initialized */
289162306a36Sopenharmony_ci	if (debugfs_initialized())
289262306a36Sopenharmony_ci		dbgfs_topdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci	/* Register the NTB hardware driver to handle the PCI device */
289562306a36Sopenharmony_ci	ret = pci_register_driver(&idt_pci_driver);
289662306a36Sopenharmony_ci	if (ret)
289762306a36Sopenharmony_ci		debugfs_remove_recursive(dbgfs_topdir);
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	return ret;
290062306a36Sopenharmony_ci}
290162306a36Sopenharmony_cimodule_init(idt_pci_driver_init);
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_cistatic void __exit idt_pci_driver_exit(void)
290462306a36Sopenharmony_ci{
290562306a36Sopenharmony_ci	/* Unregister the NTB hardware driver */
290662306a36Sopenharmony_ci	pci_unregister_driver(&idt_pci_driver);
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	/* Discard the top DebugFS directory */
290962306a36Sopenharmony_ci	debugfs_remove_recursive(dbgfs_topdir);
291062306a36Sopenharmony_ci}
291162306a36Sopenharmony_cimodule_exit(idt_pci_driver_exit);
291262306a36Sopenharmony_ci
2913