xref: /linux/arch/powerpc/platforms/powernv/ocxl.c (revision 6914c757)
1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2017 IBM Corp.
3 #include <asm/pnv-ocxl.h>
4 #include <asm/opal.h>
5 #include "pci.h"
6 
7 #define PNV_OCXL_TL_P9_RECV_CAP		0x000000000000000Full
8 /* PASIDs are 20-bit, but on P9, NPU can only handle 15 bits */
9 #define PNV_OCXL_PASID_BITS		15
10 #define PNV_OCXL_PASID_MAX		((1 << PNV_OCXL_PASID_BITS) - 1)
11 
12 
13 static void set_templ_rate(unsigned int templ, unsigned int rate, char *buf)
14 {
15 	int shift, idx;
16 
17 	WARN_ON(templ > PNV_OCXL_TL_MAX_TEMPLATE);
18 	idx = (PNV_OCXL_TL_MAX_TEMPLATE - templ) / 2;
19 	shift = 4 * (1 - ((PNV_OCXL_TL_MAX_TEMPLATE - templ) % 2));
20 	buf[idx] |= rate << shift;
21 }
22 
23 int pnv_ocxl_get_tl_cap(struct pci_dev *dev, long *cap,
24 			char *rate_buf, int rate_buf_size)
25 {
26 	if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE)
27 		return -EINVAL;
28 	/*
29 	 * The TL capabilities are a characteristic of the NPU, so
30 	 * we go with hard-coded values.
31 	 *
32 	 * The receiving rate of each template is encoded on 4 bits.
33 	 *
34 	 * On P9:
35 	 * - templates 0 -> 3 are supported
36 	 * - templates 0, 1 and 3 have a 0 receiving rate
37 	 * - template 2 has receiving rate of 1 (extra cycle)
38 	 */
39 	memset(rate_buf, 0, rate_buf_size);
40 	set_templ_rate(2, 1, rate_buf);
41 	*cap = PNV_OCXL_TL_P9_RECV_CAP;
42 	return 0;
43 }
44 EXPORT_SYMBOL_GPL(pnv_ocxl_get_tl_cap);
45 
46 int pnv_ocxl_set_tl_conf(struct pci_dev *dev, long cap,
47 			uint64_t rate_buf_phys, int rate_buf_size)
48 {
49 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
50 	struct pnv_phb *phb = hose->private_data;
51 	int rc;
52 
53 	if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE)
54 		return -EINVAL;
55 
56 	rc = opal_npu_tl_set(phb->opal_id, dev->devfn, cap,
57 			rate_buf_phys, rate_buf_size);
58 	if (rc) {
59 		dev_err(&dev->dev, "Can't configure host TL: %d\n", rc);
60 		return -EINVAL;
61 	}
62 	return 0;
63 }
64 EXPORT_SYMBOL_GPL(pnv_ocxl_set_tl_conf);
65 
66 int pnv_ocxl_get_xsl_irq(struct pci_dev *dev, int *hwirq)
67 {
68 	int rc;
69 
70 	rc = of_property_read_u32(dev->dev.of_node, "ibm,opal-xsl-irq", hwirq);
71 	if (rc) {
72 		dev_err(&dev->dev,
73 			"Can't get translation interrupt for device\n");
74 		return rc;
75 	}
76 	return 0;
77 }
78 EXPORT_SYMBOL_GPL(pnv_ocxl_get_xsl_irq);
79 
80 void pnv_ocxl_unmap_xsl_regs(void __iomem *dsisr, void __iomem *dar,
81 			void __iomem *tfc, void __iomem *pe_handle)
82 {
83 	iounmap(dsisr);
84 	iounmap(dar);
85 	iounmap(tfc);
86 	iounmap(pe_handle);
87 }
88 EXPORT_SYMBOL_GPL(pnv_ocxl_unmap_xsl_regs);
89 
90 int pnv_ocxl_map_xsl_regs(struct pci_dev *dev, void __iomem **dsisr,
91 			void __iomem **dar, void __iomem **tfc,
92 			void __iomem **pe_handle)
93 {
94 	u64 reg;
95 	int i, j, rc = 0;
96 	void __iomem *regs[4];
97 
98 	/*
99 	 * opal stores the mmio addresses of the DSISR, DAR, TFC and
100 	 * PE_HANDLE registers in a device tree property, in that
101 	 * order
102 	 */
103 	for (i = 0; i < 4; i++) {
104 		rc = of_property_read_u64_index(dev->dev.of_node,
105 						"ibm,opal-xsl-mmio", i, &reg);
106 		if (rc)
107 			break;
108 		regs[i] = ioremap(reg, 8);
109 		if (!regs[i]) {
110 			rc = -EINVAL;
111 			break;
112 		}
113 	}
114 	if (rc) {
115 		dev_err(&dev->dev, "Can't map translation mmio registers\n");
116 		for (j = i - 1; j >= 0; j--)
117 			iounmap(regs[j]);
118 	} else {
119 		*dsisr = regs[0];
120 		*dar = regs[1];
121 		*tfc = regs[2];
122 		*pe_handle = regs[3];
123 	}
124 	return rc;
125 }
126 EXPORT_SYMBOL_GPL(pnv_ocxl_map_xsl_regs);
127 
128 struct spa_data {
129 	u64 phb_opal_id;
130 	u32 bdfn;
131 };
132 
133 int pnv_ocxl_spa_setup(struct pci_dev *dev, void *spa_mem, int PE_mask,
134 		void **platform_data)
135 {
136 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
137 	struct pnv_phb *phb = hose->private_data;
138 	struct spa_data *data;
139 	u32 bdfn;
140 	int rc;
141 
142 	data = kzalloc(sizeof(*data), GFP_KERNEL);
143 	if (!data)
144 		return -ENOMEM;
145 
146 	bdfn = (dev->bus->number << 8) | dev->devfn;
147 	rc = opal_npu_spa_setup(phb->opal_id, bdfn, virt_to_phys(spa_mem),
148 				PE_mask);
149 	if (rc) {
150 		dev_err(&dev->dev, "Can't setup Shared Process Area: %d\n", rc);
151 		kfree(data);
152 		return rc;
153 	}
154 	data->phb_opal_id = phb->opal_id;
155 	data->bdfn = bdfn;
156 	*platform_data = (void *) data;
157 	return 0;
158 }
159 EXPORT_SYMBOL_GPL(pnv_ocxl_spa_setup);
160 
161 void pnv_ocxl_spa_release(void *platform_data)
162 {
163 	struct spa_data *data = (struct spa_data *) platform_data;
164 	int rc;
165 
166 	rc = opal_npu_spa_setup(data->phb_opal_id, data->bdfn, 0, 0);
167 	WARN_ON(rc);
168 	kfree(data);
169 }
170 EXPORT_SYMBOL_GPL(pnv_ocxl_spa_release);
171 
172 int pnv_ocxl_spa_remove_pe(void *platform_data, int pe_handle)
173 {
174 	struct spa_data *data = (struct spa_data *) platform_data;
175 	int rc;
176 
177 	rc = opal_npu_spa_clear_cache(data->phb_opal_id, data->bdfn, pe_handle);
178 	return rc;
179 }
180 EXPORT_SYMBOL_GPL(pnv_ocxl_spa_remove_pe);
181