summaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei/hw-me.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mei/hw-me.c')
-rw-r--r--drivers/misc/mei/hw-me.c77
1 files changed, 51 insertions, 26 deletions
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 334ab02e1de2..0759c3a668de 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -19,6 +19,7 @@
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
#include "mei_dev.h"
#include "hbm.h"
@@ -228,7 +229,7 @@ static void mei_me_hw_config(struct mei_device *dev)
/* Doesn't change in runtime */
hcsr = mei_hcsr_read(dev);
- dev->hbuf_depth = (hcsr & H_CBD) >> 24;
+ hw->hbuf_depth = (hcsr & H_CBD) >> 24;
reg = 0;
pci_read_config_dword(pdev, PCI_CFG_HFS_1, &reg);
@@ -490,70 +491,82 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
*/
static int mei_me_hbuf_empty_slots(struct mei_device *dev)
{
+ struct mei_me_hw *hw = to_me_hw(dev);
unsigned char filled_slots, empty_slots;
filled_slots = mei_hbuf_filled_slots(dev);
- empty_slots = dev->hbuf_depth - filled_slots;
+ empty_slots = hw->hbuf_depth - filled_slots;
/* check for overflow */
- if (filled_slots > dev->hbuf_depth)
+ if (filled_slots > hw->hbuf_depth)
return -EOVERFLOW;
return empty_slots;
}
/**
- * mei_me_hbuf_max_len - returns size of hw buffer.
+ * mei_me_hbuf_depth - returns depth of the hw buffer.
*
* @dev: the device structure
*
- * Return: size of hw buffer in bytes
+ * Return: size of hw buffer in slots
*/
-static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
+static u32 mei_me_hbuf_depth(const struct mei_device *dev)
{
- return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
-}
+ struct mei_me_hw *hw = to_me_hw(dev);
+ return hw->hbuf_depth;
+}
/**
* mei_me_hbuf_write - writes a message to host hw buffer.
*
* @dev: the device structure
- * @header: mei HECI header of message
- * @buf: message payload will be written
+ * @hdr: header of message
+ * @hdr_len: header length in bytes: must be multiplication of a slot (4bytes)
+ * @data: payload
+ * @data_len: payload length in bytes
*
- * Return: -EIO if write has failed
+ * Return: 0 if success, < 0 - otherwise.
*/
static int mei_me_hbuf_write(struct mei_device *dev,
- struct mei_msg_hdr *header,
- const unsigned char *buf)
+ const void *hdr, size_t hdr_len,
+ const void *data, size_t data_len)
{
unsigned long rem;
- unsigned long length = header->length;
- u32 *reg_buf = (u32 *)buf;
+ unsigned long i;
+ const u32 *reg_buf;
u32 dw_cnt;
- int i;
int empty_slots;
- dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
+ if (WARN_ON(!hdr || !data || hdr_len & 0x3))
+ return -EINVAL;
+
+ dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr));
empty_slots = mei_hbuf_empty_slots(dev);
dev_dbg(dev->dev, "empty slots = %hu.\n", empty_slots);
- dw_cnt = mei_data2slots(length);
- if (empty_slots < 0 || dw_cnt > empty_slots)
+ if (empty_slots < 0)
+ return -EOVERFLOW;
+
+ dw_cnt = mei_data2slots(hdr_len + data_len);
+ if (dw_cnt > (u32)empty_slots)
return -EMSGSIZE;
- mei_me_hcbww_write(dev, *((u32 *) header));
+ reg_buf = hdr;
+ for (i = 0; i < hdr_len / MEI_SLOT_SIZE; i++)
+ mei_me_hcbww_write(dev, reg_buf[i]);
- for (i = 0; i < length / 4; i++)
+ reg_buf = data;
+ for (i = 0; i < data_len / MEI_SLOT_SIZE; i++)
mei_me_hcbww_write(dev, reg_buf[i]);
- rem = length & 0x3;
+ rem = data_len & 0x3;
if (rem > 0) {
u32 reg = 0;
- memcpy(&reg, &buf[length - rem], rem);
+ memcpy(&reg, (const u8 *)data + data_len - rem, rem);
mei_me_hcbww_write(dev, reg);
}
@@ -601,11 +614,11 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
* Return: always 0
*/
static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
- unsigned long buffer_length)
+ unsigned long buffer_length)
{
u32 *reg_buf = (u32 *)buffer;
- for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
+ for (; buffer_length >= MEI_SLOT_SIZE; buffer_length -= MEI_SLOT_SIZE)
*reg_buf++ = mei_me_mecbrw_read(dev);
if (buffer_length > 0) {
@@ -1314,7 +1327,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
.hbuf_free_slots = mei_me_hbuf_empty_slots,
.hbuf_is_ready = mei_me_hbuf_is_empty,
- .hbuf_max_len = mei_me_hbuf_max_len,
+ .hbuf_depth = mei_me_hbuf_depth,
.write = mei_me_hbuf_write,
@@ -1377,6 +1390,11 @@ static bool mei_me_fw_type_sps(struct pci_dev *pdev)
.fw_status.status[4] = PCI_CFG_HFS_5, \
.fw_status.status[5] = PCI_CFG_HFS_6
+#define MEI_CFG_DMA_128 \
+ .dma_size[DMA_DSCR_HOST] = SZ_128K, \
+ .dma_size[DMA_DSCR_DEVICE] = SZ_128K, \
+ .dma_size[DMA_DSCR_CTRL] = PAGE_SIZE
+
/* ICH Legacy devices */
static const struct mei_cfg mei_me_ich_cfg = {
MEI_CFG_ICH_HFS,
@@ -1409,6 +1427,12 @@ static const struct mei_cfg mei_me_pch8_sps_cfg = {
MEI_CFG_FW_SPS,
};
+/* Cannon Lake and newer devices */
+static const struct mei_cfg mei_me_pch12_cfg = {
+ MEI_CFG_PCH8_HFS,
+ MEI_CFG_DMA_128,
+};
+
/*
* mei_cfg_list - A list of platform platform specific configurations.
* Note: has to be synchronized with enum mei_cfg_idx.
@@ -1421,6 +1445,7 @@ static const struct mei_cfg *const mei_cfg_list[] = {
[MEI_ME_PCH_CPT_PBG_CFG] = &mei_me_pch_cpt_pbg_cfg,
[MEI_ME_PCH8_CFG] = &mei_me_pch8_cfg,
[MEI_ME_PCH8_SPS_CFG] = &mei_me_pch8_sps_cfg,
+ [MEI_ME_PCH12_CFG] = &mei_me_pch12_cfg,
};
const struct mei_cfg *mei_me_get_cfg(kernel_ulong_t idx)