forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
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,85 @@
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
+/**
208
+ * get_dvsec_vendor0() - Find a related PCI device (function 0)
209
+ * @dev: PCI device to match
210
+ * @dev0: The PCI device (function 0) found
211
+ * @out_pos: The position of PCI device (function 0)
212
+ *
213
+ * Returns 0 on success, negative on failure.
214
+ *
215
+ * NOTE: If it's successful, the reference of dev0 is increased,
216
+ * so after using it, the callers must call pci_dev_put() to give
217
+ * up the reference.
218
+ */
219
+static int get_dvsec_vendor0(struct pci_dev *dev, struct pci_dev **dev0,
220
+ int *out_pos)
221
+{
222
+ int pos;
223
+
224
+ if (PCI_FUNC(dev->devfn) != 0) {
225
+ dev = get_function_0(dev);
226
+ if (!dev)
227
+ return -1;
228
+ } else {
229
+ dev = pci_dev_get(dev);
230
+ }
231
+ pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID);
232
+ if (!pos) {
233
+ pci_dev_put(dev);
234
+ return -1;
235
+ }
236
+ *dev0 = dev;
237
+ *out_pos = pos;
238
+ return 0;
239
+}
240
+
241
+int ocxl_config_get_reset_reload(struct pci_dev *dev, int *val)
242
+{
243
+ struct pci_dev *dev0;
244
+ u32 reset_reload;
245
+ int pos;
246
+
247
+ if (get_dvsec_vendor0(dev, &dev0, &pos))
248
+ return -1;
249
+
250
+ pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
251
+ &reset_reload);
252
+ pci_dev_put(dev0);
253
+ *val = !!(reset_reload & BIT(0));
254
+ return 0;
255
+}
256
+
257
+int ocxl_config_set_reset_reload(struct pci_dev *dev, int val)
258
+{
259
+ struct pci_dev *dev0;
260
+ u32 reset_reload;
261
+ int pos;
262
+
263
+ if (get_dvsec_vendor0(dev, &dev0, &pos))
264
+ return -1;
265
+
266
+ pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
267
+ &reset_reload);
268
+ if (val)
269
+ reset_reload |= BIT(0);
270
+ else
271
+ reset_reload &= ~BIT(0);
272
+ pci_write_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
273
+ reset_reload);
274
+ pci_dev_put(dev0);
184275 return 0;
185276 }
186277
....@@ -205,11 +296,7 @@
205296 {
206297 int rc;
207298
208
- rc = read_pasid(dev, fn);
209
- if (rc) {
210
- dev_err(&dev->dev, "Invalid PASID configuration: %d\n", rc);
211
- return -ENODEV;
212
- }
299
+ read_pasid(dev, fn);
213300
214301 rc = read_dvsec_tl(dev, fn);
215302 if (rc) {
....@@ -274,37 +361,74 @@
274361 return 0;
275362 }
276363
364
+/**
365
+ * read_template_version() - Read the template version from the AFU
366
+ * @dev: the device for the AFU
367
+ * @fn: the AFU offsets
368
+ * @len: outputs the template length
369
+ * @version: outputs the major<<8,minor version
370
+ *
371
+ * Returns 0 on success, negative on failure
372
+ */
373
+static int read_template_version(struct pci_dev *dev, struct ocxl_fn_config *fn,
374
+ u16 *len, u16 *version)
375
+{
376
+ u32 val32;
377
+ u8 major, minor;
378
+ int rc;
379
+
380
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val32);
381
+ if (rc)
382
+ return rc;
383
+
384
+ *len = EXTRACT_BITS(val32, 16, 31);
385
+ major = EXTRACT_BITS(val32, 8, 15);
386
+ minor = EXTRACT_BITS(val32, 0, 7);
387
+ *version = (major << 8) + minor;
388
+ return 0;
389
+}
390
+
277391 int ocxl_config_check_afu_index(struct pci_dev *dev,
278392 struct ocxl_fn_config *fn, int afu_idx)
279393 {
280
- u32 val;
281
- int rc, templ_major, templ_minor, len;
394
+ int rc;
395
+ u16 templ_version;
396
+ u16 len, expected_len;
282397
283398 pci_write_config_byte(dev,
284399 fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
285400 afu_idx);
286
- rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val);
401
+
402
+ rc = read_template_version(dev, fn, &len, &templ_version);
287403 if (rc)
288404 return rc;
289405
290
- /* AFU index map can have holes */
291
- if (!val)
406
+ /* AFU index map can have holes, in which case we read all 0's */
407
+ if (!templ_version && !len)
292408 return 0;
293409
294
- templ_major = EXTRACT_BITS(val, 8, 15);
295
- templ_minor = EXTRACT_BITS(val, 0, 7);
296410 dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n",
297
- templ_major, templ_minor);
411
+ templ_version >> 8, templ_version & 0xFF);
298412
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);
413
+ switch (templ_version) {
414
+ case 0x0005: // v0.5 was used prior to the spec approval
415
+ case 0x0100:
416
+ expected_len = OCXL_TEMPL_LEN_1_0;
417
+ break;
418
+ case 0x0101:
419
+ expected_len = OCXL_TEMPL_LEN_1_1;
420
+ break;
421
+ default:
422
+ dev_warn(&dev->dev, "Unknown AFU template version %#x\n",
423
+ templ_version);
424
+ expected_len = len;
304425 }
426
+ if (len != expected_len)
427
+ dev_warn(&dev->dev,
428
+ "Unexpected template length %#x in AFU information, expected %#x for version %#x\n",
429
+ len, expected_len, templ_version);
305430 return 1;
306431 }
307
-EXPORT_SYMBOL_GPL(ocxl_config_check_afu_index);
308432
309433 static int read_afu_name(struct pci_dev *dev, struct ocxl_fn_config *fn,
310434 struct ocxl_afu_config *afu)
....@@ -440,6 +564,102 @@
440564 return 0;
441565 }
442566
567
+/**
568
+ * read_afu_lpc_memory_info() - Populate AFU metadata regarding LPC memory
569
+ * @dev: the device for the AFU
570
+ * @fn: the AFU offsets
571
+ * @afu: the AFU struct to populate the LPC metadata into
572
+ *
573
+ * Returns 0 on success, negative on failure
574
+ */
575
+static int read_afu_lpc_memory_info(struct pci_dev *dev,
576
+ struct ocxl_fn_config *fn,
577
+ struct ocxl_afu_config *afu)
578
+{
579
+ int rc;
580
+ u32 val32;
581
+ u16 templ_version;
582
+ u16 templ_len;
583
+ u64 total_mem_size = 0;
584
+ u64 lpc_mem_size = 0;
585
+
586
+ afu->lpc_mem_offset = 0;
587
+ afu->lpc_mem_size = 0;
588
+ afu->special_purpose_mem_offset = 0;
589
+ afu->special_purpose_mem_size = 0;
590
+ /*
591
+ * For AFUs following template v1.0, the LPC memory covers the
592
+ * total memory. Its size is a power of 2.
593
+ *
594
+ * For AFUs with template >= v1.01, the total memory size is
595
+ * still a power of 2, but it is split in 2 parts:
596
+ * - the LPC memory, whose size can now be anything
597
+ * - the remainder memory is a special purpose memory, whose
598
+ * definition is AFU-dependent. It is not accessible through
599
+ * the usual commands for LPC memory
600
+ */
601
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_ALL_MEM_SZ, &val32);
602
+ if (rc)
603
+ return rc;
604
+
605
+ val32 = EXTRACT_BITS(val32, 0, 7);
606
+ if (!val32)
607
+ return 0; /* No LPC memory */
608
+
609
+ /*
610
+ * The configuration space spec allows for a memory size of up
611
+ * to 2^255 bytes.
612
+ *
613
+ * Current generation hardware uses 56-bit physical addresses,
614
+ * but we won't be able to get near close to that, as we won't
615
+ * have a hole big enough in the memory map. Let it pass in
616
+ * the driver for now. We'll get an error from the firmware
617
+ * when trying to configure something too big.
618
+ */
619
+ total_mem_size = 1ull << val32;
620
+
621
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START, &val32);
622
+ if (rc)
623
+ return rc;
624
+
625
+ afu->lpc_mem_offset = val32;
626
+
627
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START + 4, &val32);
628
+ if (rc)
629
+ return rc;
630
+
631
+ afu->lpc_mem_offset |= (u64) val32 << 32;
632
+
633
+ rc = read_template_version(dev, fn, &templ_len, &templ_version);
634
+ if (rc)
635
+ return rc;
636
+
637
+ if (templ_version >= 0x0101) {
638
+ rc = read_afu_info(dev, fn,
639
+ OCXL_DVSEC_TEMPL_LPC_MEM_SZ, &val32);
640
+ if (rc)
641
+ return rc;
642
+ lpc_mem_size = val32;
643
+
644
+ rc = read_afu_info(dev, fn,
645
+ OCXL_DVSEC_TEMPL_LPC_MEM_SZ + 4, &val32);
646
+ if (rc)
647
+ return rc;
648
+ lpc_mem_size |= (u64) val32 << 32;
649
+ } else {
650
+ lpc_mem_size = total_mem_size;
651
+ }
652
+ afu->lpc_mem_size = lpc_mem_size;
653
+
654
+ if (lpc_mem_size < total_mem_size) {
655
+ afu->special_purpose_mem_offset =
656
+ afu->lpc_mem_offset + lpc_mem_size;
657
+ afu->special_purpose_mem_size =
658
+ total_mem_size - lpc_mem_size;
659
+ }
660
+ return 0;
661
+}
662
+
443663 int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
444664 struct ocxl_afu_config *afu, u8 afu_idx)
445665 {
....@@ -473,10 +693,9 @@
473693 if (rc)
474694 return rc;
475695
476
- rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MEM_SZ, &val32);
696
+ rc = read_afu_lpc_memory_info(dev, fn, afu);
477697 if (rc)
478698 return rc;
479
- afu->log_mem_size = EXTRACT_BITS(val32, 0, 7);
480699
481700 rc = read_afu_control(dev, afu);
482701 if (rc)
....@@ -493,7 +712,12 @@
493712 dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar);
494713 dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset);
495714 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);
715
+ dev_dbg(&dev->dev, " lpc_mem offset = %#llx\n", afu->lpc_mem_offset);
716
+ dev_dbg(&dev->dev, " lpc_mem size = %#llx\n", afu->lpc_mem_size);
717
+ dev_dbg(&dev->dev, " special purpose mem offset = %#llx\n",
718
+ afu->special_purpose_mem_offset);
719
+ dev_dbg(&dev->dev, " special purpose mem size = %#llx\n",
720
+ afu->special_purpose_mem_size);
497721 dev_dbg(&dev->dev, " pasid supported (log) = %u\n",
498722 afu->pasid_supported_log);
499723 dev_dbg(&dev->dev, " actag supported = %u\n",
....@@ -540,7 +764,6 @@
540764 {
541765 return pnv_ocxl_get_pasid_count(dev, count);
542766 }
543
-EXPORT_SYMBOL_GPL(ocxl_config_get_pasid_info);
544767
545768 void ocxl_config_set_afu_pasid(struct pci_dev *dev, int pos, int pasid_base,
546769 u32 pasid_count_log)