diff options
author | David Rivshin <drivshin@allworx.com> | 2016-04-27 21:32:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-28 17:27:29 -0400 |
commit | d733f7542ad47cf73e033c90cf55158587e1d060 (patch) | |
tree | 552f4ff79dcecd32d50c614e7ed8e6c4f819524a | |
parent | 552165bcf7060b998b4a9b5b86110b6a5e04dfd9 (diff) |
drivers: net: cpsw: fix segfault in case of bad phy-handle
If an emac node has a phy-handle property that points to something
which is not a phy, then a segmentation fault will occur when the
interface is brought up. This is because while phy_connect() will
return ERR_PTR() on failure, of_phy_connect() will return NULL.
The common error check uses IS_ERR(), and so missed when
of_phy_connect() fails. The NULL pointer is then dereferenced.
Also, the common error message referenced slave->data->phy_id,
which would be empty in the case of phy-handle. Instead, use the
name of the device_node as a useful identifier. And in the phy_id
case add the error code for completeness.
Fixes: 9e42f715264f ("drivers: net: cpsw: add phy-handle parsing")
Signed-off-by: David Rivshin <drivshin@allworx.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index ce0b0caee35b..5903448e8ee9 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -1147,25 +1147,34 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) | |||
1147 | cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, | 1147 | cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
1148 | 1 << slave_port, 0, 0, ALE_MCAST_FWD_2); | 1148 | 1 << slave_port, 0, 0, ALE_MCAST_FWD_2); |
1149 | 1149 | ||
1150 | if (slave->data->phy_node) | 1150 | if (slave->data->phy_node) { |
1151 | slave->phy = of_phy_connect(priv->ndev, slave->data->phy_node, | 1151 | slave->phy = of_phy_connect(priv->ndev, slave->data->phy_node, |
1152 | &cpsw_adjust_link, 0, slave->data->phy_if); | 1152 | &cpsw_adjust_link, 0, slave->data->phy_if); |
1153 | else | 1153 | if (!slave->phy) { |
1154 | dev_err(priv->dev, "phy \"%s\" not found on slave %d\n", | ||
1155 | slave->data->phy_node->full_name, | ||
1156 | slave->slave_num); | ||
1157 | return; | ||
1158 | } | ||
1159 | } else { | ||
1154 | slave->phy = phy_connect(priv->ndev, slave->data->phy_id, | 1160 | slave->phy = phy_connect(priv->ndev, slave->data->phy_id, |
1155 | &cpsw_adjust_link, slave->data->phy_if); | 1161 | &cpsw_adjust_link, slave->data->phy_if); |
1156 | if (IS_ERR(slave->phy)) { | 1162 | if (IS_ERR(slave->phy)) { |
1157 | dev_err(priv->dev, "phy %s not found on slave %d\n", | 1163 | dev_err(priv->dev, |
1158 | slave->data->phy_id, slave->slave_num); | 1164 | "phy \"%s\" not found on slave %d, err %ld\n", |
1159 | slave->phy = NULL; | 1165 | slave->data->phy_id, slave->slave_num, |
1160 | } else { | 1166 | PTR_ERR(slave->phy)); |
1161 | phy_attached_info(slave->phy); | 1167 | slave->phy = NULL; |
1168 | return; | ||
1169 | } | ||
1170 | } | ||
1162 | 1171 | ||
1163 | phy_start(slave->phy); | 1172 | phy_attached_info(slave->phy); |
1164 | 1173 | ||
1165 | /* Configure GMII_SEL register */ | 1174 | phy_start(slave->phy); |
1166 | cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface, | 1175 | |
1167 | slave->slave_num); | 1176 | /* Configure GMII_SEL register */ |
1168 | } | 1177 | cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface, slave->slave_num); |
1169 | } | 1178 | } |
1170 | 1179 | ||
1171 | static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) | 1180 | static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) |