151ba902aSAviad Krawczyk /*
251ba902aSAviad Krawczyk  * Huawei HiNIC PCI Express Linux driver
351ba902aSAviad Krawczyk  * Copyright(c) 2017 Huawei Technologies Co., Ltd
451ba902aSAviad Krawczyk  *
551ba902aSAviad Krawczyk  * This program is free software; you can redistribute it and/or modify it
651ba902aSAviad Krawczyk  * under the terms and conditions of the GNU General Public License,
751ba902aSAviad Krawczyk  * version 2, as published by the Free Software Foundation.
851ba902aSAviad Krawczyk  *
951ba902aSAviad Krawczyk  * This program is distributed in the hope it will be useful, but WITHOUT
1051ba902aSAviad Krawczyk  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1151ba902aSAviad Krawczyk  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1251ba902aSAviad Krawczyk  * for more details.
1351ba902aSAviad Krawczyk  *
1451ba902aSAviad Krawczyk  */
1551ba902aSAviad Krawczyk 
1651ba902aSAviad Krawczyk #include <linux/pci.h>
1751ba902aSAviad Krawczyk #include <linux/device.h>
1851ba902aSAviad Krawczyk #include <linux/errno.h>
1951ba902aSAviad Krawczyk #include <linux/io.h>
2051ba902aSAviad Krawczyk #include <linux/types.h>
2151ba902aSAviad Krawczyk #include <linux/bitops.h>
2251ba902aSAviad Krawczyk 
2351ba902aSAviad Krawczyk #include "hinic_hw_csr.h"
2451ba902aSAviad Krawczyk #include "hinic_hw_if.h"
2551ba902aSAviad Krawczyk 
2651ba902aSAviad Krawczyk #define PCIE_ATTR_ENTRY         0
2751ba902aSAviad Krawczyk 
28f00fe738SAviad Krawczyk #define VALID_MSIX_IDX(attr, msix_index) ((msix_index) < (attr)->num_irqs)
29f00fe738SAviad Krawczyk 
30f00fe738SAviad Krawczyk /**
31f00fe738SAviad Krawczyk  * hinic_msix_attr_set - set message attribute for msix entry
32f00fe738SAviad Krawczyk  * @hwif: the HW interface of a pci function device
33f00fe738SAviad Krawczyk  * @msix_index: msix_index
34f00fe738SAviad Krawczyk  * @pending_limit: the maximum pending interrupt events (unit 8)
35f00fe738SAviad Krawczyk  * @coalesc_timer: coalesc period for interrupt (unit 8 us)
36f00fe738SAviad Krawczyk  * @lli_timer: replenishing period for low latency credit (unit 8 us)
37f00fe738SAviad Krawczyk  * @lli_credit_limit: maximum credits for low latency msix messages (unit 8)
38f00fe738SAviad Krawczyk  * @resend_timer: maximum wait for resending msix (unit coalesc period)
39f00fe738SAviad Krawczyk  *
40f00fe738SAviad Krawczyk  * Return 0 - Success, negative - Failure
41f00fe738SAviad Krawczyk  **/
42f00fe738SAviad Krawczyk int hinic_msix_attr_set(struct hinic_hwif *hwif, u16 msix_index,
43f00fe738SAviad Krawczyk 			u8 pending_limit, u8 coalesc_timer,
44f00fe738SAviad Krawczyk 			u8 lli_timer, u8 lli_credit_limit,
45f00fe738SAviad Krawczyk 			u8 resend_timer)
46f00fe738SAviad Krawczyk {
47f00fe738SAviad Krawczyk 	u32 msix_ctrl, addr;
48f00fe738SAviad Krawczyk 
49f00fe738SAviad Krawczyk 	if (!VALID_MSIX_IDX(&hwif->attr, msix_index))
50f00fe738SAviad Krawczyk 		return -EINVAL;
51f00fe738SAviad Krawczyk 
52f00fe738SAviad Krawczyk 	msix_ctrl = HINIC_MSIX_ATTR_SET(pending_limit, PENDING_LIMIT)   |
53f00fe738SAviad Krawczyk 		    HINIC_MSIX_ATTR_SET(coalesc_timer, COALESC_TIMER)   |
54f00fe738SAviad Krawczyk 		    HINIC_MSIX_ATTR_SET(lli_timer, LLI_TIMER)           |
55f00fe738SAviad Krawczyk 		    HINIC_MSIX_ATTR_SET(lli_credit_limit, LLI_CREDIT)   |
56f00fe738SAviad Krawczyk 		    HINIC_MSIX_ATTR_SET(resend_timer, RESEND_TIMER);
57f00fe738SAviad Krawczyk 
58f00fe738SAviad Krawczyk 	addr = HINIC_CSR_MSIX_CTRL_ADDR(msix_index);
59f00fe738SAviad Krawczyk 
60f00fe738SAviad Krawczyk 	hinic_hwif_write_reg(hwif, addr, msix_ctrl);
61f00fe738SAviad Krawczyk 	return 0;
62f00fe738SAviad Krawczyk }
63f00fe738SAviad Krawczyk 
64f00fe738SAviad Krawczyk /**
65f00fe738SAviad Krawczyk  * hinic_msix_attr_get - get message attribute of msix entry
66f00fe738SAviad Krawczyk  * @hwif: the HW interface of a pci function device
67f00fe738SAviad Krawczyk  * @msix_index: msix_index
68f00fe738SAviad Krawczyk  * @pending_limit: the maximum pending interrupt events (unit 8)
69f00fe738SAviad Krawczyk  * @coalesc_timer: coalesc period for interrupt (unit 8 us)
70f00fe738SAviad Krawczyk  * @lli_timer: replenishing period for low latency credit (unit 8 us)
71f00fe738SAviad Krawczyk  * @lli_credit_limit: maximum credits for low latency msix messages (unit 8)
72f00fe738SAviad Krawczyk  * @resend_timer: maximum wait for resending msix (unit coalesc period)
73f00fe738SAviad Krawczyk  *
74f00fe738SAviad Krawczyk  * Return 0 - Success, negative - Failure
75f00fe738SAviad Krawczyk  **/
76f00fe738SAviad Krawczyk int hinic_msix_attr_get(struct hinic_hwif *hwif, u16 msix_index,
77f00fe738SAviad Krawczyk 			u8 *pending_limit, u8 *coalesc_timer,
78f00fe738SAviad Krawczyk 			u8 *lli_timer, u8 *lli_credit_limit,
79f00fe738SAviad Krawczyk 			u8 *resend_timer)
80f00fe738SAviad Krawczyk {
81f00fe738SAviad Krawczyk 	u32 addr, val;
82f00fe738SAviad Krawczyk 
83f00fe738SAviad Krawczyk 	if (!VALID_MSIX_IDX(&hwif->attr, msix_index))
84f00fe738SAviad Krawczyk 		return -EINVAL;
85f00fe738SAviad Krawczyk 
86f00fe738SAviad Krawczyk 	addr = HINIC_CSR_MSIX_CTRL_ADDR(msix_index);
87f00fe738SAviad Krawczyk 	val  = hinic_hwif_read_reg(hwif, addr);
88f00fe738SAviad Krawczyk 
89f00fe738SAviad Krawczyk 	*pending_limit    = HINIC_MSIX_ATTR_GET(val, PENDING_LIMIT);
90f00fe738SAviad Krawczyk 	*coalesc_timer    = HINIC_MSIX_ATTR_GET(val, COALESC_TIMER);
91f00fe738SAviad Krawczyk 	*lli_timer        = HINIC_MSIX_ATTR_GET(val, LLI_TIMER);
92f00fe738SAviad Krawczyk 	*lli_credit_limit = HINIC_MSIX_ATTR_GET(val, LLI_CREDIT);
93f00fe738SAviad Krawczyk 	*resend_timer     = HINIC_MSIX_ATTR_GET(val, RESEND_TIMER);
94f00fe738SAviad Krawczyk 	return 0;
95f00fe738SAviad Krawczyk }
96f00fe738SAviad Krawczyk 
97f00fe738SAviad Krawczyk /**
98f00fe738SAviad Krawczyk  * hinic_msix_attr_cnt_clear - clear message attribute counters for msix entry
99f00fe738SAviad Krawczyk  * @hwif: the HW interface of a pci function device
100f00fe738SAviad Krawczyk  * @msix_index: msix_index
101f00fe738SAviad Krawczyk  *
102f00fe738SAviad Krawczyk  * Return 0 - Success, negative - Failure
103f00fe738SAviad Krawczyk  **/
104f00fe738SAviad Krawczyk int hinic_msix_attr_cnt_clear(struct hinic_hwif *hwif, u16 msix_index)
105f00fe738SAviad Krawczyk {
106f00fe738SAviad Krawczyk 	u32 msix_ctrl, addr;
107f00fe738SAviad Krawczyk 
108f00fe738SAviad Krawczyk 	if (!VALID_MSIX_IDX(&hwif->attr, msix_index))
109f00fe738SAviad Krawczyk 		return -EINVAL;
110f00fe738SAviad Krawczyk 
111f00fe738SAviad Krawczyk 	msix_ctrl = HINIC_MSIX_CNT_SET(1, RESEND_TIMER);
112f00fe738SAviad Krawczyk 	addr = HINIC_CSR_MSIX_CNT_ADDR(msix_index);
113f00fe738SAviad Krawczyk 
114f00fe738SAviad Krawczyk 	hinic_hwif_write_reg(hwif, addr, msix_ctrl);
115f00fe738SAviad Krawczyk 	return 0;
116f00fe738SAviad Krawczyk }
117f00fe738SAviad Krawczyk 
11851ba902aSAviad Krawczyk /**
11951ba902aSAviad Krawczyk  * hwif_ready - test if the HW is ready for use
12051ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
12151ba902aSAviad Krawczyk  *
12251ba902aSAviad Krawczyk  * Return 0 - Success, negative - Failure
12351ba902aSAviad Krawczyk  **/
12451ba902aSAviad Krawczyk static int hwif_ready(struct hinic_hwif *hwif)
12551ba902aSAviad Krawczyk {
12651ba902aSAviad Krawczyk 	struct pci_dev *pdev = hwif->pdev;
12751ba902aSAviad Krawczyk 	u32 addr, attr1;
12851ba902aSAviad Krawczyk 
12951ba902aSAviad Krawczyk 	addr   = HINIC_CSR_FUNC_ATTR1_ADDR;
13051ba902aSAviad Krawczyk 	attr1  = hinic_hwif_read_reg(hwif, addr);
13151ba902aSAviad Krawczyk 
13251ba902aSAviad Krawczyk 	if (!HINIC_FA1_GET(attr1, INIT_STATUS)) {
13351ba902aSAviad Krawczyk 		dev_err(&pdev->dev, "hwif status is not ready\n");
13451ba902aSAviad Krawczyk 		return -EFAULT;
13551ba902aSAviad Krawczyk 	}
13651ba902aSAviad Krawczyk 
13751ba902aSAviad Krawczyk 	return 0;
13851ba902aSAviad Krawczyk }
13951ba902aSAviad Krawczyk 
14051ba902aSAviad Krawczyk /**
14151ba902aSAviad Krawczyk  * set_hwif_attr - set the attributes in the relevant members in hwif
14251ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
14351ba902aSAviad Krawczyk  * @attr0: the first attribute that was read from the hw
14451ba902aSAviad Krawczyk  * @attr1: the second attribute that was read from the hw
14551ba902aSAviad Krawczyk  **/
14651ba902aSAviad Krawczyk static void set_hwif_attr(struct hinic_hwif *hwif, u32 attr0, u32 attr1)
14751ba902aSAviad Krawczyk {
14851ba902aSAviad Krawczyk 	hwif->attr.func_idx     = HINIC_FA0_GET(attr0, FUNC_IDX);
14951ba902aSAviad Krawczyk 	hwif->attr.pf_idx       = HINIC_FA0_GET(attr0, PF_IDX);
15051ba902aSAviad Krawczyk 	hwif->attr.pci_intf_idx = HINIC_FA0_GET(attr0, PCI_INTF_IDX);
15151ba902aSAviad Krawczyk 	hwif->attr.func_type    = HINIC_FA0_GET(attr0, FUNC_TYPE);
15251ba902aSAviad Krawczyk 
15351ba902aSAviad Krawczyk 	hwif->attr.num_aeqs = BIT(HINIC_FA1_GET(attr1, AEQS_PER_FUNC));
15451ba902aSAviad Krawczyk 	hwif->attr.num_ceqs = BIT(HINIC_FA1_GET(attr1, CEQS_PER_FUNC));
15551ba902aSAviad Krawczyk 	hwif->attr.num_irqs = BIT(HINIC_FA1_GET(attr1, IRQS_PER_FUNC));
15651ba902aSAviad Krawczyk 	hwif->attr.num_dma_attr = BIT(HINIC_FA1_GET(attr1, DMA_ATTR_PER_FUNC));
15751ba902aSAviad Krawczyk }
15851ba902aSAviad Krawczyk 
15951ba902aSAviad Krawczyk /**
16051ba902aSAviad Krawczyk  * read_hwif_attr - read the attributes and set members in hwif
16151ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
16251ba902aSAviad Krawczyk  **/
16351ba902aSAviad Krawczyk static void read_hwif_attr(struct hinic_hwif *hwif)
16451ba902aSAviad Krawczyk {
16551ba902aSAviad Krawczyk 	u32 addr, attr0, attr1;
16651ba902aSAviad Krawczyk 
16751ba902aSAviad Krawczyk 	addr   = HINIC_CSR_FUNC_ATTR0_ADDR;
16851ba902aSAviad Krawczyk 	attr0  = hinic_hwif_read_reg(hwif, addr);
16951ba902aSAviad Krawczyk 
17051ba902aSAviad Krawczyk 	addr   = HINIC_CSR_FUNC_ATTR1_ADDR;
17151ba902aSAviad Krawczyk 	attr1  = hinic_hwif_read_reg(hwif, addr);
17251ba902aSAviad Krawczyk 
17351ba902aSAviad Krawczyk 	set_hwif_attr(hwif, attr0, attr1);
17451ba902aSAviad Krawczyk }
17551ba902aSAviad Krawczyk 
17651ba902aSAviad Krawczyk /**
17751ba902aSAviad Krawczyk  * set_ppf - try to set hwif as ppf and set the type of hwif in this case
17851ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
17951ba902aSAviad Krawczyk  **/
18051ba902aSAviad Krawczyk static void set_ppf(struct hinic_hwif *hwif)
18151ba902aSAviad Krawczyk {
18251ba902aSAviad Krawczyk 	struct hinic_func_attr *attr = &hwif->attr;
18351ba902aSAviad Krawczyk 	u32 addr, val, ppf_election;
18451ba902aSAviad Krawczyk 
18551ba902aSAviad Krawczyk 	/* Read Modify Write */
18651ba902aSAviad Krawczyk 	addr = HINIC_CSR_PPF_ELECTION_ADDR(HINIC_HWIF_PCI_INTF(hwif));
18751ba902aSAviad Krawczyk 
18851ba902aSAviad Krawczyk 	val = hinic_hwif_read_reg(hwif, addr);
18951ba902aSAviad Krawczyk 	val = HINIC_PPF_ELECTION_CLEAR(val, IDX);
19051ba902aSAviad Krawczyk 
19151ba902aSAviad Krawczyk 	ppf_election = HINIC_PPF_ELECTION_SET(HINIC_HWIF_FUNC_IDX(hwif), IDX);
19251ba902aSAviad Krawczyk 
19351ba902aSAviad Krawczyk 	val |= ppf_election;
19451ba902aSAviad Krawczyk 	hinic_hwif_write_reg(hwif, addr, val);
19551ba902aSAviad Krawczyk 
19651ba902aSAviad Krawczyk 	/* check PPF */
19751ba902aSAviad Krawczyk 	val = hinic_hwif_read_reg(hwif, addr);
19851ba902aSAviad Krawczyk 
19951ba902aSAviad Krawczyk 	attr->ppf_idx = HINIC_PPF_ELECTION_GET(val, IDX);
20051ba902aSAviad Krawczyk 	if (attr->ppf_idx == HINIC_HWIF_FUNC_IDX(hwif))
20151ba902aSAviad Krawczyk 		attr->func_type = HINIC_PPF;
20251ba902aSAviad Krawczyk }
20351ba902aSAviad Krawczyk 
20451ba902aSAviad Krawczyk /**
20551ba902aSAviad Krawczyk  * set_dma_attr - set the dma attributes in the HW
20651ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
20751ba902aSAviad Krawczyk  * @entry_idx: the entry index in the dma table
20851ba902aSAviad Krawczyk  * @st: PCIE TLP steering tag
20951ba902aSAviad Krawczyk  * @at: PCIE TLP AT field
21051ba902aSAviad Krawczyk  * @ph: PCIE TLP Processing Hint field
21151ba902aSAviad Krawczyk  * @no_snooping: PCIE TLP No snooping
21251ba902aSAviad Krawczyk  * @tph_en: PCIE TLP Processing Hint Enable
21351ba902aSAviad Krawczyk  **/
21451ba902aSAviad Krawczyk static void set_dma_attr(struct hinic_hwif *hwif, u32 entry_idx,
21551ba902aSAviad Krawczyk 			 u8 st, u8 at, u8 ph,
21651ba902aSAviad Krawczyk 			 enum hinic_pcie_nosnoop no_snooping,
21751ba902aSAviad Krawczyk 			 enum hinic_pcie_tph tph_en)
21851ba902aSAviad Krawczyk {
21951ba902aSAviad Krawczyk 	u32 addr, val, dma_attr_entry;
22051ba902aSAviad Krawczyk 
22151ba902aSAviad Krawczyk 	/* Read Modify Write */
22251ba902aSAviad Krawczyk 	addr = HINIC_CSR_DMA_ATTR_ADDR(entry_idx);
22351ba902aSAviad Krawczyk 
22451ba902aSAviad Krawczyk 	val = hinic_hwif_read_reg(hwif, addr);
22551ba902aSAviad Krawczyk 	val = HINIC_DMA_ATTR_CLEAR(val, ST)             &
22651ba902aSAviad Krawczyk 	      HINIC_DMA_ATTR_CLEAR(val, AT)             &
22751ba902aSAviad Krawczyk 	      HINIC_DMA_ATTR_CLEAR(val, PH)             &
22851ba902aSAviad Krawczyk 	      HINIC_DMA_ATTR_CLEAR(val, NO_SNOOPING)    &
22951ba902aSAviad Krawczyk 	      HINIC_DMA_ATTR_CLEAR(val, TPH_EN);
23051ba902aSAviad Krawczyk 
23151ba902aSAviad Krawczyk 	dma_attr_entry = HINIC_DMA_ATTR_SET(st, ST)                     |
23251ba902aSAviad Krawczyk 			 HINIC_DMA_ATTR_SET(at, AT)                     |
23351ba902aSAviad Krawczyk 			 HINIC_DMA_ATTR_SET(ph, PH)                     |
23451ba902aSAviad Krawczyk 			 HINIC_DMA_ATTR_SET(no_snooping, NO_SNOOPING)   |
23551ba902aSAviad Krawczyk 			 HINIC_DMA_ATTR_SET(tph_en, TPH_EN);
23651ba902aSAviad Krawczyk 
23751ba902aSAviad Krawczyk 	val |= dma_attr_entry;
23851ba902aSAviad Krawczyk 	hinic_hwif_write_reg(hwif, addr, val);
23951ba902aSAviad Krawczyk }
24051ba902aSAviad Krawczyk 
24151ba902aSAviad Krawczyk /**
24251ba902aSAviad Krawczyk  * dma_attr_table_init - initialize the the default dma attributes
24351ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
24451ba902aSAviad Krawczyk  **/
24551ba902aSAviad Krawczyk static void dma_attr_init(struct hinic_hwif *hwif)
24651ba902aSAviad Krawczyk {
24751ba902aSAviad Krawczyk 	set_dma_attr(hwif, PCIE_ATTR_ENTRY, HINIC_PCIE_ST_DISABLE,
24851ba902aSAviad Krawczyk 		     HINIC_PCIE_AT_DISABLE, HINIC_PCIE_PH_DISABLE,
24951ba902aSAviad Krawczyk 		     HINIC_PCIE_SNOOP, HINIC_PCIE_TPH_DISABLE);
25051ba902aSAviad Krawczyk }
25151ba902aSAviad Krawczyk 
25251ba902aSAviad Krawczyk /**
25351ba902aSAviad Krawczyk  * hinic_init_hwif - initialize the hw interface
25451ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
25551ba902aSAviad Krawczyk  * @pdev: the pci device for acessing PCI resources
25651ba902aSAviad Krawczyk  *
25751ba902aSAviad Krawczyk  * Return 0 - Success, negative - Failure
25851ba902aSAviad Krawczyk  **/
25951ba902aSAviad Krawczyk int hinic_init_hwif(struct hinic_hwif *hwif, struct pci_dev *pdev)
26051ba902aSAviad Krawczyk {
26151ba902aSAviad Krawczyk 	int err;
26251ba902aSAviad Krawczyk 
26351ba902aSAviad Krawczyk 	hwif->pdev = pdev;
26451ba902aSAviad Krawczyk 
26551ba902aSAviad Krawczyk 	hwif->cfg_regs_bar = pci_ioremap_bar(pdev, HINIC_PCI_CFG_REGS_BAR);
26651ba902aSAviad Krawczyk 	if (!hwif->cfg_regs_bar) {
26751ba902aSAviad Krawczyk 		dev_err(&pdev->dev, "Failed to map configuration regs\n");
26851ba902aSAviad Krawczyk 		return -ENOMEM;
26951ba902aSAviad Krawczyk 	}
27051ba902aSAviad Krawczyk 
27151ba902aSAviad Krawczyk 	err = hwif_ready(hwif);
27251ba902aSAviad Krawczyk 	if (err) {
27351ba902aSAviad Krawczyk 		dev_err(&pdev->dev, "HW interface is not ready\n");
27451ba902aSAviad Krawczyk 		goto err_hwif_ready;
27551ba902aSAviad Krawczyk 	}
27651ba902aSAviad Krawczyk 
27751ba902aSAviad Krawczyk 	read_hwif_attr(hwif);
27851ba902aSAviad Krawczyk 
27951ba902aSAviad Krawczyk 	if (HINIC_IS_PF(hwif))
28051ba902aSAviad Krawczyk 		set_ppf(hwif);
28151ba902aSAviad Krawczyk 
28251ba902aSAviad Krawczyk 	/* No transactionss before DMA is initialized */
28351ba902aSAviad Krawczyk 	dma_attr_init(hwif);
28451ba902aSAviad Krawczyk 	return 0;
28551ba902aSAviad Krawczyk 
28651ba902aSAviad Krawczyk err_hwif_ready:
28751ba902aSAviad Krawczyk 	iounmap(hwif->cfg_regs_bar);
28851ba902aSAviad Krawczyk 	return err;
28951ba902aSAviad Krawczyk }
29051ba902aSAviad Krawczyk 
29151ba902aSAviad Krawczyk /**
29251ba902aSAviad Krawczyk  * hinic_free_hwif - free the HW interface
29351ba902aSAviad Krawczyk  * @hwif: the HW interface of a pci function device
29451ba902aSAviad Krawczyk  **/
29551ba902aSAviad Krawczyk void hinic_free_hwif(struct hinic_hwif *hwif)
29651ba902aSAviad Krawczyk {
29751ba902aSAviad Krawczyk 	iounmap(hwif->cfg_regs_bar);
29851ba902aSAviad Krawczyk }
299