diff options
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r-- | drivers/net/gianfar.c | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index a06d8d1aaceb..baa35144134c 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * Author: Andy Fleming | 9 | * Author: Andy Fleming |
10 | * Maintainer: Kumar Gala | 10 | * Maintainer: Kumar Gala |
11 | * | 11 | * |
12 | * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | 12 | * Copyright (c) 2002-2006 Freescale Semiconductor, Inc. |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify it | 14 | * This program is free software; you can redistribute it and/or modify it |
15 | * under the terms of the GNU General Public License as published by the | 15 | * under the terms of the GNU General Public License as published by the |
@@ -133,6 +133,9 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); | |||
133 | #ifdef CONFIG_GFAR_NAPI | 133 | #ifdef CONFIG_GFAR_NAPI |
134 | static int gfar_poll(struct net_device *dev, int *budget); | 134 | static int gfar_poll(struct net_device *dev, int *budget); |
135 | #endif | 135 | #endif |
136 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
137 | static void gfar_netpoll(struct net_device *dev); | ||
138 | #endif | ||
136 | int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); | 139 | int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); |
137 | static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); | 140 | static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); |
138 | static void gfar_vlan_rx_register(struct net_device *netdev, | 141 | static void gfar_vlan_rx_register(struct net_device *netdev, |
@@ -260,6 +263,9 @@ static int gfar_probe(struct platform_device *pdev) | |||
260 | dev->poll = gfar_poll; | 263 | dev->poll = gfar_poll; |
261 | dev->weight = GFAR_DEV_WEIGHT; | 264 | dev->weight = GFAR_DEV_WEIGHT; |
262 | #endif | 265 | #endif |
266 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
267 | dev->poll_controller = gfar_netpoll; | ||
268 | #endif | ||
263 | dev->stop = gfar_close; | 269 | dev->stop = gfar_close; |
264 | dev->get_stats = gfar_get_stats; | 270 | dev->get_stats = gfar_get_stats; |
265 | dev->change_mtu = gfar_change_mtu; | 271 | dev->change_mtu = gfar_change_mtu; |
@@ -392,6 +398,38 @@ static int gfar_remove(struct platform_device *pdev) | |||
392 | } | 398 | } |
393 | 399 | ||
394 | 400 | ||
401 | /* Reads the controller's registers to determine what interface | ||
402 | * connects it to the PHY. | ||
403 | */ | ||
404 | static phy_interface_t gfar_get_interface(struct net_device *dev) | ||
405 | { | ||
406 | struct gfar_private *priv = netdev_priv(dev); | ||
407 | u32 ecntrl = gfar_read(&priv->regs->ecntrl); | ||
408 | |||
409 | if (ecntrl & ECNTRL_SGMII_MODE) | ||
410 | return PHY_INTERFACE_MODE_SGMII; | ||
411 | |||
412 | if (ecntrl & ECNTRL_TBI_MODE) { | ||
413 | if (ecntrl & ECNTRL_REDUCED_MODE) | ||
414 | return PHY_INTERFACE_MODE_RTBI; | ||
415 | else | ||
416 | return PHY_INTERFACE_MODE_TBI; | ||
417 | } | ||
418 | |||
419 | if (ecntrl & ECNTRL_REDUCED_MODE) { | ||
420 | if (ecntrl & ECNTRL_REDUCED_MII_MODE) | ||
421 | return PHY_INTERFACE_MODE_RMII; | ||
422 | else | ||
423 | return PHY_INTERFACE_MODE_RGMII; | ||
424 | } | ||
425 | |||
426 | if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) | ||
427 | return PHY_INTERFACE_MODE_GMII; | ||
428 | |||
429 | return PHY_INTERFACE_MODE_MII; | ||
430 | } | ||
431 | |||
432 | |||
395 | /* Initializes driver's PHY state, and attaches to the PHY. | 433 | /* Initializes driver's PHY state, and attaches to the PHY. |
396 | * Returns 0 on success. | 434 | * Returns 0 on success. |
397 | */ | 435 | */ |
@@ -403,6 +441,7 @@ static int init_phy(struct net_device *dev) | |||
403 | SUPPORTED_1000baseT_Full : 0; | 441 | SUPPORTED_1000baseT_Full : 0; |
404 | struct phy_device *phydev; | 442 | struct phy_device *phydev; |
405 | char phy_id[BUS_ID_SIZE]; | 443 | char phy_id[BUS_ID_SIZE]; |
444 | phy_interface_t interface; | ||
406 | 445 | ||
407 | priv->oldlink = 0; | 446 | priv->oldlink = 0; |
408 | priv->oldspeed = 0; | 447 | priv->oldspeed = 0; |
@@ -410,7 +449,9 @@ static int init_phy(struct net_device *dev) | |||
410 | 449 | ||
411 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); | 450 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); |
412 | 451 | ||
413 | phydev = phy_connect(dev, phy_id, &adjust_link, 0); | 452 | interface = gfar_get_interface(dev); |
453 | |||
454 | phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface); | ||
414 | 455 | ||
415 | if (IS_ERR(phydev)) { | 456 | if (IS_ERR(phydev)) { |
416 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | 457 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); |
@@ -1536,6 +1577,33 @@ static int gfar_poll(struct net_device *dev, int *budget) | |||
1536 | } | 1577 | } |
1537 | #endif | 1578 | #endif |
1538 | 1579 | ||
1580 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1581 | /* | ||
1582 | * Polling 'interrupt' - used by things like netconsole to send skbs | ||
1583 | * without having to re-enable interrupts. It's not called while | ||
1584 | * the interrupt routine is executing. | ||
1585 | */ | ||
1586 | static void gfar_netpoll(struct net_device *dev) | ||
1587 | { | ||
1588 | struct gfar_private *priv = netdev_priv(dev); | ||
1589 | |||
1590 | /* If the device has multiple interrupts, run tx/rx */ | ||
1591 | if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { | ||
1592 | disable_irq(priv->interruptTransmit); | ||
1593 | disable_irq(priv->interruptReceive); | ||
1594 | disable_irq(priv->interruptError); | ||
1595 | gfar_interrupt(priv->interruptTransmit, dev); | ||
1596 | enable_irq(priv->interruptError); | ||
1597 | enable_irq(priv->interruptReceive); | ||
1598 | enable_irq(priv->interruptTransmit); | ||
1599 | } else { | ||
1600 | disable_irq(priv->interruptTransmit); | ||
1601 | gfar_interrupt(priv->interruptTransmit, dev); | ||
1602 | enable_irq(priv->interruptTransmit); | ||
1603 | } | ||
1604 | } | ||
1605 | #endif | ||
1606 | |||
1539 | /* The interrupt handler for devices with one interrupt */ | 1607 | /* The interrupt handler for devices with one interrupt */ |
1540 | static irqreturn_t gfar_interrupt(int irq, void *dev_id) | 1608 | static irqreturn_t gfar_interrupt(int irq, void *dev_id) |
1541 | { | 1609 | { |