aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Wunner <lukas@wunner.de>2016-11-12 16:32:37 -0500
committerIngo Molnar <mingo@kernel.org>2016-11-13 02:23:16 -0500
commitc9cc3aaa0281fec487794a473c82544bb7ac1b68 (patch)
treeaf8885a0dcb9a9f3e4af768a4dfea386b1026efb
parent58c5475aba67706b31d9237808d5d3d54074e5ea (diff)
thunderbolt: Use Device ROM retrieved from EFI
Macs with Thunderbolt 1 do not have a unit-specific DROM: The DROM is empty with uid 0x1000000000000. (Apple started factory-burning a unit- specific DROM with Thunderbolt 2.) Instead, the NHI EFI driver supplies a DROM in a device property. Use it if available. It's only available when booting with the efistub. If it's not available, silently fall back to our hardcoded DROM. The size of the DROM is always 256 bytes. The number is hardcoded into the NHI EFI driver. This commit can deal with an arbitrary size however, just in case they ever change that. Background information: The EFI firmware volume contains ROM files for the NHI, GMUX and several other chips as well as key material. This strategy allows Apple to deploy ROM or key updates by simply publishing an EFI firmware update on their website. Drivers do not access those files directly but rather through a file server via EFI protocol AC5E4829-A8FD-440B-AF33-9FFE013B12D8. Files are identified by GUID, the NHI DROM has 339370BD-CFC6-4454-8EF7-704653120818. The NHI EFI driver amends that file with a unit-specific uid. The uid has 64 bit but its entropy is much lower: 24 bit represent the model, 24 bit are taken from a serial number, 16 bit are fixed. The NHI EFI driver obtains the serial number via the DataHub protocol, copies it into the DROM, calculates the CRC and submits the result as a device property. A modification is needed in the resume code where we currently read the uid of all switches in the hierarchy to detect plug events that occurred during sleep. On Thunderbolt 1 root switches this will now lead to a mismatch between the uid of the empty DROM and the EFI DROM. Exempt the root switch from this check: It's built in, so the uid should never change. However we continue to *read* the uid of the root switch, this seems like a good way to test its reachability after resume. Tested-by: Lukas Wunner <lukas@wunner.de> [MacBookPro9,1] Tested-by: Pierre Moreau <pierre.morrow@free.fr> [MacBookPro11,3] Signed-off-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk> Acked-by: Andreas Noever <andreas.noever@gmail.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Pedro Vilaça <reverser@put.as> Cc: Peter Jones <pjones@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/20161112213237.8804-10-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--drivers/thunderbolt/Kconfig1
-rw-r--r--drivers/thunderbolt/eeprom.c43
-rw-r--r--drivers/thunderbolt/switch.c2
3 files changed, 45 insertions, 1 deletions
diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig
index c121acc15bfe..0056df7f3c09 100644
--- a/drivers/thunderbolt/Kconfig
+++ b/drivers/thunderbolt/Kconfig
@@ -1,6 +1,7 @@
1menuconfig THUNDERBOLT 1menuconfig THUNDERBOLT
2 tristate "Thunderbolt support for Apple devices" 2 tristate "Thunderbolt support for Apple devices"
3 depends on PCI 3 depends on PCI
4 select APPLE_PROPERTIES
4 select CRC32 5 select CRC32
5 help 6 help
6 Cactus Ridge Thunderbolt Controller driver 7 Cactus Ridge Thunderbolt Controller driver
diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c
index 2b9602c2c355..6392990c984d 100644
--- a/drivers/thunderbolt/eeprom.c
+++ b/drivers/thunderbolt/eeprom.c
@@ -5,6 +5,7 @@
5 */ 5 */
6 6
7#include <linux/crc32.h> 7#include <linux/crc32.h>
8#include <linux/property.h>
8#include <linux/slab.h> 9#include <linux/slab.h>
9#include "tb.h" 10#include "tb.h"
10 11
@@ -360,6 +361,40 @@ static int tb_drom_parse_entries(struct tb_switch *sw)
360} 361}
361 362
362/** 363/**
364 * tb_drom_copy_efi - copy drom supplied by EFI to sw->drom if present
365 */
366static int tb_drom_copy_efi(struct tb_switch *sw, u16 *size)
367{
368 struct device *dev = &sw->tb->nhi->pdev->dev;
369 int len, res;
370
371 len = device_property_read_u8_array(dev, "ThunderboltDROM", NULL, 0);
372 if (len < 0 || len < sizeof(struct tb_drom_header))
373 return -EINVAL;
374
375 sw->drom = kmalloc(len, GFP_KERNEL);
376 if (!sw->drom)
377 return -ENOMEM;
378
379 res = device_property_read_u8_array(dev, "ThunderboltDROM", sw->drom,
380 len);
381 if (res)
382 goto err;
383
384 *size = ((struct tb_drom_header *)sw->drom)->data_len +
385 TB_DROM_DATA_START;
386 if (*size > len)
387 goto err;
388
389 return 0;
390
391err:
392 kfree(sw->drom);
393 sw->drom = NULL;
394 return -EINVAL;
395}
396
397/**
363 * tb_drom_read - copy drom to sw->drom and parse it 398 * tb_drom_read - copy drom to sw->drom and parse it
364 */ 399 */
365int tb_drom_read(struct tb_switch *sw) 400int tb_drom_read(struct tb_switch *sw)
@@ -374,6 +409,13 @@ int tb_drom_read(struct tb_switch *sw)
374 409
375 if (tb_route(sw) == 0) { 410 if (tb_route(sw) == 0) {
376 /* 411 /*
412 * Apple's NHI EFI driver supplies a DROM for the root switch
413 * in a device property. Use it if available.
414 */
415 if (tb_drom_copy_efi(sw, &size) == 0)
416 goto parse;
417
418 /*
377 * The root switch contains only a dummy drom (header only, 419 * The root switch contains only a dummy drom (header only,
378 * no entries). Hardcode the configuration here. 420 * no entries). Hardcode the configuration here.
379 */ 421 */
@@ -418,6 +460,7 @@ int tb_drom_read(struct tb_switch *sw)
418 if (res) 460 if (res)
419 goto err; 461 goto err;
420 462
463parse:
421 header = (void *) sw->drom; 464 header = (void *) sw->drom;
422 465
423 if (header->data_len + TB_DROM_DATA_START != size) { 466 if (header->data_len + TB_DROM_DATA_START != size) {
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 9840fdecb73b..c6f30b1695a9 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -460,7 +460,7 @@ int tb_switch_resume(struct tb_switch *sw)
460 tb_sw_warn(sw, "uid read failed\n"); 460 tb_sw_warn(sw, "uid read failed\n");
461 return err; 461 return err;
462 } 462 }
463 if (sw->uid != uid) { 463 if (sw != sw->tb->root_switch && sw->uid != uid) {
464 tb_sw_info(sw, 464 tb_sw_info(sw,
465 "changed while suspended (uid %#llx -> %#llx)\n", 465 "changed while suspended (uid %#llx -> %#llx)\n",
466 sw->uid, uid); 466 sw->uid, uid);