mei: extract fw status registers
authorAlexander Usyskin <alexander.usyskin@intel.com>
Mon, 31 Mar 2014 14:59:23 +0000 (17:59 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 3 May 2014 23:21:22 +0000 (19:21 -0400)
Fetch FW status registers, as they are important in
in understanding of FW reset reasons

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/hw-me.c
drivers/misc/mei/hw-txe-regs.h
drivers/misc/mei/hw-txe.c
drivers/misc/mei/init.c
drivers/misc/mei/mei_dev.h

index 4b048b67a248375e1c033ec675d41e4452808ef1..a31bc4c36cca8f4680579f8ea4ec65b23c737224 100644 (file)
@@ -696,10 +696,65 @@ end:
        mutex_unlock(&dev->device_lock);
        return IRQ_HANDLED;
 }
+
+/**
+ * mei_me_fw_status - retrieve fw status from the pci config space
+ *
+ * @dev: the device structure
+ * @fw_status: fw status registers storage
+ *
+ * returns 0 on success an error code otherwise
+ */
+static int mei_me_fw_status(struct mei_device *dev,
+                           struct mei_fw_status *fw_status)
+{
+       const u32 pci_cfg_reg[] = {PCI_CFG_HFS_1, PCI_CFG_HFS_2};
+       int i;
+
+       if (!fw_status)
+               return -EINVAL;
+
+       switch (dev->pdev->device) {
+       case MEI_DEV_ID_IBXPK_1:
+       case MEI_DEV_ID_IBXPK_2:
+       case MEI_DEV_ID_CPT_1:
+       case MEI_DEV_ID_PBG_1:
+       case MEI_DEV_ID_PPT_1:
+       case MEI_DEV_ID_PPT_2:
+       case MEI_DEV_ID_PPT_3:
+       case MEI_DEV_ID_LPT_H:
+       case MEI_DEV_ID_LPT_W:
+       case MEI_DEV_ID_LPT_LP:
+       case MEI_DEV_ID_LPT_HR:
+       case MEI_DEV_ID_WPT_LP:
+               fw_status->count = 2;
+               break;
+       case MEI_DEV_ID_ICH10_1:
+       case MEI_DEV_ID_ICH10_2:
+       case MEI_DEV_ID_ICH10_3:
+       case MEI_DEV_ID_ICH10_4:
+               fw_status->count = 1;
+               break;
+       default:
+               fw_status->count = 0;
+               break;
+       }
+
+       for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) {
+               int ret;
+               ret = pci_read_config_dword(dev->pdev,
+                               pci_cfg_reg[i], &fw_status->status[i]);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
 static const struct mei_hw_ops mei_me_hw_ops = {
 
        .pg_state  = mei_me_pg_state,
 
+       .fw_status = mei_me_fw_status,
        .host_is_ready = mei_me_host_is_ready,
 
        .hw_is_ready = mei_me_hw_is_ready,
index 7283c24c1af19e8225ba532e4be4f79edbf12478..f19229c4e65586dcb39697e928afa48e7731c0ec 100644 (file)
@@ -89,7 +89,7 @@ enum {
 #  define PCI_CFG_TXE_FW_STS0_ERR_CODE_MSK  0x0000F000
 #  define PCI_CFG_TXE_FW_STS0_OP_MODE_MSK   0x000F0000
 #  define PCI_CFG_TXE_FW_STS0_RST_CNT_MSK   0x00F00000
-
+#define PCI_CFG_TXE_FW_STS1   0x48
 
 #define IPC_BASE_ADDR  0x80400 /* SeC IPC Base Address */
 
index 4a6f567f4f80b0ef0219f12aed4a5af1ad2c4015..455a6a56b82b3b6bbe584a4aabca020211bd70e7 100644 (file)
@@ -620,7 +620,10 @@ static int mei_txe_write(struct mei_device *dev,
        mei_txe_input_ready_interrupt_enable(dev);
 
        if (!mei_txe_is_input_ready(dev)) {
-               dev_err(&dev->pdev->dev, "Input is not ready");
+               struct mei_fw_status fw_status;
+               mei_fw_status(dev, &fw_status);
+               dev_err(&dev->pdev->dev, "Input is not ready " FW_STS_FMT "\n",
+                       FW_STS_PRM(fw_status));
                return -EAGAIN;
        }
 
@@ -1039,8 +1042,40 @@ end:
        return IRQ_HANDLED;
 }
 
+
+/**
+ * mei_txe_fw_status - retrieve fw status from the pci config space
+ *
+ * @dev: the device structure
+ * @fw_status: fw status registers storage
+ *
+ * returns: 0 on success an error code otherwise
+ */
+static int mei_txe_fw_status(struct mei_device *dev,
+                            struct mei_fw_status *fw_status)
+{
+       const u32 pci_cfg_reg[] = {PCI_CFG_TXE_FW_STS0, PCI_CFG_TXE_FW_STS1};
+       int i;
+
+       if (!fw_status)
+               return -EINVAL;
+
+       fw_status->count = 2;
+
+       for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) {
+               int ret;
+               ret = pci_read_config_dword(dev->pdev,
+                               pci_cfg_reg[i], &fw_status->status[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static const struct mei_hw_ops mei_txe_hw_ops = {
 
+       .fw_status = mei_txe_fw_status,
        .host_is_ready = mei_txe_host_is_ready,
 
        .pg_state = mei_txe_pg_state,
index abc5ea053bf7ac28e2af203b592f86e41508cceb..b3f70eb17934b69c9ec03b58cd43d0df276f1b49 100644 (file)
@@ -74,9 +74,13 @@ int mei_reset(struct mei_device *dev)
        if (state != MEI_DEV_INITIALIZING &&
            state != MEI_DEV_DISABLED &&
            state != MEI_DEV_POWER_DOWN &&
-           state != MEI_DEV_POWER_UP)
-               dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
-                        mei_dev_state_str(state));
+           state != MEI_DEV_POWER_UP) {
+               struct mei_fw_status fw_status;
+               mei_fw_status(dev, &fw_status);
+               dev_warn(&dev->pdev->dev,
+                       "unexpected reset: dev_state = %s " FW_STS_FMT "\n",
+                       mei_dev_state_str(state), FW_STS_PRM(fw_status));
+       }
 
        /* we're already in reset, cancel the init timer
         * if the reset was called due the hbm protocol error
index beff9ef319f8c93592a98d90ca479d6d604b5631..1aaaf0b6681c08c6be3c6275a88efcaa4baf0263 100644 (file)
@@ -153,6 +153,20 @@ struct mei_msg_data {
        unsigned char *data;
 };
 
+/* Maximum number of processed FW status registers */
+#define MEI_FW_STATUS_MAX 2
+
+/*
+ * struct mei_fw_status - storage of FW status data
+ *
+ * @count - number of actually available elements in array
+ * @status - FW status registers
+ */
+struct mei_fw_status {
+       int count;
+       u32 status[MEI_FW_STATUS_MAX];
+};
+
 /**
  * struct mei_me_client - representation of me (fw) client
  *
@@ -213,6 +227,7 @@ struct mei_cl {
 
 /** struct mei_hw_ops
  *
+ * @fw_status        - read FW status from PCI config space
  * @host_is_ready    - query for host readiness
 
  * @hw_is_ready      - query if hw is ready
@@ -240,6 +255,8 @@ struct mei_cl {
  */
 struct mei_hw_ops {
 
+       int (*fw_status)(struct mei_device *dev,
+               struct mei_fw_status *fw_status);
        bool (*host_is_ready)(struct mei_device *dev);
 
        bool (*hw_is_ready)(struct mei_device *dev);
@@ -681,6 +698,17 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
        return dev->ops->rdbuf_full_slots(dev);
 }
 
+static inline int mei_fw_status(struct mei_device *dev,
+                               struct mei_fw_status *fw_status)
+{
+       return dev->ops->fw_status(dev, fw_status);
+}
+
+#define FW_STS_FMT "%08X %08X"
+#define FW_STS_PRM(fw_status) \
+       (fw_status).count > 0 ? (fw_status).status[0] : 0xDEADBEEF, \
+       (fw_status).count > 1 ? (fw_status).status[1] : 0xDEADBEEF
+
 bool mei_hbuf_acquire(struct mei_device *dev);
 
 bool mei_write_is_idle(struct mei_device *dev);