diff options
Diffstat (limited to 'drivers/thunderbolt/eeprom.c')
-rw-r--r-- | drivers/thunderbolt/eeprom.c | 43 |
1 files changed, 43 insertions, 0 deletions
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 @@ */ #include <linux/crc32.h> +#include <linux/property.h> #include <linux/slab.h> #include "tb.h" @@ -360,6 +361,40 @@ static int tb_drom_parse_entries(struct tb_switch *sw) } /** + * tb_drom_copy_efi - copy drom supplied by EFI to sw->drom if present + */ +static int tb_drom_copy_efi(struct tb_switch *sw, u16 *size) +{ + struct device *dev = &sw->tb->nhi->pdev->dev; + int len, res; + + len = device_property_read_u8_array(dev, "ThunderboltDROM", NULL, 0); + if (len < 0 || len < sizeof(struct tb_drom_header)) + return -EINVAL; + + sw->drom = kmalloc(len, GFP_KERNEL); + if (!sw->drom) + return -ENOMEM; + + res = device_property_read_u8_array(dev, "ThunderboltDROM", sw->drom, + len); + if (res) + goto err; + + *size = ((struct tb_drom_header *)sw->drom)->data_len + + TB_DROM_DATA_START; + if (*size > len) + goto err; + + return 0; + +err: + kfree(sw->drom); + sw->drom = NULL; + return -EINVAL; +} + +/** * tb_drom_read - copy drom to sw->drom and parse it */ int tb_drom_read(struct tb_switch *sw) @@ -374,6 +409,13 @@ int tb_drom_read(struct tb_switch *sw) if (tb_route(sw) == 0) { /* + * Apple's NHI EFI driver supplies a DROM for the root switch + * in a device property. Use it if available. + */ + if (tb_drom_copy_efi(sw, &size) == 0) + goto parse; + + /* * The root switch contains only a dummy drom (header only, * no entries). Hardcode the configuration here. */ @@ -418,6 +460,7 @@ int tb_drom_read(struct tb_switch *sw) if (res) goto err; +parse: header = (void *) sw->drom; if (header->data_len + TB_DROM_DATA_START != size) { |