-
-
Notifications
You must be signed in to change notification settings - Fork 299
Add the ability to load different IPTS firmware per SKU #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Revert a3a3ed3: "updating 4.19 patches to fix touch and suspend". Calling intel_ipts_cleanup during suspend causes destroy_doorbell to fail. Furthermore, removing intel_ipts_cleanup from suspend does not seem to cause any issues on the Surface Book 1 and 2, and the introduction of the device link in the previous commit may have fixed some of the edge-cases/race conditions that may have made this call necessary in the past. If any issue arises from this, we will deal with it later in a more subtle way. See jakeday#544 for an exhaustive discussion on this.
Note: NVMe part will be merged into Linux 5.3. Remove the part in 0002-suspend.patch when it arrives. For 5.2 - (Reverted NVMe part of 0002-suspend.patch to apply following patch set) - nvme: export get and set features · torvalds/linux@1a87ee6 torvalds/linux@1a87ee6 - nvme-pci: use host managed power state for suspend · torvalds/linux@d916b1b torvalds/linux@d916b1b#diff-bc4c090f021c046a7d256a3fcf86b7da For 4.19, this patch is also applied - nvme-pci: Sync queues on reset · torvalds/linux@d6135c3 torvalds/linux@d6135c3#diff-bc4c090f021c046a7d256a3fcf86b7da See - Surface Book with Performance Base: NVMe SSD breaks suspend (s2idle) · Issue jakeday#123 · jakeday/linux-surface jakeday#123
Update NVMe part of suspend.patch
Integrate the changes discussed in [1] as proposed by @kitakar5525 in [2]. The IPTS suspend/resume mechanism should work without the need for unloading/reloading the corresponding modules, so we comment-out and update the workaround and will handle any issues coming from that via the IPTS drivers. The workaround is not completely removed yet as want to provide an easy-to-apply temporary fix in case anything goes wrong. [1]: jakeday#544 [2]: jakeday#544 (comment)
Using the old script I regulary had the problem, that after resuming from suspend (or hibernate) the wifi would just break. The only way to fix it was to restart network manager, or disable it in the GNOME network settings. I am not a 100% sure *why*, but this change greatly improved the wifi stability after resume. I am running this for like 5 days now and didn't see the wifi breaking once. I suppose, that `modprobe` vs `modprobe -i` is what makes the difference. Signed-off-by: Dorian Stoll <[email protected]>
Improve wifi reliability after resuming from suspend
All calls that load firmware inside the IPTS driver are wrapped with the new ipts_request_firmware function. It requests the model name and SKU from DMI and then tries to load the firmware from the following locations: - intel/ipts/[MODEL NAME]/[MODEL SKU] - intel/ipts/[MODEL NAME] - intel/ipts So for my SB2 13" that would result in: - intel/ipts/Surface_Book_2/Surface_Book_1832 - intel/ipts/Surface_Book_2 - intel/ipts Since `intel/ipts` was the directory that was checked before, merging this would not influence existing installations. However, for new installations, it would be possible to install the firmware blobs for all models without a check at setup. This also makes it possible to package the firmware files and install them through the package manager. Signed-off-by: Dorian Stoll <[email protected]>
|
Thank you for your work! Although I'm happy with a lot of If we want to merge into jakeday repo, I still think all the firmwares should be placed in a one directory. I first thought we have to write a DMI matching code into IPTS driver to achieve this way. |
Regarding firmware embedding if we want to build IPTS driver as a built-in driver.This is not necessarily a issue only on Chromium OS. If we build IPTS as a built-in driver, we might need firmwares also to be as built-in using kernel config (However, if we want to build all the firmware into a kernel, we need to specify a lot of firmware files in References |
|
So I looked into this a bit more and I might have found a way to do this. The problem is that the IPTS driver never interacts with the device that However what I figured out: The ID for IPTS is defined by a device with the (this is from a Surface Laptop DSDT I found online. I checked another other So, what we could do is just search for an ACPI device with that specific path This is a bit more hacky than the approach with model name and SKU, since it For example it could look like this (still using subdirectories, since it makes |
It could be acpi_evaluate_* in drivers/acpi/utils.c |
I ended up using // This is a dummy device, but it reports a _HID that corresponds
// to the version of the IPTS firmware that is required.
#define IPTS_MSHW_ACPI_PATH "\\_SB.TSML"
#define IPTS_FW_PATH_FMT "intel/ipts/%s"
#define IPTS_FW_PATH_FMT_MSHW "intel/ipts/%s/%s"
#define IPTS_FW_CONFIG_FILE "ipts_fw_config.bin"
// [...]
int ipts_request_firmware(ipts_info_t *ipts, const struct firmware **fw,
const char *name, struct device *device)
{
char fw_path[MAX_IOCL_FILE_PATH_LEN];
int ret = 0;
acpi_handle handle;
acpi_status status;
struct acpi_device_info *info;
status = acpi_get_handle(ACPI_ROOT_OBJECT, IPTS_MSHW_ACPI_PATH, &handle);
if (ACPI_FAILURE(status)) {
ipts_dbg(ipts, "Unable to find ACPI device %s: %d\n",
IPTS_MSHW_ACPI_PATH, status);
goto ipts_load_default_fw_path;
}
status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status)) {
ipts_dbg(ipts, "Unable to find ACPI info for device %s: %d\n",
IPTS_MSHW_ACPI_PATH, status);
goto ipts_load_default_fw_path;
}
snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT_MSHW,
info->hardware_id.string, name);
ret = firmware_request_nowarn(fw, fw_path, device);
if (!ret) {
goto ipts_request_firmware_return;
}
ipts_dbg(ipts, "no firmware '%s' found, retrying with more generic path\n",
fw_path);
ipts_load_default_fw_path:
/* No firmware was found for DMI_PRODUCT_NAME, try without DMI parameters */
snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, name);
ret = request_firmware(fw, fw_path, device);
ipts_request_firmware_return:
return ret;
}If you want to try it I can push the updated patch to another branch on my repository. |
|
Pushed the changes for using the MSHW ID, so you guys can take a look: StollD/linux-surface@25b4689 If you decide that this is more suited for merging into jakedays upstream, I |
|
I noticed current IPTS driver will try to work even if However, IPTS will not work properly. What do you think whether IPTS should be stopped if |
|
@kitakar5525 @StollD Sorry it's currently taking me a while to respond, have some University stuff to do. I haven't had the time to test this myself yet, but I have some potential issues with it and some questions:
From the Windows Device Manager, it looks like TSML has it's own driver (Surface Touch Servicing ML). Now this could only be something solely for updating the firmware, but it could also be something like a driver that provides the IPTS driver with the firmware. Unfortunately something like this probably gets a bit complex to implement and I couldn't find a DSDT for a non-Surface device with IPTS to see if that theory works out there, too. DMI-matching with a whitelist and then checking TSML depending on that would also work, but then we could also directly hard-code the firmware names or paths via DMI. So as a quick recap, I think we should create a driver that loads against the MSHW IDs and supplies the firmware to the IPTS MEI driver. This way, other devices using IPTS could have their own driver. In my opinion, this would nicely separate the ME driver from the touch controller specifics. Problem is that this will break things, so we should probably add some module parameters to directly set the firmware files/directories. |
|
@qzed Thank you for your input! What would you think about adding and exporting an function in the IPTS ME part, that allows a model specific driver (e.g. So basically, That way it would still be compatible with existing installations, and other devices using IPTS can add their model detection through a device specific module. Some questions regarding this idea though:
I will look into implementing this tomorrow, but I don't really have experience with developing kernel code, so if you have reservations against the idea, or additional input, please tell me. |
|
I think registering a callback function pointer seem like a good idea. Again, I haven't looked at the firmware-loading code in detail but I think one should be enough.
This will cause a bit of a problem though: We need to decide on an order in which things are getting registered and set-up. Since we would have two independent drivers, we also can't rely on their order loading, i.e. you'd have to make sure that the order is correct, for example by returning |
|
Ok, I implemented a first version of this and it seems to work fine. I added an API to IPTS ME that allows to set a function pointer for loading firmware, and wrote an Currently, when IPTS ME probes for the ME device, it will check if a firmware handler was already registered, and if not return After the link to the companion driver was established, it will redirect all firmware requests to it first. If the companion driver wasn't able to find a firmware, it will try to load it from I hope this solution is fine for you. I will do some more tests but for the moment everything seems stable on my surface. At the same time it still has support for the old firmware layout, given that a matching companion driver is included. But since we have control over that, it shouldn't cause problems for end-users. Regarding other devices who might want to use our IPTS driver: I think I could write a companion driver that isn't automatically loaded. When there is a device that wants to use IPTS without a companion driver, the generic driver could be forced to load through |
I think if we already have fallbacks in the MEI driver, we should rather solve that part via a module parameter that then forces the MEI driver to directly fall back to A small note as I haven't looked at the code yet: You should make sure that setting and clearing the handler function is synchronized properly (e.g. via mutex) and the function cannot be overwritten by a second driver, i.e. if it is non-null and we're trying to set it, return something like
This, of course, requires a bunch of well planned synchronization (something like states, e.g. I also think it might be a good idea to have options to override the file paths directly (like if all paths are overridden, don't wait for the firmware-supply-driver to load), but that can also be implemented later. The rest sounds good to me! Thanks for looking into this! |
See linux-surface/linux-surface#5 for discussion Signed-off-by: Dorian Stoll <[email protected]>
Done, you can make IPTS ignore the missing handler by adding You can also disable the fallback loading (so if the companion driver fails to find firmware, IPTS won't start), by adding
Done (I think)
Done too, it actually already did that yesterday. Regarding issues when suspending: Suspending and reloading the firmware works fine for me. I think the only real issue is if someone manually unloads
I will look into that. Code is here: https://github.com/StollD/linux-surface/tree/ipts-wip |
|
I've rebased v5.2 on master due to some changes there, unfortunately this has created some conflicts. I'll try to look at your code in the next couple of days, but I think a new PR is appropriate when it's ready. Let's keep this one open for discussion until then. |
|
New and improved PR: #7 Closing this one. |
The current v6.9 patches include a fix for the serdev driver probe issue. Therefore, we don't need to build in the serial driver modules any longer.
Some days ago @kitakar5525 mentioned on Gitter that the IPTS driver could be
modified to load different firmware based on which model it is running on.
(This was in the context of platforms where running the setup script is
difficulty if not impossible, and firmware needs to be embedded, like ChromeOS)
This change archives that by redirecting the calls to
request_firmwarefromIPTS into subfolders, using a custom wrapper (
ipts_request_firmware). Thatwrapper requests the model name and SKU from DMI and then tries to load the
firmware from the following locations:
intel/ipts/[MODEL NAME]/[MODEL SKU]intel/ipts/[MODEL NAME]intel/iptsSo for my SB2 13" that would result in:
intel/ipts/Surface_Book_2/Surface_Book_1832intel/ipts/Surface_Book_2intel/iptsSince
intel/iptsis still checked as a fallback if no other firmware wasfound, it would not break existing installations. However, it allows to install
all firmware from jakedays repository at the same time, like this:
This is a
treeoutput of my/lib/firmware/intel/iptsfolder at the moment,and it works fine. I just installed all firmware from the repository, following
the routines from the setup script. I also removed some unused files to make the
output cleaner.
This change also makes it possible to package all the firmware as a .deb /
.pkg.tar.xz / .rpm / etc. and install it through your package manager.
I decided to use directory names, because some of these file names are read
from
ipts_fw_config.binand loaded dynamically at runtime. Since the driverdoesn't have direct control over the filename, and only over the directory path
that it is prefixed with, it was easier to prefix it than to reprocess the
filenames. Sadly I wasn't able to figure out, how to determine that
MSHW0xyznumber from the driver, otherwise we could have done sth. like
intel/ipts/MSHW0137/vendor_kernel.bin. If you have an idea how to do this, Iwould be happy to modify my implementation, since this isn't a very elegant
solution after all.