Merge branch 'for-6.13/intel-ish' into for-linus

- exposing firmware versions for Intel-ISH devices that load
  firmware from the host (Zhang Lixu)
- switch to flex-array members (Erick Archer)
This commit is contained in:
Jiri Kosina 2024-11-18 21:55:04 +01:00
commit 9411aacd72
6 changed files with 144 additions and 18 deletions

View File

@ -381,6 +381,50 @@ static int __maybe_unused ish_resume(struct device *device)
static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume); static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume);
static ssize_t base_version_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct ishtp_device *dev = dev_get_drvdata(cdev);
return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->base_ver.major,
dev->base_ver.minor, dev->base_ver.hotfix,
dev->base_ver.build);
}
static DEVICE_ATTR_RO(base_version);
static ssize_t project_version_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct ishtp_device *dev = dev_get_drvdata(cdev);
return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->prj_ver.major,
dev->prj_ver.minor, dev->prj_ver.hotfix,
dev->prj_ver.build);
}
static DEVICE_ATTR_RO(project_version);
static struct attribute *ish_firmware_attrs[] = {
&dev_attr_base_version.attr,
&dev_attr_project_version.attr,
NULL
};
static umode_t firmware_is_visible(struct kobject *kobj, struct attribute *attr,
int i)
{
struct ishtp_device *dev = dev_get_drvdata(kobj_to_dev(kobj));
return dev->driver_data->fw_generation ? attr->mode : 0;
}
static const struct attribute_group ish_firmware_group = {
.name = "firmware",
.attrs = ish_firmware_attrs,
.is_visible = firmware_is_visible,
};
__ATTRIBUTE_GROUPS(ish_firmware);
static struct pci_driver ish_driver = { static struct pci_driver ish_driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.id_table = ish_pci_tbl, .id_table = ish_pci_tbl,
@ -388,6 +432,7 @@ static struct pci_driver ish_driver = {
.remove = ish_remove, .remove = ish_remove,
.shutdown = ish_shutdown, .shutdown = ish_shutdown,
.driver.pm = &ish_pm_ops, .driver.pm = &ish_pm_ops,
.dev_groups = ish_firmware_groups,
}; };
module_pci_driver(ish_driver); module_pci_driver(ish_driver);

View File

@ -70,10 +70,10 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
unsigned char *payload; unsigned char *payload;
struct device_info *dev_info; struct device_info *dev_info;
int i, j; int i, j;
size_t payload_len, total_len, cur_pos, raw_len; size_t payload_len, total_len, cur_pos, raw_len, msg_len;
int report_type; int report_type;
struct report_list *reports_list; struct report_list *reports_list;
char *reports; struct report *report;
size_t report_len; size_t report_len;
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
int curr_hid_dev = client_data->cur_hid_dev; int curr_hid_dev = client_data->cur_hid_dev;
@ -280,14 +280,13 @@ do_get_report:
case HOSTIF_PUBLISH_INPUT_REPORT_LIST: case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
report_type = HID_INPUT_REPORT; report_type = HID_INPUT_REPORT;
reports_list = (struct report_list *)payload; reports_list = (struct report_list *)payload;
reports = (char *)reports_list->reports; report = reports_list->reports;
for (j = 0; j < reports_list->num_of_reports; j++) { for (j = 0; j < reports_list->num_of_reports; j++) {
recv_msg = (struct hostif_msg *)(reports + recv_msg = container_of(&report->msg,
sizeof(uint16_t)); struct hostif_msg, hdr);
report_len = *(uint16_t *)reports; report_len = report->size;
payload = reports + sizeof(uint16_t) + payload = recv_msg->payload;
sizeof(struct hostif_msg_hdr);
payload_len = report_len - payload_len = report_len -
sizeof(struct hostif_msg_hdr); sizeof(struct hostif_msg_hdr);
@ -304,7 +303,7 @@ do_get_report:
0); 0);
} }
reports += sizeof(uint16_t) + report_len; report += sizeof(*report) + payload_len;
} }
break; break;
default: default:
@ -316,12 +315,12 @@ do_get_report:
} }
if (!cur_pos && cur_pos + payload_len + msg_len = payload_len + sizeof(struct hostif_msg);
sizeof(struct hostif_msg) < total_len) if (!cur_pos && cur_pos + msg_len < total_len)
++client_data->multi_packet_cnt; ++client_data->multi_packet_cnt;
cur_pos += payload_len + sizeof(struct hostif_msg); cur_pos += msg_len;
payload += payload_len + sizeof(struct hostif_msg); payload += msg_len;
} while (cur_pos < total_len); } while (cur_pos < total_len);
} }

View File

