There are two ways to mark a port as unimplemented. Typical way is to
return port type as TB_TYPE_INACTIVE when its config space is read.
Alternatively if the port is not physically present (such as ports 10
and 11 in ICL) reading from port config space returns
TB_CFG_ERROR_INVALID_CONFIG_SPACE instead. Currently the driver bails
out from adding the switch if it receives any error during port
inititialization which is wrong.
Handle this properly and just leave the port as TB_TYPE_INACTIVE before
continuing to the next port.
Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/thunderbolt/ctl.c | 23 +++++++++++++++++++----
drivers/thunderbolt/switch.c | 8 +++++++-
2 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index 2427d73be731..2ec1af8f7968 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -930,6 +930,23 @@ struct tb_cfg_result tb_cfg_write_raw(struct tb_ctl *ctl, const void *buffer,
return res;
}
+static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space,
+ const struct tb_cfg_result *res)
+{
+ /*
+ * For unimplemented ports access to port config space may return
+ * TB_CFG_ERROR_INVALID_CONFIG_SPACE (alternatively their type is
+ * set to TB_TYPE_INACTIVE). In the former case return -ENODEV so
+ * that the caller can mark the port as disabled.
+ */
+ if (space == TB_CFG_PORT &&
+ res->tb_error == TB_CFG_ERROR_INVALID_CONFIG_SPACE)
+ return -ENODEV;
+
+ tb_cfg_print_error(ctl, res);
+ return -EIO;
+}
+
int tb_cfg_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port,
enum tb_cfg_space space, u32 offset, u32 length)
{
@@ -942,8 +959,7 @@ int tb_cfg_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port,
case 1:
/* Thunderbolt error, tb_error holds the actual number */
- tb_cfg_print_error(ctl, &res);
- return -EIO;
+ return tb_cfg_get_error(ctl, space, &res);
case -ETIMEDOUT:
tb_ctl_warn(ctl, "timeout reading config space %u from %#x\n",
@@ -969,8 +985,7 @@ int tb_cfg_write(struct tb_ctl *ctl, const void *buffer, u64 route, u32 port,
case 1:
/* Thunderbolt error, tb_error holds the actual number */
- tb_cfg_print_error(ctl, &res);
- return -EIO;
+ return tb_cfg_get_error(ctl, space, &res);
case -ETIMEDOUT:
tb_ctl_warn(ctl, "timeout writing config space %u to %#x\n",
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 10b56c66fec3..eac62ff1b85c 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -611,8 +611,14 @@ static int tb_init_port(struct tb_port *port)
int cap;
res = tb_port_read(port, &port->config, TB_CFG_PORT, 0, 8);
- if (res)
+ if (res) {
+ if (res == -ENODEV) {
+ tb_dbg(port->sw->tb, " Port %d: not implemented\n",
+ port->port);
+ return 0;
+ }
return res;
+ }
/* Port 0 is the switch itself and has no PHY. */
if (port->config.type == TB_TYPE_PORT && port->port != 0) {
--
2.20.1
On Fri, Jul 05, 2019 at 12:57:56PM +0300, Mika Westerberg wrote:
> There are two ways to mark a port as unimplemented. Typical way is to
> return port type as TB_TYPE_INACTIVE when its config space is read.
> Alternatively if the port is not physically present (such as ports 10
> and 11 in ICL) reading from port config space returns
> TB_CFG_ERROR_INVALID_CONFIG_SPACE instead. Currently the driver bails
> out from adding the switch if it receives any error during port
> inititialization which is wrong.
>
> Handle this properly and just leave the port as TB_TYPE_INACTIVE before
> continuing to the next port.
Your patch may also cause this snippet in eeprom.c to become obsolete:
/* Port 5 is inaccessible on this gen 1 controller */
if (sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE)
sw->ports[5].disabled = true;
To verify this hypothesis, one needs to comment out the call to
tb_drom_copy_efi() as well as the above-quoted snippet and boot
on a Mac with Light Ridge. The driver should hit an error without
your patch and it may work correctly with your patch.
Thanks,
Lukas
On Sat, Aug 03, 2019 at 04:14:01PM +0200, Lukas Wunner wrote:
> On Fri, Jul 05, 2019 at 12:57:56PM +0300, Mika Westerberg wrote:
> > There are two ways to mark a port as unimplemented. Typical way is to
> > return port type as TB_TYPE_INACTIVE when its config space is read.
> > Alternatively if the port is not physically present (such as ports 10
> > and 11 in ICL) reading from port config space returns
> > TB_CFG_ERROR_INVALID_CONFIG_SPACE instead. Currently the driver bails
> > out from adding the switch if it receives any error during port
> > inititialization which is wrong.
> >
> > Handle this properly and just leave the port as TB_TYPE_INACTIVE before
> > continuing to the next port.
>
> Your patch may also cause this snippet in eeprom.c to become obsolete:
>
> /* Port 5 is inaccessible on this gen 1 controller */
> if (sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE)
> sw->ports[5].disabled = true;
>
> To verify this hypothesis, one needs to comment out the call to
> tb_drom_copy_efi() as well as the above-quoted snippet and boot
> on a Mac with Light Ridge. The driver should hit an error without
> your patch and it may work correctly with your patch.
Indeed. I'll check this - as I have Mac with LR, and update the patch
accordingly (e.g drop the check if the error does not appear).