diff options
author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2009-03-23 00:30:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-23 00:30:52 -0400 |
commit | 61fa9dcf9329cb92c220f7b656410fbe5e72f933 (patch) | |
tree | f8b375ca64e3af7c5f12ab2e9d1a590f76a110cc /drivers/net | |
parent | e3162d381fc359ebe5c98a3e216888a7cb200051 (diff) |
ucc_geth: Fix oops when using fixed-link support
commit b1c4a9dddf09fe99b8f88252718ac5b357363dc4 ("ucc_geth: Change
uec phy id to the same format as gianfar's") introduced a regression
in the ucc_geth driver that causes this oops when fixed-link is used:
Unable to handle kernel paging request for data at address 0x00000000
Faulting instruction address: 0xc0151270
Oops: Kernel access of bad area, sig: 11 [#1]
TMCUTU
NIP: c0151270 LR: c0151270 CTR: c0017760
REGS: cf81fa60 TRAP: 0300 Not tainted (2.6.29-rc8)
MSR: 00009032 <EE,ME,IR,DR> CR: 24024042 XER: 20000000
DAR: 00000000, DSISR: 20000000
TASK = cf81cba0[1] 'swapper' THREAD: cf81e000
GPR00: c0151270 cf81fb10 cf81cba0 00000000 c0272e20 c025f354 00001e80
cf86b08c
GPR08: d1068200 cffffb74 06000000 d106c200 42024042 10085148 0fffd000
0ffc81a0
GPR16: 00000001 00000001 00000000 007ffeb0 00000000 0000c000 cf83f36c
cf83f000
GPR24: 00000030 cf83f360 cf81fb20 00000000 d106c200 20000000 00001e80
cf83f360
NIP [c0151270] ucc_geth_open+0x330/0x1efc
LR [c0151270] ucc_geth_open+0x330/0x1efc
Call Trace:
[cf81fb10] [c0151270] ucc_geth_open+0x330/0x1efc (unreliable)
[cf81fba0] [c0187638] dev_open+0xbc/0x12c
[cf81fbc0] [c0187e38] dev_change_flags+0x8c/0x1b0
This patch fixes the issue by removing offending (and somewhat
duplicate) code from init_phy() routine, and changes _probe()
function to use uec_mdio_bus_name().
Also, since we fully construct phy_bus_id in the _probe() routine,
we no longer need ->phy_address and ->mdio_bus fields in
ucc_geth_info structure.
I wish the patch would be a bit shorter, but it seems like the only
way to fix the issue in a sane way. Luckily, the patch has been
tested with real PHYs and fixed-link, so no further regressions
expected.
Reported-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Tested-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ucc_geth.c | 34 | ||||
-rw-r--r-- | drivers/net/ucc_geth.h | 3 |
2 files changed, 11 insertions, 26 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index e87986867ba5..1f61e42c641d 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -1536,32 +1536,15 @@ static void adjust_link(struct net_device *dev) | |||
1536 | static int init_phy(struct net_device *dev) | 1536 | static int init_phy(struct net_device *dev) |
1537 | { | 1537 | { |
1538 | struct ucc_geth_private *priv = netdev_priv(dev); | 1538 | struct ucc_geth_private *priv = netdev_priv(dev); |
1539 | struct device_node *np = priv->node; | 1539 | struct ucc_geth_info *ug_info = priv->ug_info; |
1540 | struct device_node *phy, *mdio; | ||
1541 | const phandle *ph; | ||
1542 | char bus_name[MII_BUS_ID_SIZE]; | ||
1543 | const unsigned int *id; | ||
1544 | struct phy_device *phydev; | 1540 | struct phy_device *phydev; |
1545 | char phy_id[BUS_ID_SIZE]; | ||
1546 | 1541 | ||
1547 | priv->oldlink = 0; | 1542 | priv->oldlink = 0; |
1548 | priv->oldspeed = 0; | 1543 | priv->oldspeed = 0; |
1549 | priv->oldduplex = -1; | 1544 | priv->oldduplex = -1; |
1550 | 1545 | ||
1551 | ph = of_get_property(np, "phy-handle", NULL); | 1546 | phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0, |
1552 | phy = of_find_node_by_phandle(*ph); | 1547 | priv->phy_interface); |
1553 | mdio = of_get_parent(phy); | ||
1554 | |||
1555 | id = of_get_property(phy, "reg", NULL); | ||
1556 | |||
1557 | of_node_put(phy); | ||
1558 | of_node_put(mdio); | ||
1559 | |||
1560 | uec_mdio_bus_name(bus_name, mdio); | ||
1561 | snprintf(phy_id, sizeof(phy_id), "%s:%02x", | ||
1562 | bus_name, *id); | ||
1563 | |||
1564 | phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); | ||
1565 | 1548 | ||
1566 | if (IS_ERR(phydev)) { | 1549 | if (IS_ERR(phydev)) { |
1567 | printk("%s: Could not attach to PHY\n", dev->name); | 1550 | printk("%s: Could not attach to PHY\n", dev->name); |
@@ -3629,10 +3612,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3629 | ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); | 3612 | ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); |
3630 | fixed_link = of_get_property(np, "fixed-link", NULL); | 3613 | fixed_link = of_get_property(np, "fixed-link", NULL); |
3631 | if (fixed_link) { | 3614 | if (fixed_link) { |
3632 | snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "0"); | 3615 | snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), |
3633 | ug_info->phy_address = fixed_link[0]; | 3616 | PHY_ID_FMT, "0", fixed_link[0]); |
3634 | phy = NULL; | 3617 | phy = NULL; |
3635 | } else { | 3618 | } else { |
3619 | char bus_name[MII_BUS_ID_SIZE]; | ||
3620 | |||
3636 | ph = of_get_property(np, "phy-handle", NULL); | 3621 | ph = of_get_property(np, "phy-handle", NULL); |
3637 | phy = of_find_node_by_phandle(*ph); | 3622 | phy = of_find_node_by_phandle(*ph); |
3638 | 3623 | ||
@@ -3643,7 +3628,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3643 | prop = of_get_property(phy, "reg", NULL); | 3628 | prop = of_get_property(phy, "reg", NULL); |
3644 | if (prop == NULL) | 3629 | if (prop == NULL) |
3645 | return -1; | 3630 | return -1; |
3646 | ug_info->phy_address = *prop; | ||
3647 | 3631 | ||
3648 | /* Set the bus id */ | 3632 | /* Set the bus id */ |
3649 | mdio = of_get_parent(phy); | 3633 | mdio = of_get_parent(phy); |
@@ -3657,7 +3641,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3657 | if (err) | 3641 | if (err) |
3658 | return -1; | 3642 | return -1; |
3659 | 3643 | ||
3660 | snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x", res.start); | 3644 | uec_mdio_bus_name(bus_name, mdio); |
3645 | snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), | ||
3646 | "%s:%02x", bus_name, *prop); | ||
3661 | } | 3647 | } |
3662 | 3648 | ||
3663 | /* get the phy interface type, or default to MII */ | 3649 | /* get the phy interface type, or default to MII */ |
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 16cbe42ba43c..611bdef2402b 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h | |||
@@ -1091,8 +1091,7 @@ struct ucc_geth_info { | |||
1091 | u32 eventRegMask; | 1091 | u32 eventRegMask; |
1092 | u16 pausePeriod; | 1092 | u16 pausePeriod; |
1093 | u16 extensionField; | 1093 | u16 extensionField; |
1094 | u8 phy_address; | 1094 | char phy_bus_id[BUS_ID_SIZE]; |
1095 | char mdio_bus[MII_BUS_ID_SIZE]; | ||
1096 | u8 weightfactor[NUM_TX_QUEUES]; | 1095 | u8 weightfactor[NUM_TX_QUEUES]; |
1097 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; | 1096 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; |
1098 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; | 1097 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; |