@ -31,6 +31,7 @@ struct hostif_msg_hdr {
struct hostif_msg { struct hostif_msg {
struct hostif_msg_hdr hdr; struct hostif_msg_hdr hdr;
uint8_t payload[];
} __packed; } __packed;
struct hostif_msg_to_sensor { struct hostif_msg_to_sensor {
@ -52,15 +53,17 @@ struct ishtp_version {
uint16_t build; uint16_t build;
} __packed; } __packed;
struct report {
uint16_t size;
struct hostif_msg_hdr msg;
} __packed;
/* struct for ISHTP aggregated input data */ /* struct for ISHTP aggregated input data */
struct report_list { struct report_list {
uint16_t total_size; uint16_t total_size;
uint8_t num_of_reports; uint8_t num_of_reports;
uint8_t flags; uint8_t flags;
struct { struct report reports[];
uint16_t size_of_report;
uint8_t report[1];
} __packed reports[1];
} __packed; } __packed;
/* HOSTIF commands */ /* HOSTIF commands */

View File

@ -140,6 +140,13 @@ struct ishtp_driver_data {
char *fw_generation; char *fw_generation;
}; };
struct ish_version {
u16 major;
u16 minor;
u16 hotfix;
u16 build;
};
/** /**
* struct ishtp_device - ISHTP private device struct * struct ishtp_device - ISHTP private device struct
*/ */
@ -236,6 +243,11 @@ struct ishtp_device {
/* Dump to trace buffers if enabled*/ /* Dump to trace buffers if enabled*/
ishtp_print_log print_log; ishtp_print_log print_log;
/* Base version of Intel's released firmware */
struct ish_version base_ver;
/* Vendor-customized project version */
struct ish_version prj_ver;
/* Debug stats */ /* Debug stats */
unsigned int ipc_rx_cnt; unsigned int ipc_rx_cnt;
unsigned long long ipc_rx_bytes_cnt; unsigned long long ipc_rx_bytes_cnt;

View File

@ -308,6 +308,28 @@ static int request_ish_firmware(const struct firmware **firmware_p,
return _request_ish_firmware(firmware_p, filename, dev); return _request_ish_firmware(firmware_p, filename, dev);
} }
static int copy_manifest(const struct firmware *fw, struct ish_global_manifest *manifest)
{
u32 offset;
for (offset = 0; offset + sizeof(*manifest) < fw->size; offset += ISH_MANIFEST_ALIGNMENT) {
memcpy(manifest, fw->data + offset, sizeof(*manifest));
if (le32_to_cpu(manifest->sig_fourcc) == ISH_GLOBAL_SIG)
return 0;
}
return -1;
}
static void copy_ish_version(struct version_in_manifest *src, struct ish_version *dst)
{
dst->major = le16_to_cpu(src->major);
dst->minor = le16_to_cpu(src->minor);
dst->hotfix = le16_to_cpu(src->hotfix);
dst->build = le16_to_cpu(src->build);
}
/** /**
* ishtp_loader_work() - Load the ISHTP firmware * ishtp_loader_work() - Load the ISHTP firmware
* @work: The work structure * @work: The work structure
@ -336,6 +358,7 @@ void ishtp_loader_work(struct work_struct *work)
struct loader_xfer_query query = { .header = cpu_to_le32(query_hdr.val32), }; struct loader_xfer_query query = { .header = cpu_to_le32(query_hdr.val32), };
struct loader_start start = { .header = cpu_to_le32(start_hdr.val32), }; struct loader_start start = { .header = cpu_to_le32(start_hdr.val32), };
union loader_recv_message recv_msg; union loader_recv_message recv_msg;
struct ish_global_manifest manifest;
const struct firmware *ish_fw; const struct firmware *ish_fw;
void *dma_bufs[FRAGMENT_MAX_NUM] = {}; void *dma_bufs[FRAGMENT_MAX_NUM] = {};
u32 fragment_size; u32 fragment_size;
@ -372,7 +395,7 @@ void ishtp_loader_work(struct work_struct *work)
if (rv) if (rv)
continue; /* try again if failed */ continue; /* try again if failed */
dev_dbg(dev->devc, "ISH Version %u.%u.%u.%u\n", dev_dbg(dev->devc, "ISH Bootloader Version %u.%u.%u.%u\n",
recv_msg.query_ack.version_major, recv_msg.query_ack.version_major,
recv_msg.query_ack.version_minor, recv_msg.query_ack.version_minor,
recv_msg.query_ack.version_hotfix, recv_msg.query_ack.version_hotfix,
@ -390,6 +413,16 @@ void ishtp_loader_work(struct work_struct *work)
continue; /* try again if failed */ continue; /* try again if failed */
dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size); dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size);
if (!copy_manifest(ish_fw, &manifest)) {
copy_ish_version(&manifest.base_ver, &dev->base_ver);
copy_ish_version(&manifest.prj_ver, &dev->prj_ver);
dev_info(dev->devc, "FW base version: %u.%u.%u.%u\n",
dev->base_ver.major, dev->base_ver.minor,
dev->base_ver.hotfix, dev->base_ver.build);
dev_info(dev->devc, "FW project version: %u.%u.%u.%u\n",
dev->prj_ver.major, dev->prj_ver.minor,
dev->prj_ver.hotfix, dev->prj_ver.build);
}
break; break;
} while (--retry); } while (--retry);

View File

@ -10,6 +10,7 @@
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/sizes.h>
#include <linux/types.h> #include <linux/types.h>
#include "ishtp-dev.h" #include "ishtp-dev.h"
@ -228,4 +229,37 @@ struct ish_firmware_variant {
*/ */
void ishtp_loader_work(struct work_struct *work); void ishtp_loader_work(struct work_struct *work);
/* ISH Manifest alignment in binary is 4KB aligned */
#define ISH_MANIFEST_ALIGNMENT SZ_4K
/* Signature for ISH global manifest */
#define ISH_GLOBAL_SIG 0x47485349 /* FourCC 'I', 'S', 'H', 'G' */
struct version_in_manifest {
__le16 major;
__le16 minor;
__le16 hotfix;
__le16 build;
};
/**
* struct ish_global_manifest - global manifest for ISH
* @sig_fourcc: Signature FourCC, should be 'I', 'S', 'H', 'G'.
* @len: Length of the manifest.
* @header_version: Version of the manifest header.
* @flags: Flags for additional information.
* @base_ver: Base version of Intel's released firmware.
* @reserved: Reserved space for future use.
* @prj_ver: Vendor-customized project version.
*/
struct ish_global_manifest {
__le32 sig_fourcc;
__le32 len;
__le32 header_version;
__le32 flags;
struct version_in_manifest base_ver;
__le32 reserved[13];
struct version_in_manifest prj_ver;
};
#endif /* _ISHTP_LOADER_H_ */ #endif /* _ISHTP_LOADER_H_ */