mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
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:
commit
9411aacd72
@ -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 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 = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = ish_pci_tbl,
|
||||
@ -388,6 +432,7 @@ static struct pci_driver ish_driver = {
|
||||
.remove = ish_remove,
|
||||
.shutdown = ish_shutdown,
|
||||
.driver.pm = &ish_pm_ops,
|
||||
.dev_groups = ish_firmware_groups,
|
||||
};
|
||||
|
||||
module_pci_driver(ish_driver);
|
||||
|
@ -70,10 +70,10 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
|
||||
unsigned char *payload;
|
||||
struct device_info *dev_info;
|
||||
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;
|
||||
struct report_list *reports_list;
|
||||
char *reports;
|
||||
struct report *report;
|
||||
size_t report_len;
|
||||
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
|
||||
int curr_hid_dev = client_data->cur_hid_dev;
|
||||
@ -280,14 +280,13 @@ do_get_report:
|
||||
case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
|
||||
report_type = HID_INPUT_REPORT;
|
||||
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++) {
|
||||
recv_msg = (struct hostif_msg *)(reports +
|
||||
sizeof(uint16_t));
|
||||
report_len = *(uint16_t *)reports;
|
||||
payload = reports + sizeof(uint16_t) +
|
||||
sizeof(struct hostif_msg_hdr);
|
||||
recv_msg = container_of(&report->msg,
|
||||
struct hostif_msg, hdr);
|
||||
report_len = report->size;
|
||||
payload = recv_msg->payload;
|
||||
payload_len = report_len -
|
||||
sizeof(struct hostif_msg_hdr);
|
||||
|
||||
@ -304,7 +303,7 @@ do_get_report:
|
||||
0);
|
||||
}
|
||||
|
||||
reports += sizeof(uint16_t) + report_len;
|
||||
report += sizeof(*report) + payload_len;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -316,12 +315,12 @@ do_get_report:
|
||||
|
||||
}
|
||||
|
||||
if (!cur_pos && cur_pos + payload_len +
|
||||
sizeof(struct hostif_msg) < total_len)
|
||||
msg_len = payload_len + sizeof(struct hostif_msg);
|
||||
if (!cur_pos && cur_pos + msg_len < total_len)
|
||||
++client_data->multi_packet_cnt;
|
||||
|
||||
cur_pos += payload_len + sizeof(struct hostif_msg);
|
||||
payload += payload_len + sizeof(struct hostif_msg);
|
||||
cur_pos += msg_len;
|
||||
payload += msg_len;
|
||||
|
||||
} while (cur_pos < total_len);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ struct hostif_msg_hdr {
|
||||
|
||||
struct hostif_msg {
|
||||
struct hostif_msg_hdr hdr;
|
||||
uint8_t payload[];
|
||||
} __packed;
|
||||
|
||||
struct hostif_msg_to_sensor {
|
||||
@ -52,15 +53,17 @@ struct ishtp_version {
|
||||
uint16_t build;
|
||||
} __packed;
|
||||
|
||||
struct report {
|
||||
uint16_t size;
|
||||
struct hostif_msg_hdr msg;
|
||||
} __packed;
|
||||
|
||||
/* struct for ISHTP aggregated input data */
|
||||
struct report_list {
|
||||
uint16_t total_size;
|
||||
uint8_t num_of_reports;
|
||||
uint8_t flags;
|
||||
struct {
|
||||
uint16_t size_of_report;
|
||||
uint8_t report[1];
|
||||
} __packed reports[1];
|
||||
struct report reports[];
|
||||
} __packed;
|
||||
|
||||
/* HOSTIF commands */
|
||||
|
@ -140,6 +140,13 @@ struct ishtp_driver_data {
|
||||
char *fw_generation;
|
||||
};
|
||||
|
||||
struct ish_version {
|
||||
u16 major;
|
||||
u16 minor;
|
||||
u16 hotfix;
|
||||
u16 build;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ishtp_device - ISHTP private device struct
|
||||
*/
|
||||
@ -236,6 +243,11 @@ struct ishtp_device {
|
||||
/* Dump to trace buffers if enabled*/
|
||||
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 */
|
||||
unsigned int ipc_rx_cnt;
|
||||
unsigned long long ipc_rx_bytes_cnt;
|
||||
|
@ -308,6 +308,28 @@ static int request_ish_firmware(const struct firmware **firmware_p,
|
||||
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
|
||||
* @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_start start = { .header = cpu_to_le32(start_hdr.val32), };
|
||||
union loader_recv_message recv_msg;
|
||||
struct ish_global_manifest manifest;
|
||||
const struct firmware *ish_fw;
|
||||
void *dma_bufs[FRAGMENT_MAX_NUM] = {};
|
||||
u32 fragment_size;
|
||||
@ -372,7 +395,7 @@ void ishtp_loader_work(struct work_struct *work)
|
||||
if (rv)
|
||||
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_minor,
|
||||
recv_msg.query_ack.version_hotfix,
|
||||
@ -390,6 +413,16 @@ void ishtp_loader_work(struct work_struct *work)
|
||||
continue; /* try again if failed */
|
||||
|
||||
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;
|
||||
} while (--retry);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ishtp-dev.h"
|
||||
@ -228,4 +229,37 @@ struct ish_firmware_variant {
|
||||
*/
|
||||
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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user