]> Git Repo - linux.git/blob - drivers/misc/cxl/of.c
Linux 6.14-rc3
[linux.git] / drivers / misc / cxl / of.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2015 IBM Corp.
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/slab.h>
10 #include <linux/of.h>
11 #include <linux/of_address.h>
12 #include <linux/of_platform.h>
13
14 #include "cxl.h"
15
16 static int read_phys_addr(struct device_node *np, char *prop_name,
17                         struct cxl_afu *afu)
18 {
19         int i, len, entry_size, naddr, nsize, type;
20         u64 addr, size;
21         const __be32 *prop;
22
23         naddr = of_n_addr_cells(np);
24         nsize = of_n_size_cells(np);
25
26         prop = of_get_property(np, prop_name, &len);
27         if (prop) {
28                 entry_size = naddr + nsize;
29                 for (i = 0; i < (len / 4); i += entry_size, prop += entry_size) {
30                         type = be32_to_cpu(prop[0]);
31                         addr = of_read_number(prop, naddr);
32                         size = of_read_number(&prop[naddr], nsize);
33                         switch (type) {
34                         case 0: /* unit address */
35                                 afu->guest->handle = addr;
36                                 break;
37                         case 1: /* p2 area */
38                                 afu->guest->p2n_phys += addr;
39                                 afu->guest->p2n_size = size;
40                                 break;
41                         case 2: /* problem state area */
42                                 afu->psn_phys += addr;
43                                 afu->adapter->ps_size = size;
44                                 break;
45                         default:
46                                 pr_err("Invalid address type %d found in %s property of AFU\n",
47                                         type, prop_name);
48                                 return -EINVAL;
49                         }
50                 }
51         }
52         return 0;
53 }
54
55 static int read_vpd(struct cxl *adapter, struct cxl_afu *afu)
56 {
57         char vpd[256];
58         int rc;
59         size_t len = sizeof(vpd);
60
61         memset(vpd, 0, len);
62
63         if (adapter)
64                 rc = cxl_guest_read_adapter_vpd(adapter, vpd, len);
65         else
66                 rc = cxl_guest_read_afu_vpd(afu, vpd, len);
67
68         if (rc > 0) {
69                 cxl_dump_debug_buffer(vpd, rc);
70                 rc = 0;
71         }
72         return rc;
73 }
74
75 int cxl_of_read_afu_handle(struct cxl_afu *afu, struct device_node *afu_np)
76 {
77         return of_property_read_reg(afu_np, 0, &afu->guest->handle, NULL);
78 }
79
80 int cxl_of_read_afu_properties(struct cxl_afu *afu, struct device_node *np)
81 {
82         int i, rc;
83         u16 device_id, vendor_id;
84         u32 val = 0, class_code;
85
86         /* Properties are read in the same order as listed in PAPR */
87
88         rc = read_phys_addr(np, "reg", afu);
89         if (rc)
90                 return rc;
91
92         rc = read_phys_addr(np, "assigned-addresses", afu);
93         if (rc)
94                 return rc;
95
96         if (afu->psn_phys == 0)
97                 afu->psa = false;
98         else
99                 afu->psa = true;
100
101         of_property_read_u32(np, "ibm,#processes", &afu->max_procs_virtualised);
102
103         if (cxl_verbose)
104                 read_vpd(NULL, afu);
105
106         of_property_read_u32(np, "ibm,max-ints-per-process", &afu->guest->max_ints);
107         afu->irqs_max = afu->guest->max_ints;
108
109         if (!of_property_read_u32(np, "ibm,min-ints-per-process", &afu->pp_irqs)) {
110                 /* One extra interrupt for the PSL interrupt is already
111                  * included. Remove it now to keep only AFU interrupts and
112                  * match the native case.
113                  */
114                 afu->pp_irqs--;
115         }
116
117         of_property_read_u64(np, "ibm,error-buffer-size", &afu->eb_len);
118         afu->eb_offset = 0;
119
120         of_property_read_u64(np, "ibm,config-record-size", &afu->crs_len);
121         afu->crs_offset = 0;
122
123         of_property_read_u32(np, "ibm,#config-records", &afu->crs_num);
124
125         if (cxl_verbose) {
126                 for (i = 0; i < afu->crs_num; i++) {
127                         rc = cxl_ops->afu_cr_read16(afu, i, PCI_DEVICE_ID,
128                                                 &device_id);
129                         if (!rc)
130                                 pr_info("record %d - device-id: %#x\n",
131                                         i, device_id);
132                         rc = cxl_ops->afu_cr_read16(afu, i, PCI_VENDOR_ID,
133                                                 &vendor_id);
134                         if (!rc)
135                                 pr_info("record %d - vendor-id: %#x\n",
136                                         i, vendor_id);
137                         rc = cxl_ops->afu_cr_read32(afu, i, PCI_CLASS_REVISION,
138                                                 &class_code);
139                         if (!rc) {
140                                 class_code >>= 8;
141                                 pr_info("record %d - class-code: %#x\n",
142                                         i, class_code);
143                         }
144                 }
145         }
146         /*
147          * if "ibm,process-mmio" doesn't exist then per-process mmio is
148          * not supported
149          */
150         val = 0;
151         if (!of_property_read_u32(np, "ibm,process-mmio", &val) && val == 1)
152                 afu->pp_psa = true;
153         else
154                 afu->pp_psa = false;
155
156         if (!of_property_read_u32(np, "ibm,function-error-interrupt", &val))
157                 afu->serr_hwirq = val;
158
159         pr_devel("AFU handle: %#llx\n", afu->guest->handle);
160         pr_devel("p2n_phys: %#llx (size %#llx)\n",
161                 afu->guest->p2n_phys, afu->guest->p2n_size);
162         pr_devel("psn_phys: %#llx (size %#llx)\n",
163                 afu->psn_phys, afu->adapter->ps_size);
164         pr_devel("Max number of processes virtualised=%i\n",
165                 afu->max_procs_virtualised);
166         pr_devel("Per-process irqs min=%i, max=%i\n", afu->pp_irqs,
167                  afu->irqs_max);
168         pr_devel("Slice error interrupt=%#lx\n", afu->serr_hwirq);
169
170         return 0;
171 }
172
173 static int read_adapter_irq_config(struct cxl *adapter, struct device_node *np)
174 {
175         const __be32 *ranges;
176         int len, nranges, i;
177         struct irq_avail *cur;
178
179         ranges = of_get_property(np, "interrupt-ranges", &len);
180         if (ranges == NULL || len < (2 * sizeof(int)))
181                 return -EINVAL;
182
183         /*
184          * encoded array of two cells per entry, each cell encoded as
185          * with encode-int
186          */
187         nranges = len / (2 * sizeof(int));
188         if (nranges == 0 || (nranges * 2 * sizeof(int)) != len)
189                 return -EINVAL;
190
191         adapter->guest->irq_avail = kcalloc(nranges, sizeof(struct irq_avail),
192                                             GFP_KERNEL);
193         if (adapter->guest->irq_avail == NULL)
194                 return -ENOMEM;
195
196         adapter->guest->irq_base_offset = be32_to_cpu(ranges[0]);
197         for (i = 0; i < nranges; i++) {
198                 cur = &adapter->guest->irq_avail[i];
199                 cur->offset = be32_to_cpu(ranges[i * 2]);
200                 cur->range  = be32_to_cpu(ranges[i * 2 + 1]);
201                 cur->bitmap = bitmap_zalloc(cur->range, GFP_KERNEL);
202                 if (cur->bitmap == NULL)
203                         goto err;
204                 if (cur->offset < adapter->guest->irq_base_offset)
205                         adapter->guest->irq_base_offset = cur->offset;
206                 if (cxl_verbose)
207                         pr_info("available IRQ range: %#lx-%#lx (%lu)\n",
208                                 cur->offset, cur->offset + cur->range - 1,
209                                 cur->range);
210         }
211         adapter->guest->irq_nranges = nranges;
212         spin_lock_init(&adapter->guest->irq_alloc_lock);
213
214         return 0;
215 err:
216         for (i--; i >= 0; i--) {
217                 cur = &adapter->guest->irq_avail[i];
218                 bitmap_free(cur->bitmap);
219         }
220         kfree(adapter->guest->irq_avail);
221         adapter->guest->irq_avail = NULL;
222         return -ENOMEM;
223 }
224
225 int cxl_of_read_adapter_handle(struct cxl *adapter, struct device_node *np)
226 {
227         return of_property_read_reg(np, 0, &adapter->guest->handle, NULL);
228 }
229
230 int cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np)
231 {
232         int rc;
233         const char *p;
234         u32 val = 0;
235
236         /* Properties are read in the same order as listed in PAPR */
237
238         if ((rc = read_adapter_irq_config(adapter, np)))
239                 return rc;
240
241         if (!of_property_read_u32(np, "ibm,caia-version", &val)) {
242                 adapter->caia_major = (val & 0xFF00) >> 8;
243                 adapter->caia_minor = val & 0xFF;
244         }
245
246         if (!of_property_read_u32(np, "ibm,psl-revision", &val))
247                 adapter->psl_rev = val;
248
249         if (!of_property_read_string(np, "status", &p)) {
250                 adapter->guest->status = kasprintf(GFP_KERNEL, "%s", p);
251                 if (adapter->guest->status == NULL)
252                         return -ENOMEM;
253         }
254
255         if (!of_property_read_u32(np, "vendor-id", &val))
256                 adapter->guest->vendor = val;
257
258         if (!of_property_read_u32(np, "device-id", &val))
259                 adapter->guest->device = val;
260
261         if (!of_property_read_u32(np, "subsystem-vendor-id", &val))
262                 adapter->guest->subsystem_vendor = val;
263
264         if (!of_property_read_u32(np, "subsystem-id", &val))
265                 adapter->guest->subsystem = val;
266
267         if (cxl_verbose)
268                 read_vpd(adapter, NULL);
269
270         return 0;
271 }
272
273 static void cxl_of_remove(struct platform_device *pdev)
274 {
275         struct cxl *adapter;
276         int afu;
277
278         adapter = dev_get_drvdata(&pdev->dev);
279         for (afu = 0; afu < adapter->slices; afu++)
280                 cxl_guest_remove_afu(adapter->afu[afu]);
281
282         cxl_guest_remove_adapter(adapter);
283 }
284
285 static void cxl_of_shutdown(struct platform_device *pdev)
286 {
287         cxl_of_remove(pdev);
288 }
289
290 int cxl_of_probe(struct platform_device *pdev)
291 {
292         struct device_node *np = NULL;
293         struct device_node *afu_np = NULL;
294         struct cxl *adapter = NULL;
295         int ret;
296         int slice = 0, slice_ok = 0;
297
298         dev_err_once(&pdev->dev, "DEPRECATION: cxl is deprecated and will be removed in a future kernel release\n");
299
300         pr_devel("in %s\n", __func__);
301
302         np = pdev->dev.of_node;
303         if (np == NULL)
304                 return -ENODEV;
305
306         /* init adapter */
307         adapter = cxl_guest_init_adapter(np, pdev);
308         if (IS_ERR(adapter)) {
309                 dev_err(&pdev->dev, "guest_init_adapter failed: %li\n", PTR_ERR(adapter));
310                 return PTR_ERR(adapter);
311         }
312
313         /* init afu */
314         for_each_child_of_node(np, afu_np) {
315                 if ((ret = cxl_guest_init_afu(adapter, slice, afu_np)))
316                         dev_err(&pdev->dev, "AFU %i failed to initialise: %i\n",
317                                 slice, ret);
318                 else
319                         slice_ok++;
320                 slice++;
321         }
322
323         if (slice_ok == 0) {
324                 dev_info(&pdev->dev, "No active AFU");
325                 adapter->slices = 0;
326         }
327
328         return 0;
329 }
330
331 static const struct of_device_id cxl_of_match[] = {
332         { .compatible = "ibm,coherent-platform-facility",},
333         {},
334 };
335 MODULE_DEVICE_TABLE(of, cxl_of_match);
336
337 struct platform_driver cxl_of_driver = {
338         .driver = {
339                 .name = "cxl_of",
340                 .of_match_table = cxl_of_match,
341                 .owner = THIS_MODULE
342         },
343         .probe = cxl_of_probe,
344         .remove = cxl_of_remove,
345         .shutdown = cxl_of_shutdown,
346 };
This page took 0.052878 seconds and 4 git commands to generate.