diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-15 12:40:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-15 12:40:05 -0400 |
commit | 2ed0e21b30b53d3a94e204196e523e6c8f732b56 (patch) | |
tree | de2635426477d86338a9469ce09ba0626052288f /drivers/net/ucc_geth.c | |
parent | 0fa213310cd8fa7a51071cdcf130e26fa56e9549 (diff) | |
parent | 9cbc1cb8cd46ce1f7645b9de249b2ce8460129bb (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1244 commits)
pkt_sched: Rename PSCHED_US2NS and PSCHED_NS2US
ipv4: Fix fib_trie rebalancing
Bluetooth: Fix issue with uninitialized nsh.type in DTL-1 driver
Bluetooth: Fix Kconfig issue with RFKILL integration
PIM-SM: namespace changes
ipv4: update ARPD help text
net: use a deferred timer in rt_check_expire
ieee802154: fix kconfig bool/tristate muckup
bonding: initialization rework
bonding: use is_zero_ether_addr
bonding: network device names are case sensative
bonding: elminate bad refcount code
bonding: fix style issues
bonding: fix destructor
bonding: remove bonding read/write semaphore
bonding: initialize before registration
bonding: bond_create always called with default parameters
x_tables: Convert printk to pr_err
netfilter: conntrack: optional reliable conntrack event delivery
list_nulls: add hlist_nulls_add_head and hlist_nulls_del
...
Diffstat (limited to 'drivers/net/ucc_geth.c')
-rw-r--r-- | drivers/net/ucc_geth.c | 187 |
1 files changed, 130 insertions, 57 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 9dd16c9b1a10..e2f2e91cfdd2 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved. | 2 | * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * Author: Shlomi Gridish <gridish@freescale.com> | 4 | * Author: Shlomi Gridish <gridish@freescale.com> |
5 | * Li Yang <leoli@freescale.com> | 5 | * Li Yang <leoli@freescale.com> |
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/mii.h> | 27 | #include <linux/mii.h> |
28 | #include <linux/phy.h> | 28 | #include <linux/phy.h> |
29 | #include <linux/workqueue.h> | 29 | #include <linux/workqueue.h> |
30 | #include <linux/of_mdio.h> | ||
30 | #include <linux/of_platform.h> | 31 | #include <linux/of_platform.h> |
31 | 32 | ||
32 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
@@ -64,6 +65,8 @@ | |||
64 | 65 | ||
65 | static DEFINE_SPINLOCK(ugeth_lock); | 66 | static DEFINE_SPINLOCK(ugeth_lock); |
66 | 67 | ||
68 | static void uec_configure_serdes(struct net_device *dev); | ||
69 | |||
67 | static struct { | 70 | static struct { |
68 | u32 msg_enable; | 71 | u32 msg_enable; |
69 | } debug = { -1 }; | 72 | } debug = { -1 }; |
@@ -1409,6 +1412,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1409 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | 1412 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { |
1410 | upsmr |= UCC_GETH_UPSMR_TBIM; | 1413 | upsmr |= UCC_GETH_UPSMR_TBIM; |
1411 | } | 1414 | } |
1415 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII)) | ||
1416 | upsmr |= UCC_GETH_UPSMR_SGMM; | ||
1417 | |||
1412 | out_be32(&uf_regs->upsmr, upsmr); | 1418 | out_be32(&uf_regs->upsmr, upsmr); |
1413 | 1419 | ||
1414 | /* Disable autonegotiation in tbi mode, because by default it | 1420 | /* Disable autonegotiation in tbi mode, because by default it |
@@ -1543,14 +1549,19 @@ static int init_phy(struct net_device *dev) | |||
1543 | priv->oldspeed = 0; | 1549 | priv->oldspeed = 0; |
1544 | priv->oldduplex = -1; | 1550 | priv->oldduplex = -1; |
1545 | 1551 | ||
1546 | phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0, | 1552 | if (!ug_info->phy_node) |
1547 | priv->phy_interface); | 1553 | return 0; |
1548 | 1554 | ||
1549 | if (IS_ERR(phydev)) { | 1555 | phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0, |
1556 | priv->phy_interface); | ||
1557 | if (!phydev) { | ||
1550 | printk("%s: Could not attach to PHY\n", dev->name); | 1558 | printk("%s: Could not attach to PHY\n", dev->name); |
1551 | return PTR_ERR(phydev); | 1559 | return -ENODEV; |
1552 | } | 1560 | } |
1553 | 1561 | ||
1562 | if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) | ||
1563 | uec_configure_serdes(dev); | ||
1564 | |||
1554 | phydev->supported &= (ADVERTISED_10baseT_Half | | 1565 | phydev->supported &= (ADVERTISED_10baseT_Half | |
1555 | ADVERTISED_10baseT_Full | | 1566 | ADVERTISED_10baseT_Full | |
1556 | ADVERTISED_100baseT_Half | | 1567 | ADVERTISED_100baseT_Half | |
@@ -1566,7 +1577,41 @@ static int init_phy(struct net_device *dev) | |||
1566 | return 0; | 1577 | return 0; |
1567 | } | 1578 | } |
1568 | 1579 | ||
1580 | /* Initialize TBI PHY interface for communicating with the | ||
1581 | * SERDES lynx PHY on the chip. We communicate with this PHY | ||
1582 | * through the MDIO bus on each controller, treating it as a | ||
1583 | * "normal" PHY at the address found in the UTBIPA register. We assume | ||
1584 | * that the UTBIPA register is valid. Either the MDIO bus code will set | ||
1585 | * it to a value that doesn't conflict with other PHYs on the bus, or the | ||
1586 | * value doesn't matter, as there are no other PHYs on the bus. | ||
1587 | */ | ||
1588 | static void uec_configure_serdes(struct net_device *dev) | ||
1589 | { | ||
1590 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
1591 | |||
1592 | if (!ugeth->tbiphy) { | ||
1593 | printk(KERN_WARNING "SGMII mode requires that the device " | ||
1594 | "tree specify a tbi-handle\n"); | ||
1595 | return; | ||
1596 | } | ||
1597 | |||
1598 | /* | ||
1599 | * If the link is already up, we must already be ok, and don't need to | ||
1600 | * configure and reset the TBI<->SerDes link. Maybe U-Boot configured | ||
1601 | * everything for us? Resetting it takes the link down and requires | ||
1602 | * several seconds for it to come back. | ||
1603 | */ | ||
1604 | if (phy_read(ugeth->tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS) | ||
1605 | return; | ||
1569 | 1606 | ||
1607 | /* Single clk mode, mii mode off(for serdes communication) */ | ||
1608 | phy_write(ugeth->tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS); | ||
1609 | |||
1610 | phy_write(ugeth->tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT); | ||
1611 | |||
1612 | phy_write(ugeth->tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS); | ||
1613 | |||
1614 | } | ||
1570 | 1615 | ||
1571 | static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) | 1616 | static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) |
1572 | { | 1617 | { |
@@ -3225,7 +3270,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) | |||
3225 | dev->stats.tx_packets++; | 3270 | dev->stats.tx_packets++; |
3226 | 3271 | ||
3227 | /* Free the sk buffer associated with this TxBD */ | 3272 | /* Free the sk buffer associated with this TxBD */ |
3228 | dev_kfree_skb_irq(ugeth-> | 3273 | dev_kfree_skb(ugeth-> |
3229 | tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); | 3274 | tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); |
3230 | ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; | 3275 | ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; |
3231 | ugeth->skb_dirtytx[txQ] = | 3276 | ugeth->skb_dirtytx[txQ] = |
@@ -3259,9 +3304,15 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) | |||
3259 | for (i = 0; i < ug_info->numQueuesRx; i++) | 3304 | for (i = 0; i < ug_info->numQueuesRx; i++) |
3260 | howmany += ucc_geth_rx(ugeth, i, budget - howmany); | 3305 | howmany += ucc_geth_rx(ugeth, i, budget - howmany); |
3261 | 3306 | ||
3307 | /* Tx event processing */ | ||
3308 | spin_lock(&ugeth->lock); | ||
3309 | for (i = 0; i < ug_info->numQueuesTx; i++) | ||
3310 | ucc_geth_tx(ugeth->ndev, i); | ||
3311 | spin_unlock(&ugeth->lock); | ||
3312 | |||
3262 | if (howmany < budget) { | 3313 | if (howmany < budget) { |
3263 | napi_complete(napi); | 3314 | napi_complete(napi); |
3264 | setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS); | 3315 | setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS); |
3265 | } | 3316 | } |
3266 | 3317 | ||
3267 | return howmany; | 3318 | return howmany; |
@@ -3275,8 +3326,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | |||
3275 | struct ucc_geth_info *ug_info; | 3326 | struct ucc_geth_info *ug_info; |
3276 | register u32 ucce; | 3327 | register u32 ucce; |
3277 | register u32 uccm; | 3328 | register u32 uccm; |
3278 | register u32 tx_mask; | ||
3279 | u8 i; | ||
3280 | 3329 | ||
3281 | ugeth_vdbg("%s: IN", __func__); | 3330 | ugeth_vdbg("%s: IN", __func__); |
3282 | 3331 | ||
@@ -3290,27 +3339,14 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | |||
3290 | out_be32(uccf->p_ucce, ucce); | 3339 | out_be32(uccf->p_ucce, ucce); |
3291 | 3340 | ||
3292 | /* check for receive events that require processing */ | 3341 | /* check for receive events that require processing */ |
3293 | if (ucce & UCCE_RX_EVENTS) { | 3342 | if (ucce & (UCCE_RX_EVENTS | UCCE_TX_EVENTS)) { |
3294 | if (napi_schedule_prep(&ugeth->napi)) { | 3343 | if (napi_schedule_prep(&ugeth->napi)) { |
3295 | uccm &= ~UCCE_RX_EVENTS; | 3344 | uccm &= ~(UCCE_RX_EVENTS | UCCE_TX_EVENTS); |
3296 | out_be32(uccf->p_uccm, uccm); | 3345 | out_be32(uccf->p_uccm, uccm); |
3297 | __napi_schedule(&ugeth->napi); | 3346 | __napi_schedule(&ugeth->napi); |
3298 | } | 3347 | } |
3299 | } | 3348 | } |
3300 | 3349 | ||
3301 | /* Tx event processing */ | ||
3302 | if (ucce & UCCE_TX_EVENTS) { | ||
3303 | spin_lock(&ugeth->lock); | ||
3304 | tx_mask = UCC_GETH_UCCE_TXB0; | ||
3305 | for (i = 0; i < ug_info->numQueuesTx; i++) { | ||
3306 | if (ucce & tx_mask) | ||
3307 | ucc_geth_tx(dev, i); | ||
3308 | ucce &= ~tx_mask; | ||
3309 | tx_mask <<= 1; | ||
3310 | } | ||
3311 | spin_unlock(&ugeth->lock); | ||
3312 | } | ||
3313 | |||
3314 | /* Errors and other events */ | 3350 | /* Errors and other events */ |
3315 | if (ucce & UCCE_OTHER) { | 3351 | if (ucce & UCCE_OTHER) { |
3316 | if (ucce & UCC_GETH_UCCE_BSY) | 3352 | if (ucce & UCC_GETH_UCCE_BSY) |
@@ -3339,6 +3375,37 @@ static void ucc_netpoll(struct net_device *dev) | |||
3339 | } | 3375 | } |
3340 | #endif /* CONFIG_NET_POLL_CONTROLLER */ | 3376 | #endif /* CONFIG_NET_POLL_CONTROLLER */ |
3341 | 3377 | ||
3378 | static int ucc_geth_set_mac_addr(struct net_device *dev, void *p) | ||
3379 | { | ||
3380 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
3381 | struct sockaddr *addr = p; | ||
3382 | |||
3383 | if (!is_valid_ether_addr(addr->sa_data)) | ||
3384 | return -EADDRNOTAVAIL; | ||
3385 | |||
3386 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
3387 | |||
3388 | /* | ||
3389 | * If device is not running, we will set mac addr register | ||
3390 | * when opening the device. | ||
3391 | */ | ||
3392 | if (!netif_running(dev)) | ||
3393 | return 0; | ||
3394 | |||
3395 | spin_lock_irq(&ugeth->lock); | ||
3396 | init_mac_station_addr_regs(dev->dev_addr[0], | ||
3397 | dev->dev_addr[1], | ||
3398 | dev->dev_addr[2], | ||
3399 | dev->dev_addr[3], | ||
3400 | dev->dev_addr[4], | ||
3401 | dev->dev_addr[5], | ||
3402 | &ugeth->ug_regs->macstnaddr1, | ||
3403 | &ugeth->ug_regs->macstnaddr2); | ||
3404 | spin_unlock_irq(&ugeth->lock); | ||
3405 | |||
3406 | return 0; | ||
3407 | } | ||
3408 | |||
3342 | /* Called when something needs to use the ethernet device */ | 3409 | /* Called when something needs to use the ethernet device */ |
3343 | /* Returns 0 for success. */ | 3410 | /* Returns 0 for success. */ |
3344 | static int ucc_geth_open(struct net_device *dev) | 3411 | static int ucc_geth_open(struct net_device *dev) |
@@ -3506,6 +3573,8 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type) | |||
3506 | return PHY_INTERFACE_MODE_RGMII_RXID; | 3573 | return PHY_INTERFACE_MODE_RGMII_RXID; |
3507 | if (strcasecmp(phy_connection_type, "rtbi") == 0) | 3574 | if (strcasecmp(phy_connection_type, "rtbi") == 0) |
3508 | return PHY_INTERFACE_MODE_RTBI; | 3575 | return PHY_INTERFACE_MODE_RTBI; |
3576 | if (strcasecmp(phy_connection_type, "sgmii") == 0) | ||
3577 | return PHY_INTERFACE_MODE_SGMII; | ||
3509 | 3578 | ||
3510 | return PHY_INTERFACE_MODE_MII; | 3579 | return PHY_INTERFACE_MODE_MII; |
3511 | } | 3580 | } |
@@ -3515,7 +3584,7 @@ static const struct net_device_ops ucc_geth_netdev_ops = { | |||
3515 | .ndo_stop = ucc_geth_close, | 3584 | .ndo_stop = ucc_geth_close, |
3516 | .ndo_start_xmit = ucc_geth_start_xmit, | 3585 | .ndo_start_xmit = ucc_geth_start_xmit, |
3517 | .ndo_validate_addr = eth_validate_addr, | 3586 | .ndo_validate_addr = eth_validate_addr, |
3518 | .ndo_set_mac_address = eth_mac_addr, | 3587 | .ndo_set_mac_address = ucc_geth_set_mac_addr, |
3519 | .ndo_change_mtu = eth_change_mtu, | 3588 | .ndo_change_mtu = eth_change_mtu, |
3520 | .ndo_set_multicast_list = ucc_geth_set_multi, | 3589 | .ndo_set_multicast_list = ucc_geth_set_multi, |
3521 | .ndo_tx_timeout = ucc_geth_timeout, | 3590 | .ndo_tx_timeout = ucc_geth_timeout, |
@@ -3528,14 +3597,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3528 | { | 3597 | { |
3529 | struct device *device = &ofdev->dev; | 3598 | struct device *device = &ofdev->dev; |
3530 | struct device_node *np = ofdev->node; | 3599 | struct device_node *np = ofdev->node; |
3531 | struct device_node *mdio; | ||
3532 | struct net_device *dev = NULL; | 3600 | struct net_device *dev = NULL; |
3533 | struct ucc_geth_private *ugeth = NULL; | 3601 | struct ucc_geth_private *ugeth = NULL; |
3534 | struct ucc_geth_info *ug_info; | 3602 | struct ucc_geth_info *ug_info; |
3535 | struct resource res; | 3603 | struct resource res; |
3536 | struct device_node *phy; | 3604 | struct device_node *phy; |
3537 | int err, ucc_num, max_speed = 0; | 3605 | int err, ucc_num, max_speed = 0; |
3538 | const phandle *ph; | ||
3539 | const u32 *fixed_link; | 3606 | const u32 *fixed_link; |
3540 | const unsigned int *prop; | 3607 | const unsigned int *prop; |
3541 | const char *sprop; | 3608 | const char *sprop; |
@@ -3552,6 +3619,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3552 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, | 3619 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, |
3553 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, | 3620 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, |
3554 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, | 3621 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, |
3622 | PHY_INTERFACE_MODE_SGMII, | ||
3555 | }; | 3623 | }; |
3556 | 3624 | ||
3557 | ugeth_vdbg("%s: IN", __func__); | 3625 | ugeth_vdbg("%s: IN", __func__); |
@@ -3635,40 +3703,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3635 | ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); | 3703 | ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); |
3636 | fixed_link = of_get_property(np, "fixed-link", NULL); | 3704 | fixed_link = of_get_property(np, "fixed-link", NULL); |
3637 | if (fixed_link) { | 3705 | if (fixed_link) { |
3638 | snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), | ||
3639 | PHY_ID_FMT, "0", fixed_link[0]); | ||
3640 | phy = NULL; | 3706 | phy = NULL; |
3641 | } else { | 3707 | } else { |
3642 | char bus_name[MII_BUS_ID_SIZE]; | 3708 | phy = of_parse_phandle(np, "phy-handle", 0); |
3643 | |||
3644 | ph = of_get_property(np, "phy-handle", NULL); | ||
3645 | phy = of_find_node_by_phandle(*ph); | ||
3646 | |||
3647 | if (phy == NULL) | 3709 | if (phy == NULL) |
3648 | return -ENODEV; | 3710 | return -ENODEV; |
3649 | |||
3650 | /* set the PHY address */ | ||
3651 | prop = of_get_property(phy, "reg", NULL); | ||
3652 | if (prop == NULL) | ||
3653 | return -1; | ||
3654 | |||
3655 | /* Set the bus id */ | ||
3656 | mdio = of_get_parent(phy); | ||
3657 | |||
3658 | if (mdio == NULL) | ||
3659 | return -ENODEV; | ||
3660 | |||
3661 | err = of_address_to_resource(mdio, 0, &res); | ||
3662 | |||
3663 | if (err) { | ||
3664 | of_node_put(mdio); | ||
3665 | return err; | ||
3666 | } | ||
3667 | fsl_pq_mdio_bus_name(bus_name, mdio); | ||
3668 | of_node_put(mdio); | ||
3669 | snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), | ||
3670 | "%s:%02x", bus_name, *prop); | ||
3671 | } | 3711 | } |
3712 | ug_info->phy_node = phy; | ||
3672 | 3713 | ||
3673 | /* get the phy interface type, or default to MII */ | 3714 | /* get the phy interface type, or default to MII */ |
3674 | prop = of_get_property(np, "phy-connection-type", NULL); | 3715 | prop = of_get_property(np, "phy-connection-type", NULL); |
@@ -3694,6 +3735,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3694 | case PHY_INTERFACE_MODE_RGMII_TXID: | 3735 | case PHY_INTERFACE_MODE_RGMII_TXID: |
3695 | case PHY_INTERFACE_MODE_TBI: | 3736 | case PHY_INTERFACE_MODE_TBI: |
3696 | case PHY_INTERFACE_MODE_RTBI: | 3737 | case PHY_INTERFACE_MODE_RTBI: |
3738 | case PHY_INTERFACE_MODE_SGMII: | ||
3697 | max_speed = SPEED_1000; | 3739 | max_speed = SPEED_1000; |
3698 | break; | 3740 | break; |
3699 | default: | 3741 | default: |
@@ -3751,7 +3793,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3751 | dev->netdev_ops = &ucc_geth_netdev_ops; | 3793 | dev->netdev_ops = &ucc_geth_netdev_ops; |
3752 | dev->watchdog_timeo = TX_TIMEOUT; | 3794 | dev->watchdog_timeo = TX_TIMEOUT; |
3753 | INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work); | 3795 | INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work); |
3754 | netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); | 3796 | netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, 64); |
3755 | dev->mtu = 1500; | 3797 | dev->mtu = 1500; |
3756 | 3798 | ||
3757 | ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT); | 3799 | ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT); |
@@ -3776,6 +3818,37 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3776 | ugeth->ndev = dev; | 3818 | ugeth->ndev = dev; |
3777 | ugeth->node = np; | 3819 | ugeth->node = np; |
3778 | 3820 | ||
3821 | /* Find the TBI PHY. If it's not there, we don't support SGMII */ | ||
3822 | ph = of_get_property(np, "tbi-handle", NULL); | ||
3823 | if (ph) { | ||
3824 | struct device_node *tbi = of_find_node_by_phandle(*ph); | ||
3825 | struct of_device *ofdev; | ||
3826 | struct mii_bus *bus; | ||
3827 | const unsigned int *id; | ||
3828 | |||
3829 | if (!tbi) | ||
3830 | return 0; | ||
3831 | |||
3832 | mdio = of_get_parent(tbi); | ||
3833 | if (!mdio) | ||
3834 | return 0; | ||
3835 | |||
3836 | ofdev = of_find_device_by_node(mdio); | ||
3837 | |||
3838 | of_node_put(mdio); | ||
3839 | |||
3840 | id = of_get_property(tbi, "reg", NULL); | ||
3841 | if (!id) | ||
3842 | return 0; | ||
3843 | of_node_put(tbi); | ||
3844 | |||
3845 | bus = dev_get_drvdata(&ofdev->dev); | ||
3846 | if (!bus) | ||
3847 | return 0; | ||
3848 | |||
3849 | ugeth->tbiphy = bus->phy_map[*id]; | ||
3850 | } | ||
3851 | |||
3779 | return 0; | 3852 | return 0; |
3780 | } | 3853 | } |
3781 | 3854 | ||