forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/drivers/misc/ocxl/config.c
....@@ -2,8 +2,8 @@
22 // Copyright 2017 IBM Corp.
33 #include <linux/pci.h>
44 #include <asm/pnv-ocxl.h>
5
-#include <misc/ocxl.h>
65 #include <misc/ocxl-config.h>
6
+#include "ocxl_internal.h"
77
88 #define EXTRACT_BIT(val, bit) (!!(val & BIT(bit)))
99 #define EXTRACT_BITS(val, s, e) ((val & GENMASK(e, s)) >> s)
....@@ -20,11 +20,14 @@
2020 #define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28
2121 #define OCXL_DVSEC_TEMPL_MMIO_PP 0x30
2222 #define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38
23
-#define OCXL_DVSEC_TEMPL_MEM_SZ 0x3C
24
-#define OCXL_DVSEC_TEMPL_WWID 0x40
23
+#define OCXL_DVSEC_TEMPL_ALL_MEM_SZ 0x3C
24
+#define OCXL_DVSEC_TEMPL_LPC_MEM_START 0x40
25
+#define OCXL_DVSEC_TEMPL_WWID 0x48
26
+#define OCXL_DVSEC_TEMPL_LPC_MEM_SZ 0x58
2527
2628 #define OCXL_MAX_AFU_PER_FUNCTION 64
27
-#define OCXL_TEMPL_LEN 0x58
29
+#define OCXL_TEMPL_LEN_1_0 0x58
30
+#define OCXL_TEMPL_LEN_1_1 0x60
2831 #define OCXL_TEMPL_NAME_LEN 24
2932 #define OCXL_CFG_TIMEOUT 3
3033
....@@ -68,7 +71,21 @@
6871 return 0;
6972 }
7073
71
-static int read_pasid(struct pci_dev *dev, struct ocxl_fn_config *fn)
74
+/**
75
+ * get_function_0() - Find a related PCI device (function 0)
76
+ * @device: PCI device to match
77
+ *
78
+ * Returns a pointer to the related device, or null if not found
79
+ */
80
+static struct pci_dev *get_function_0(struct pci_dev *dev)
81
+{
82
+ unsigned int devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0);
83
+
84
+ return pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
85
+ dev->bus->number, devfn);
86
+}
87
+
88
+static void read_pasid(struct pci_dev *dev, struct ocxl_fn_config *fn)
7289 {
7390 u16 val;
7491 int pos;
....@@ -89,7 +106,6 @@
89106 out:
90107 dev_dbg(&dev->dev, "PASID capability:\n");
91108 dev_dbg(&dev->dev, " Max PASID log = %d\n", fn->max_pasid_log);
92
- return 0;
93109 }
94110
95111 static int read_dvsec_tl(struct pci_dev *dev, struct ocxl_fn_config *fn)
....@@ -157,14 +173,15 @@
157173 static int read_dvsec_vendor(struct pci_dev *dev)
158174 {
159175 int pos;
160
- u32 cfg, tlx, dlx;
176
+ u32 cfg, tlx, dlx, reset_reload;
161177
162178 /*
163
- * vendor specific DVSEC is optional
179
+ * vendor specific DVSEC, for IBM images only. Some older
180
+ * images may not have it
164181 *
165
- * It's currently only used on function 0 to specify the
166
- * version of some logic blocks. Some older images may not
167
- * even have it so we ignore any errors
182
+ * It's only used on function 0 to specify the version of some
183
+ * logic blocks and to give access to special registers to
184
+ * enable host-based flashing.
168185 */
169186 if (PCI_FUNC(dev->devfn) != 0)
170187 return 0;
....@@ -176,11 +193,67 @@
176193 pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_CFG_VERS, &cfg);
177194 pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_TLX_VERS, &tlx);
178195 pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_DLX_VERS, &dlx);
196
+ pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
197
+ &reset_reload);
179198
180199 dev_dbg(&dev->dev, "Vendor specific DVSEC:\n");
181200 dev_dbg(&dev->dev, " CFG version = 0x%x\n", cfg);
182201 dev_dbg(&dev->dev, " TLX version = 0x%x\n", tlx);
183202 dev_dbg(&dev->dev, " DLX version = 0x%x\n", dlx);
203
+ dev_dbg(&dev->dev, " ResetReload = 0x%x\n", reset_reload);
204
+ return 0;
205
+}
206
+
207
+static int get_dvsec_vendor0(struct pci_dev *dev, struct pci_dev **dev0,
208
+ int *out_pos)
209
+{
210
+ int pos;
211
+
212
+ if (PCI_FUNC(dev->devfn) != 0) {
213
+ dev = get_function_0(dev);
214
+ if (!dev)
215
+ return -1;
216
+ }
217
+ pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID);
218
+ if (!pos)
219
+ return -1;
220
+ *dev0 = dev;
221
+ *out_pos = pos;
222
+ return 0;
223
+}
224
+
225
+int ocxl_config_get_reset_reload(struct pci_dev *dev, int *val)
226
+{
227
+ struct pci_dev *dev0;
228
+ u32 reset_reload;
229
+ int pos;
230
+
231
+ if (get_dvsec_vendor0(dev, &dev0, &pos))
232
+ return -1;
233
+
234
+ pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
235
+ &reset_reload);
236
+ *val = !!(reset_reload & BIT(0));
237
+ return 0;
238
+}
239
+
240
+int ocxl_config_set_reset_reload(struct pci_dev *dev, int val)
241
+{
242
+ struct pci_dev *dev0;
243
+ u32 reset_reload;
244
+ int pos;
245
+
246
+ if (get_dvsec_vendor0(dev, &dev0, &pos))
247
+ return -1;
248
+
249
+ pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
250
+ &reset_reload);
251
+ if (val)
252
+ reset_reload |= BIT(0);
253
+ else
254
+ reset_reload &= ~BIT(0);
255
+ pci_write_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
256
+ reset_reload);
184257 return 0;
185258 }
186259
....@@ -205,11 +278,7 @@
205278 {
206279 int rc;
207280
208
- rc = read_pasid(dev, fn);
209
- if (rc) {
210
- dev_err(&dev->dev, "Invalid PASID configuration: %d\n", rc);
211
- return -ENODEV;
212
- }
281
+ read_pasid(dev, fn);
213282
214283 rc = read_dvsec_tl(dev, fn);
215284 if (rc) {
....@@ -274,37 +343,74 @@
274343 return 0;
275344 }
276345
346
+/**
347
+ * read_template_version() - Read the template version from the AFU
348
+ * @dev: the device for the AFU
349
+ * @fn: the AFU offsets
350
+ * @len: outputs the template length
351
+ * @version: outputs the major<<8,minor version
352
+ *
353
+ * Returns 0 on success, negative on failure
354
+ */
355
+static int read_template_version(struct pci_dev *dev, struct ocxl_fn_config *fn,
356
+ u16 *len, u16 *version)
357
+{
358
+ u32 val32;
359
+ u8 major, minor;
360
+ int rc;
361
+
362
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val32);
363
+ if (rc)
364
+ return rc;
365
+
366
+ *len = EXTRACT_BITS(val32, 16, 31);
367
+ major = EXTRACT_BITS(val32, 8, 15);
368
+ minor = EXTRACT_BITS(val32, 0, 7);
369
+ *version = (major << 8) + minor;
370
+ return 0;
371
+}
372
+
277373 int ocxl_config_check_afu_index(struct pci_dev *dev,
278374 struct ocxl_fn_config *fn, int afu_idx)
279375 {
280
- u32 val;
281
- int rc, templ_major, templ_minor, len;
376
+ int rc;
377
+ u16 templ_version;
378
+ u16 len, expected_len;
282379
283380 pci_write_config_byte(dev,
284381 fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
285382 afu_idx);
286
- rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val);
383
+
384
+ rc = read_template_version(dev, fn, &len, &templ_version);
287385 if (rc)
288386 return rc;
289387
290
- /* AFU index map can have holes */
291
- if (!val)
388
+ /* AFU index map can have holes, in which case we read all 0's */
389
+ if (!templ_version && !len)
292390 return 0;
293391
294
- templ_major = EXTRACT_BITS(val, 8, 15);
295
- templ_minor = EXTRACT_BITS(val, 0, 7);
296392 dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n",
297
- templ_major, templ_minor);
393
+ templ_version >> 8, templ_version & 0xFF);
298394
299
- len = EXTRACT_BITS(val, 16, 31);
300
- if (len != OCXL_TEMPL_LEN) {
301
- dev_warn(&dev->dev,
302
- "Unexpected template length in AFU information (%#x)\n",
303
- len);
395
+ switch (templ_version) {
396
+ case 0x0005: // v0.5 was used prior to the spec approval
397
+ case 0x0100:
398
+ expected_len = OCXL_TEMPL_LEN_1_0;
399
+ break;
400
+ case 0x0101:
401
+ expected_len = OCXL_TEMPL_LEN_1_1;
402
+ break;
403
+ default:
404
+ dev_warn(&dev->dev, "Unknown AFU template version %#x\n",
405
+ templ_version);
406
+ expected_len = len;
304407 }
408
+ if (len != expected_len)
409
+ dev_warn(&dev->dev,
410
+ "Unexpected template length %#x in AFU information, expected %#x for version %#x\n",
411
+ len, expected_len, templ_version);
305412 return 1;
306413 }
307
-EXPORT_SYMBOL_GPL(ocxl_config_check_afu_index);
308414
309415 static int read_afu_name(struct pci_dev *dev, struct ocxl_fn_config *fn,
310416 struct ocxl_afu_config *afu)
....@@ -440,6 +546,102 @@
440546 return 0;
441547 }
442548
549
+/**
550
+ * read_afu_lpc_memory_info() - Populate AFU metadata regarding LPC memory
551
+ * @dev: the device for the AFU
552
+ * @fn: the AFU offsets
553
+ * @afu: the AFU struct to populate the LPC metadata into
554
+ *
555
+ * Returns 0 on success, negative on failure
556
+ */
557
+static int read_afu_lpc_memory_info(struct pci_dev *dev,
558
+ struct ocxl_fn_config *fn,
559
+ struct ocxl_afu_config *afu)
560
+{
561
+ int rc;
562
+ u32 val32;
563
+ u16 templ_version;
564
+ u16 templ_len;
565
+ u64 total_mem_size = 0;
566
+ u64 lpc_mem_size = 0;
567
+
568
+ afu->lpc_mem_offset = 0;
569
+ afu->lpc_mem_size = 0;
570
+ afu->special_purpose_mem_offset = 0;
571
+ afu->special_purpose_mem_size = 0;
572
+ /*
573
+ * For AFUs following template v1.0, the LPC memory covers the
574
+ * total memory. Its size is a power of 2.
575
+ *
576
+ * For AFUs with template >= v1.01, the total memory size is
577
+ * still a power of 2, but it is split in 2 parts:
578
+ * - the LPC memory, whose size can now be anything
579
+ * - the remainder memory is a special purpose memory, whose
580
+ * definition is AFU-dependent. It is not accessible through
581
+ * the usual commands for LPC memory
582
+ */
583
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_ALL_MEM_SZ, &val32);
584
+ if (rc)
585
+ return rc;
586
+
587
+ val32 = EXTRACT_BITS(val32, 0, 7);
588
+ if (!val32)
589
+ return 0; /* No LPC memory */
590
+
591
+ /*
592
+ * The configuration space spec allows for a memory size of up
593
+ * to 2^255 bytes.
594
+ *
595
+ * Current generation hardware uses 56-bit physical addresses,
596
+ * but we won't be able to get near close to that, as we won't
597
+ * have a hole big enough in the memory map. Let it pass in
598
+ * the driver for now. We'll get an error from the firmware
599
+ * when trying to configure something too big.
600
+ */
601
+ total_mem_size = 1ull << val32;
602
+
603
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START, &val32);
604
+ if (rc)
605
+ return rc;
606
+
607
+ afu->lpc_mem_offset = val32;
608
+
609
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START + 4, &val32);
610
+ if (rc)
611
+ return rc;
612
+
613
+ afu->lpc_mem_offset |= (u64) val32 << 32;
614
+
615
+ rc = read_template_version(dev, fn, &templ_len, &templ_version);
616
+ if (rc)
617
+ return rc;
618
+
619
+ if (templ_version >= 0x0101) {
620
+ rc = read_afu_info(dev, fn,
621
+ OCXL_DVSEC_TEMPL_LPC_MEM_SZ, &val32);
622
+ if (rc)
623
+ return rc;
624
+ lpc_mem_size = val32;
625
+
626
+ rc = read_afu_info(dev, fn,
627
+ OCXL_DVSEC_TEMPL_LPC_MEM_SZ + 4, &val32);
628
+ if (rc)
629
+ return rc;
630
+ lpc_mem_size |= (u64) val32 << 32;
631
+ } else {
632
+ lpc_mem_size = total_mem_size;
633
+ }
634
+ afu->lpc_mem_size = lpc_mem_size;
635
+
636
+ if (lpc_mem_size < total_mem_size) {
637
+ afu->special_purpose_mem_offset =
638
+ afu->lpc_mem_offset + lpc_mem_size;
639
+ afu->special_purpose_mem_size =
640
+ total_mem_size - lpc_mem_size;
641
+ }
642
+ return 0;
643
+}
644
+
443645 int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
444646 struct ocxl_afu_config *afu, u8 afu_idx)
445647 {
....@@ -473,10 +675,9 @@
473675 if (rc)
474676 return rc;
475677
476
- rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MEM_SZ, &val32);
678
+ rc = read_afu_lpc_memory_info(dev, fn, afu);
477679 if (rc)
478680 return rc;
479
- afu->log_mem_size = EXTRACT_BITS(val32, 0, 7);
480681
481682 rc = read_afu_control(dev, afu);
482683 if (rc)
....@@ -493,7 +694,12 @@
493694 dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar);
494695 dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset);
495696 dev_dbg(&dev->dev, " pp mmio stride = %#x\n", afu->pp_mmio_stride);
496
- dev_dbg(&dev->dev, " mem size (log) = %hhu\n", afu->log_mem_size);
697
+ dev_dbg(&dev->dev, " lpc_mem offset = %#llx\n", afu->lpc_mem_offset);
698
+ dev_dbg(&dev->dev, " lpc_mem size = %#llx\n", afu->lpc_mem_size);
699
+ dev_dbg(&dev->dev, " special purpose mem offset = %#llx\n",
700
+ afu->special_purpose_mem_offset);
701
+ dev_dbg(&dev->dev, " special purpose mem size = %#llx\n",
702
+ afu->special_purpose_mem_size);
497703 dev_dbg(&dev->dev, " pasid supported (log) = %u\n",
498704 afu->pasid_supported_log);
499705 dev_dbg(&dev->dev, " actag supported = %u\n",
....@@ -540,7 +746,6 @@
540746 {
541747 return pnv_ocxl_get_pasid_count(dev, count);
542748 }
543
-EXPORT_SYMBOL_GPL(ocxl_config_get_pasid_info);
544749
545750 void ocxl_config_set_afu_pasid(struct pci_dev *dev, int pos, int pasid_base,
546751 u32 pasid_count_log)