Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 04dd3661 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman
Browse files

mei: extract fw status registers



Fetch FW status registers, as they are important in
in understanding of FW reset reasons

Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 61a1aea7
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -696,10 +696,65 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
	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,
+1 −1
Original line number Diff line number Diff line
@@ -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 */

+36 −1
Original line number Diff line number Diff line
@@ -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 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
	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,
+7 −3
Original line number Diff line number Diff line
@@ -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
+28 −0
Original line number Diff line number Diff line
@@ -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);