From 3e13676862f90dbf5b00d57d5599e57788289897 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 6 Jun 2017 15:25:14 +0300 Subject: thunderbolt: Add support for DMA configuration based mailbox The DMA (NHI) port of a switch provides access to the NVM of the host controller (and devices starting from Intel Alpine Ridge). The NVM contains also more complete DROM for the root switch including vendor and device identification strings. This will look for the DMA port capability for each switch and if found populates sw->dma_port. We then teach tb_drom_read() to read the DROM information from NVM if available for the root switch. The DMA port capability also supports upgrading the NVM for both host controller and devices which will be added in subsequent patches. This code is based on the work done by Amir Levy and Michael Jamet. Signed-off-by: Michael Jamet Signed-off-by: Mika Westerberg Reviewed-by: Yehezkel Bernat Reviewed-by: Andy Shevchenko Signed-off-by: Andreas Noever Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/eeprom.c | 51 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'drivers/thunderbolt/eeprom.c') diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index d40a5f07fc4c..996c6e29c8ad 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -429,6 +429,50 @@ err: return -EINVAL; } +static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size) +{ + u32 drom_offset; + int ret; + + if (!sw->dma_port) + return -ENODEV; + + ret = tb_sw_read(sw, &drom_offset, TB_CFG_SWITCH, + sw->cap_plug_events + 12, 1); + if (ret) + return ret; + + if (!drom_offset) + return -ENODEV; + + ret = dma_port_flash_read(sw->dma_port, drom_offset + 14, size, + sizeof(*size)); + if (ret) + return ret; + + /* Size includes CRC8 + UID + CRC32 */ + *size += 1 + 8 + 4; + sw->drom = kzalloc(*size, GFP_KERNEL); + if (!sw->drom) + return -ENOMEM; + + ret = dma_port_flash_read(sw->dma_port, drom_offset, sw->drom, *size); + if (ret) + goto err_free; + + /* + * Read UID from the minimal DROM because the one in NVM is just + * a placeholder. + */ + tb_drom_read_uid_only(sw, &sw->uid); + return 0; + +err_free: + kfree(sw->drom); + sw->drom = NULL; + return ret; +} + /** * tb_drom_read - copy drom to sw->drom and parse it */ @@ -450,6 +494,10 @@ int tb_drom_read(struct tb_switch *sw) if (tb_drom_copy_efi(sw, &size) == 0) goto parse; + /* Non-Apple hardware has the DROM as part of NVM */ + if (tb_drom_copy_nvm(sw, &size) == 0) + goto parse; + /* * The root switch contains only a dummy drom (header only, * no entries). Hardcode the configuration here. @@ -510,7 +558,8 @@ parse: header->uid_crc8, crc); goto err; } - sw->uid = header->uid; + if (!sw->uid) + sw->uid = header->uid; sw->vendor = header->vendor_id; sw->device = header->model_id; -- cgit v1.2.3