platform/x86/intel/tpmi: Add debugfs support for read/write blocked
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Mon, 25 Sep 2023 19:42:19 +0000 (12:42 -0700)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Wed, 4 Oct 2023 08:57:32 +0000 (11:57 +0300)
Display read and write blocked status of each TPMI feature in addition
to disabled and locked status.

This will require reading of read/write blocked state from the hardware.
Currently tpmi_read_feature_status(), doesn't provide this state.

Define TPMI feature state as defined in the TPMI spec. Modify the function
tpmi_read_feature_status() to update full feature state instead of just
disabled and locked state.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Link: https://lore.kernel.org/r/20230925194219.966602-1-srinivas.pandruvada@linux.intel.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
drivers/platform/x86/intel/tpmi.c

index 0a95736d97e4dc3e853fe5c407e17d495cbb64ad..311abcac894a63c005d571a34c9ab23c4c536b2f 100644 (file)
@@ -143,6 +143,33 @@ struct tpmi_info_header {
        u64 lock:1;
 } __packed;
 
+/**
+ * struct tpmi_feature_state - Structure to read hardware state of a feature
+ * @enabled:   Enable state of a feature, 1: enabled, 0: disabled
+ * @reserved_1:        Reserved for future use
+ * @write_blocked: Writes are blocked means all write operations are ignored
+ * @read_blocked: Reads are blocked means will read 0xFFs
+ * @pcs_select:        Interface used by out of band software, not used in OS
+ * @reserved_2:        Reserved for future use
+ * @id:                TPMI ID of the feature
+ * @reserved_3:        Reserved for future use
+ * @locked:    When set to 1, OS can't change this register.
+ *
+ * The structure is used to read hardware state of a TPMI feature. This
+ * information is used for debug and restricting operations for this feature.
+ */
+struct tpmi_feature_state {
+       u32 enabled:1;
+       u32 reserved_1:3;
+       u32 write_blocked:1;
+       u32 read_blocked:1;
+       u32 pcs_select:1;
+       u32 reserved_2:1;
+       u32 id:8;
+       u32 reserved_3:15;
+       u32 locked:1;
+} __packed;
+
 /*
  * List of supported TMPI IDs.
  * Some TMPI IDs are not used by Linux, so the numbers are not consecutive.
@@ -202,6 +229,7 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
 
 #define TPMI_CONTROL_STATUS_OFFSET     0x00
 #define TPMI_COMMAND_OFFSET            0x08
+#define TMPI_CONTROL_DATA_VAL_OFFSET   0x0c
 
 /*
  * Spec is calling for max 1 seconds to get ownership at the worst
@@ -230,7 +258,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
 
 /* TPMI command data registers */
 #define TMPI_CONTROL_DATA_CMD          GENMASK_ULL(7, 0)
-#define TMPI_CONTROL_DATA_VAL          GENMASK_ULL(63, 32)
 #define TPMI_CONTROL_DATA_VAL_FEATURE  GENMASK_ULL(48, 40)
 
 /* Command to send via control interface */
@@ -240,9 +267,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
 
 #define TPMI_CMD_LEN_MASK              GENMASK_ULL(18, 16)
 
-#define TPMI_STATE_DISABLED            BIT_ULL(0)
-#define TPMI_STATE_LOCKED              BIT_ULL(31)
-
 /* Mutex to complete get feature status without interruption */
 static DEFINE_MUTEX(tpmi_dev_lock);
 
@@ -256,7 +280,7 @@ static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner)
 }
 
 static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id,
-                                   int *locked, int *disabled)
+                                   struct tpmi_feature_state *feature_state)
 {
        u64 control, data;
        int ret;
@@ -306,17 +330,8 @@ static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int featu
        }
 
        /* Response is ready */
-       data = readq(tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET);
-       data = FIELD_GET(TMPI_CONTROL_DATA_VAL, data);
-
-       *disabled = 0;
-       *locked = 0;
-
-       if (!(data & TPMI_STATE_DISABLED))
-               *disabled = 1;
-
-       if (data & TPMI_STATE_LOCKED)
-               *locked = 1;
+       memcpy_fromio(feature_state, tpmi_info->tpmi_control_mem + TMPI_CONTROL_DATA_VAL_OFFSET,
+                     sizeof(*feature_state));
 
        ret = 0;
 
@@ -335,34 +350,50 @@ int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id,
 {
        struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent);
        struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev);
+       struct tpmi_feature_state feature_state;
+       int ret;
+
+       ret = tpmi_read_feature_status(tpmi_info, feature_id, &feature_state);
+       if (ret)
+               return ret;
 
-       return tpmi_read_feature_status(tpmi_info, feature_id, locked, disabled);
+       *locked = feature_state.locked;
+       *disabled = !feature_state.enabled;
+
+       return 0;
 }
 EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI);
 
 static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused)
 {
        struct intel_tpmi_info *tpmi_info = s->private;
+       int locked, disabled, read_blocked, write_blocked;
+       struct tpmi_feature_state feature_state;
        struct intel_tpmi_pm_feature *pfs;
-       int locked, disabled, ret, i;
+       int ret, i;
+
 
        seq_printf(s, "tpmi PFS start offset 0x:%llx\n", tpmi_info->pfs_start);
-       seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\n");
+       seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\tread_blocked\twrite_blocked\n");
        for (i = 0; i < tpmi_info->feature_count; ++i) {
                pfs = &tpmi_info->tpmi_features[i];
-               ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &locked,
-                                              &disabled);
+               ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state);
                if (ret) {
                        locked = 'U';
                        disabled = 'U';
+                       read_blocked = 'U';
+                       write_blocked = 'U';
                } else {
-                       disabled = disabled ? 'Y' : 'N';
-                       locked = locked ? 'Y' : 'N';
+                       disabled = feature_state.enabled ? 'N' : 'Y';
+                       locked = feature_state.locked ? 'Y' : 'N';
+                       read_blocked = feature_state.read_blocked ? 'Y' : 'N';
+                       write_blocked = feature_state.write_blocked ? 'Y' : 'N';
                }
-               seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\n",
+               seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\t\t%c\t\t%c\n",
                           pfs->pfs_header.tpmi_id, pfs->pfs_header.num_entries,
                           pfs->pfs_header.entry_size, pfs->pfs_header.cap_offset,
-                          pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled);
+                          pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled,
+                          read_blocked, write_blocked);
        }
 
        return 0;