net driver: mpc52xx fec
Subsystems (6)
RFC PATCH 1/1 net driver: mpc52xx fec
Hi!
Not for merge (yet)! But please do review.
fec_mpc52xx driver (not in-tree, but floating around) isn't in very good shape, so I tried to change that.
Diff against original is quite big (fec_phy.c is completely rewritten) and confuzing, so I'm including whole drivers/net/fec_mpc52xx/ .
I still have 'make CONFIG_FEC_MPC52xx_MDIO=n compile and work' on my TODO, maybe even ethtool support.
Domen
arch/powerpc/boot/dts/lite5200b.dts | 18 arch/powerpc/sysdev/bestcomm/fec.h | 14 drivers/net/fec_mpc52xx/Kconfig | 24 drivers/net/fec_mpc52xx/Makefile | 7 drivers/net/fec_mpc52xx/fec.c | 1002 ++++++++++++++++++++++++++++++++++++ drivers/net/fec_mpc52xx/fec.h | 299 ++++++++++ drivers/net/fec_mpc52xx/fec_phy.c | 229 ++++++++ drivers/net/fec_mpc52xx/fec_phy.h | 49 + 8 files changed, 1641 insertions(+), 1 deletion(-)
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +1002 -0
@@ -0,0 +1,1002 @@ +/* +* drivers/net/fec_mpc52xx/fec.c +* +* Driver for the MPC5200 Fast Ethernet Controller +* +* Originally written by Dale Farnsworth <[email protected]> and +* now maintained by Sylvain Munaut <[email protected]> +* +* Copyright (C) 2007 Sylvain Munaut <[email protected]> +* Copyrigth (C) 2003-2004 MontaVista, Software, Inc. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +*/ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/crc32.h> +#include <linux/hardirq.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> + +#include <asm/of_device.h> +#include <asm/of_platform.h> +#include <asm/io.h> +#include <asm/delay.h> +#include <asm/mpc52xx.h> + +#include <sysdev/bestcomm/bestcomm.h> +#include <sysdev/bestcomm/fec.h> + +#include "fec_phy.h" +#include "fec.h" + +#define DRIVER_NAME "mpc52xx-fec" + +static irqreturn_t fec_interrupt (int ,void *); +static irqreturn_t fec_rx_interrupt (int ,void *); +static irqreturn_t fec_tx_interrupt (int ,void *); +static struct net_device_stats *fec_get_stats (struct net_device *); +static void fec_set_multicast_list (struct net_device *dev); +static void fec_hw_init (struct net_device *dev); +static void fec_stop (struct net_device *dev); +static void fec_start (struct net_device *dev); + +static u8 mpc52xx_fec_mac_addr[6 ]; +static u8 null_mac[6 ]; + +static void fec_tx_timeout (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); + +dev_warn (&dev->dev,"transmit timed out\n" ); + +fec_stop (dev); +fec_start (dev); + + priv->stats.tx_errors++; + +if (!priv->tx_full) +netif_wake_queue (dev); +} + +static void fec_set_paddr (struct net_device *dev,u8 *mac) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + +out_be32 (&fec->paddr1, *(u32 *)(&mac[0 ])); +out_be32 (&fec->paddr2, (*(u16 *)(&mac[4 ]) <<16 ) |FEC_PADDR2_TYPE ); +} + +static void fec_get_paddr (struct net_device *dev,u8 *mac) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + + *(u32 *)(&mac[0 ]) =in_be32 (&fec->paddr1); + *(u16 *)(&mac[4 ]) =in_be32 (&fec->paddr2) >>16 ; +} + +static int fec_set_mac_address (struct net_device *dev,void *addr) +{ +struct sockaddr *sock = (struct sockaddr *)addr; + +memcpy (dev->dev_addr, sock->sa_data, dev->addr_len); + +fec_set_paddr (dev, sock->sa_data); +return 0 ; +} + +static void fec_free_rx_buffers (struct bcom_task *s) +{ +struct sk_buff *skb; + +while (!bcom_queue_empty (s)) { + skb =bcom_retrieve_buffer (s,NULL ,NULL ); +kfree_skb (skb); + } +} + +static int fec_alloc_rx_buffers (struct bcom_task *rxtsk) +{ +while (!bcom_queue_full (rxtsk)) { +struct sk_buff *skb; +struct bcom_fec_bd *bd; + + skb =dev_alloc_skb (FEC_RX_BUFFER_SIZE ); +if (skb ==0 ) +return -EAGAIN ; + +/* zero out the initial receive buffers to aid debugging */ +memset (skb->data,0 ,FEC_RX_BUFFER_SIZE ); + + bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer (rxtsk); + + bd->status =FEC_RX_BUFFER_SIZE ; + bd->skb_pa =virt_to_phys (skb->data); + +bcom_submit_next_buffer (rxtsk, skb); + } + +return 0 ; +} + +/* based on generic_adjust_link - fs_enet-main.c */ +static void fec_adjust_link (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct phy_device *phydev = priv->phydev; +int new_state =0 ; + +if (phydev->link !=PHY_DOWN ) { +if (phydev->duplex != priv->duplex) { + new_state =1 ; + priv->duplex = phydev->duplex; + } + +if (phydev->speed != priv->speed) { + new_state =1 ; + priv->speed = phydev->speed; + } + +if (priv->link ==PHY_DOWN ) { + new_state =1 ; + priv->link = phydev->link; +netif_schedule (dev); +netif_carrier_on (dev); +netif_start_queue (dev); + } + + }else if (priv->link) { + new_state =1 ; + priv->link =PHY_DOWN ; + priv->speed =0 ; + priv->duplex =-1 ; +netif_stop_queue (dev); +netif_carrier_off (dev); + } + +if (new_state &&netif_msg_link (priv)) { +phy_print_status (phydev); + } +} + +static int fec_init_phy (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct phy_device *phydev; +char phy_id[BUS_ID_SIZE ]; + +struct device_node *dn, *phy_dn; +unsigned int phy_addr; +const phandle *ph; +const unsigned int *prop; +struct resource res; +int ret; + + dn = priv->ofdev->node; + ph =of_get_property (dn,"phy-handle" ,NULL ); +if (!ph) { +dev_err (&dev->dev,"can't find \"phy-handle\" in device tree\n" ); +return -ENODEV ; + } + phy_dn =of_find_node_by_phandle (*ph); + + prop =of_get_property (phy_dn,"reg" ,NULL ); + ret =of_address_to_resource (phy_dn->parent,0 , &res); +if (ret) { +dev_err (&dev->dev,"of_address_to_resource failed\n" ); +return ret; + } + + phy_addr = *prop; +of_node_put (phy_dn); + +snprintf (phy_id,BUS_ID_SIZE ,PHY_ID_FMT , res.start, phy_addr); + + priv->link =PHY_DOWN ; + priv->speed =0 ; + priv->duplex =-1 ; + + phydev =phy_connect (dev, phy_id, &fec_adjust_link,0 ,PHY_INTERFACE_MODE_MII ); +if (IS_ERR (phydev)) { +printk (KERN_ERR "%s: phy_connect failed\n" , dev->name); +return PTR_ERR (phydev); + } + + phydev->advertising &= ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half; + + priv->phydev = phydev; + +return 0 ; +} + +static int fec_open (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +int err = -EBUSY ; + +if (request_irq (dev->irq, &fec_interrupt,IRQF_DISABLED |IRQF_SHARED , +DRIVER_NAME "_ctrl" , dev)) { +dev_err (&dev->dev,"ctrl interrupt request failed\n" ); + goto out; + } +if (request_irq (priv->r_irq, &fec_rx_interrupt,IRQF_DISABLED , +DRIVER_NAME "_rx" , dev)) { +dev_err (&dev->dev,"rx interrupt request failed\n" ); + goto free_ctrl_irq; + } +if (request_irq (priv->t_irq, &fec_tx_interrupt,IRQF_DISABLED , +DRIVER_NAME "_tx" , dev)) { +dev_err (&dev->dev,"tx interrupt request failed\n" ); + goto free_2irqs; + } + +bcom_fec_rx_reset (priv->rx_dmatsk); +bcom_fec_tx_reset (priv->tx_dmatsk); + + err =fec_alloc_rx_buffers (priv->rx_dmatsk); +if (err) { +dev_err (&dev->dev,"fec_alloc_rx_buffers failed\n" ); + goto free_irqs; + } + + err =fec_init_phy (dev); +if (err) { +dev_err (&dev->dev,"fec_init_phy failed\n" ); + goto free_skbs; + } +bcom_enable (priv->rx_dmatsk); +bcom_enable (priv->tx_dmatsk); + +/* reset phy - this also wakes it from PDOWN */ +phy_write (priv->phydev,MII_BMCR ,BMCR_RESET ); +phy_start (priv->phydev); + +fec_start (dev); + +netif_start_queue (dev); + +return 0 ; + + free_skbs: +fec_free_rx_buffers (priv->rx_dmatsk); + + free_irqs: +free_irq (priv->t_irq, dev); + free_2irqs: +free_irq (priv->r_irq, dev); + free_ctrl_irq: +free_irq (dev->irq, dev); + out: + +return err; +} + +static int fec_close (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); + +netif_stop_queue (dev); + +fec_stop (dev); + +fec_free_rx_buffers (priv->rx_dmatsk); + +phy_disconnect (priv->phydev); + +free_irq (dev->irq, dev); +free_irq (priv->r_irq, dev); +free_irq (priv->t_irq, dev); + +/* power down phy */ +phy_stop (priv->phydev); +phy_write (priv->phydev,MII_BMCR ,BMCR_PDOWN ); + +return 0 ; +} + +/* This will only be invoked if your driver is _not_ in XOFF state. +* What this means is that you need not check it, and that this +* invariant will hold if you make sure that the netif_*_queue() +* calls are done at the proper times. +*/ +static int fec_hard_start_xmit (struct sk_buff *skb,struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct bcom_fec_bd *bd; + +if (bcom_queue_full (priv->tx_dmatsk)) { +if (net_ratelimit ()) +dev_err (&dev->dev,"transmit queue overrun\n" ); +return 1 ; + } + +spin_lock_irq (&priv->lock); + dev->trans_start = jiffies; + + bd = (struct bcom_fec_bd *) +bcom_prepare_next_buffer (priv->tx_dmatsk); + + bd->status = skb->len |BCOM_FEC_TX_BD_TFD |BCOM_FEC_TX_BD_INT ; + bd->skb_pa =virt_to_phys (skb->data); + +bcom_submit_next_buffer (priv->tx_dmatsk, skb); + +if (bcom_queue_full (priv->tx_dmatsk)) { + priv->tx_full =1 ; +netif_stop_queue (dev); + } + +spin_unlock_irq (&priv->lock); + +return 0 ; +} + +/* This handles BestComm transmit task interrupts +*/ +static irqreturn_t fec_tx_interrupt (int irq,void *dev_id) +{ +struct net_device *dev = dev_id; +struct fec_priv *priv =netdev_priv (dev); + +spin_lock (&priv->lock); + +while (bcom_buffer_done (priv->tx_dmatsk)) { +struct sk_buff *skb; + skb =bcom_retrieve_buffer (priv->tx_dmatsk,NULL ,NULL ); + + priv->tx_full =0 ; +dev_kfree_skb_irq (skb); + } + +if (netif_queue_stopped (dev) && !priv->tx_full) +netif_wake_queue (dev); + +spin_unlock (&priv->lock); + +return IRQ_HANDLED ; +} + +static irqreturn_t fec_rx_interrupt (int irq,void *dev_id) +{ +struct net_device *dev = dev_id; +struct fec_priv *priv =netdev_priv (dev); + +while (bcom_buffer_done (priv->rx_dmatsk)) { +struct sk_buff *skb; +struct sk_buff *rskb; +struct bcom_fec_bd *bd; +u32 status; + + rskb =bcom_retrieve_buffer (priv->rx_dmatsk, &status,NULL ); + +/* Test for errors in received frame */ +if (status &BCOM_FEC_RX_BD_ERRORS ) { +/* Drop packet and reuse the buffer */ + bd = (struct bcom_fec_bd *) +bcom_prepare_next_buffer (priv->rx_dmatsk); + + bd->status =FEC_RX_BUFFER_SIZE ; + bd->skb_pa =virt_to_phys (rskb->data); + +bcom_submit_next_buffer (priv->rx_dmatsk, rskb); + + priv->stats.rx_dropped++; + +continue ; + } + +/* skbs are allocated on open, so now we allocate a new one, +* and remove the old (with the packet) */ + skb =dev_alloc_skb (FEC_RX_BUFFER_SIZE ); +if (skb) { +/* Process the received skb */ +int length = status &BCOM_FEC_RX_BD_LEN_MASK ; + +skb_put (rskb, length -4 );/* length without CRC32 */ + + rskb->dev = dev; + rskb->protocol =eth_type_trans (rskb, dev); + +netif_rx (rskb); + dev->last_rx = jiffies; + }else { +/* Can't get a new one : reuse the same & drop pkt */ +dev_notice (&dev->dev,"Memory squeeze, dropping packet.\n" ); + priv->stats.rx_dropped++; + + skb = rskb; + } + + bd = (struct bcom_fec_bd *) +bcom_prepare_next_buffer (priv->rx_dmatsk); + + bd->status =FEC_RX_BUFFER_SIZE ; + bd->skb_pa =virt_to_phys (skb->data); + +bcom_submit_next_buffer (priv->rx_dmatsk, skb); + } + +return IRQ_HANDLED ; +} + +static irqreturn_t fec_interrupt (int irq,void *dev_id) +{ +struct net_device *dev = dev_id; +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +u32 ievent; + + ievent =in_be32 (&fec->ievent); + + ievent &= ~FEC_IEVENT_MII ;/* mii is handled separately */ +if (!ievent) +return IRQ_NONE ; + +out_be32 (&fec->ievent, ievent);/* clear pending events */ + +if (ievent & ~(FEC_IEVENT_RFIFO_ERROR |FEC_IEVENT_XFIFO_ERROR )) { +if (ievent & ~FEC_IEVENT_TFINT ) +dev_dbg (&dev->dev,"ievent: %08x\n" , ievent); +return IRQ_HANDLED ; + } + +if (net_ratelimit () && (ievent &FEC_IEVENT_RFIFO_ERROR )) +dev_warn (&dev->dev,"FEC_IEVENT_RFIFO_ERROR\n" ); +if (net_ratelimit () && (ievent &FEC_IEVENT_XFIFO_ERROR )) +dev_warn (&dev->dev,"FEC_IEVENT_XFIFO_ERROR\n" ); + +fec_stop (dev); +fec_hw_init (dev); +fec_start (dev); + +netif_wake_queue (dev); +return IRQ_HANDLED ; +} + +/* +* Get the current statistics. +* This may be called with the card open or closed. +*/ +static struct net_device_stats *fec_get_stats (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct net_device_stats *stats = &priv->stats; +struct mpc52xx_fec __iomem *fec = priv->fec; + +/* printk(KERN_ALERT "%s: %i, rmon_r_octets: %i, rmon_r_packets: %i, " +"ieee_r_octets_ok: %i, ieee_r_frame_ok: %i, " +"%i\n", +__func__, __LINE__, +in_be32(&fec->rmon_r_octets), in_be32(&fec->rmon_r_packets), +in_be32(&fec->ieee_r_octets_ok), in_be32(&fec->ieee_r_frame_ok), +0); +*/ + stats->rx_bytes =in_be32 (&fec->rmon_r_octets); + stats->rx_packets =in_be32 (&fec->rmon_r_packets); + stats->rx_errors =in_be32 (&fec->rmon_r_crc_align) + +in_be32 (&fec->rmon_r_undersize) + +in_be32 (&fec->rmon_r_oversize) + +in_be32 (&fec->rmon_r_frag) + +in_be32 (&fec->rmon_r_jab); + + stats->tx_bytes =in_be32 (&fec->rmon_t_octets); + stats->tx_packets =in_be32 (&fec->rmon_t_packets); + stats->tx_errors =in_be32 (&fec->rmon_t_crc_align) + +in_be32 (&fec->rmon_t_undersize) + +in_be32 (&fec->rmon_t_oversize) + +in_be32 (&fec->rmon_t_frag) + +in_be32 (&fec->rmon_t_jab); + + stats->multicast =in_be32 (&fec->rmon_r_mc_pkt); + stats->collisions =in_be32 (&fec->rmon_t_col); + +/* detailed rx_errors: */ + stats->rx_length_errors =in_be32 (&fec->rmon_r_undersize) + +in_be32 (&fec->rmon_r_oversize) + +in_be32 (&fec->rmon_r_frag) + +in_be32 (&fec->rmon_r_jab); + stats->rx_over_errors =in_be32 (&fec->r_macerr); + stats->rx_crc_errors =in_be32 (&fec->ieee_r_crc); + stats->rx_frame_errors =in_be32 (&fec->ieee_r_align); + stats->rx_fifo_errors =in_be32 (&fec->rmon_r_drop); + stats->rx_missed_errors =in_be32 (&fec->rmon_r_drop); + +/* detailed tx_errors: */ + stats->tx_aborted_errors =0 ; + stats->tx_carrier_errors =in_be32 (&fec->ieee_t_cserr); + stats->tx_fifo_errors =in_be32 (&fec->rmon_t_drop); + stats->tx_heartbeat_errors =in_be32 (&fec->ieee_t_sqe); + stats->tx_window_errors =in_be32 (&fec->ieee_t_lcol); + +return stats; +} + +/* +* Read MIB counters in order to reset them, +* then zero all the stats fields in memory +*/ +static void fec_reset_stats (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + +out_be32 (&fec->mib_control,FEC_MIB_DISABLE ); +memset_io (&fec->rmon_t_drop,0 , + (u32 )&fec->reserved10 - (u32)&fec->rmon_t_drop); +out_be32 (&fec->mib_control,0 ); + +memset (&priv->stats,0 ,sizeof (priv->stats)); +} + +/* +* Set or clear the multicast filter for this adaptor. +*/ +static void fec_set_multicast_list (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +u32 rx_control; + + rx_control =in_be32 (&fec->r_cntrl); + +if (dev->flags &IFF_PROMISC ) { + rx_control |=FEC_RCNTRL_PROM ; +out_be32 (&fec->r_cntrl, rx_control); + }else { + rx_control &= ~FEC_RCNTRL_PROM ; +out_be32 (&fec->r_cntrl, rx_control); + +if (dev->flags &IFF_ALLMULTI ) { +out_be32 (&fec->gaddr1,0xffffffff ); +out_be32 (&fec->gaddr2,0xffffffff ); + }else { +u32 crc; +int i; +struct dev_mc_list *dmi; +u32 gaddr1 =0x00000000 ; +u32 gaddr2 =0x00000000 ; + + dmi = dev->mc_list; +for (i=0 ; i<dev->mc_count; i++) { + crc =ether_crc_le (6 , dmi->dmi_addr) >>26 ; +if (crc >=32 ) + gaddr1 |=1 << (crc-32 ); +else + gaddr2 |=1 << crc; + dmi = dmi->next; + } +out_be32 (&fec->gaddr1, gaddr1); +out_be32 (&fec->gaddr2, gaddr2); + } + } +} + +static void __init fec_str2mac (char *str,unsigned char *mac) +{ +int i; +u64 val64; + + val64 =simple_strtoull (str,NULL ,16 ); + +for (i =0 ; i <6 ; i++) + mac[5 -i] = val64 >> (i*8 ); +} + +static int __init mpc52xx_fec_mac_setup (char *mac_address) +{ +fec_str2mac (mac_address, mpc52xx_fec_mac_addr); +return 0 ; +} + +/* XXX do we need this? */ +__setup ("mpc52xx-mac=" , mpc52xx_fec_mac_setup); + +/** +* fec_hw_init +* @dev: network device +* +* Setup various hardware setting, only needed once on start +*/ +static void fec_hw_init (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +int i; + +/* Whack a reset. We should wait for this. */ +out_be32 (&fec->ecntrl,FEC_ECNTRL_RESET ); +for (i =0 ; i <FEC_RESET_DELAY ; ++i) { +if ((in_be32 (&fec->ecntrl) &FEC_ECNTRL_RESET ) ==0 ) +break ; +udelay (1 ); + } +if (i ==FEC_RESET_DELAY ) +dev_err (&dev->dev,"FEC Reset timeout!\n" ); + +/* set pause to 0x20 frames */ +out_be32 (&fec->op_pause,FEC_OP_PAUSE_OPCODE |0x20 ); + +/* high service request will be deasserted when there's < 7 bytes in fifo +* low service request will be deasserted when there's < 4*7 bytes in fifo +*/ +out_be32 (&fec->rfifo_cntrl,FEC_FIFO_CNTRL_FRAME |FEC_FIFO_CNTRL_LTG_7 ); +out_be32 (&fec->tfifo_cntrl,FEC_FIFO_CNTRL_FRAME |FEC_FIFO_CNTRL_LTG_7 ); + +/* alarm when <= x bytes in FIFO */ +out_be32 (&fec->rfifo_alarm,0x0000030c ); +out_be32 (&fec->tfifo_alarm,0x00000100 ); + +/* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */ +out_be32 (&fec->x_wmrk,FEC_FIFO_WMRK_256B ); + +/* enable crc generation */ +out_be32 (&fec->xmit_fsm,FEC_XMIT_FSM_APPEND_CRC |FEC_XMIT_FSM_ENABLE_CRC ); +out_be32 (&fec->iaddr1,0x00000000 );/* No individual filter */ +out_be32 (&fec->iaddr2,0x00000000 );/* No individual filter */ + +/* set phy speed and enable MII interrupt +* this can't be done in phy driver, since it needs to be called +* before fec stuff (even on resume) */ +set_phy_speed (fec, priv->phy_speed); +out_be32 (&fec->imask,in_be32 (&fec->imask) |FEC_IMASK_MII ); +} + +/** +* fec_start +* @dev: network device +* +* This function is called to start or restart the FEC during a link +* change. This happens on fifo errors or when switching between half +* and full duplex. +*/ +static void fec_start (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +u32 rcntrl; +u32 tcntrl; +u32 tmp; + +/* clear sticky error bits */ + tmp =FEC_FIFO_STATUS_ERR |FEC_FIFO_STATUS_UF |FEC_FIFO_STATUS_OF ; +out_be32 (&fec->rfifo_status,in_be32 (&fec->rfifo_status) & tmp); +out_be32 (&fec->tfifo_status,in_be32 (&fec->tfifo_status) & tmp); + +/* FIFOs will reset on fec_enable */ +out_be32 (&fec->reset_cntrl,FEC_RESET_CNTRL_ENABLE_IS_RESET ); + +/* Set station address. */ +fec_set_paddr (dev, dev->dev_addr); + +fec_set_multicast_list (dev); + +/* set max frame len, enable flow control, select mii mode */ + rcntrl =FEC_RX_BUFFER_SIZE <<16 ;/* max frame length */ + rcntrl |=FEC_RCNTRL_FCE ; + rcntrl |=MII_RCNTL_MODE ; +if (priv->duplex ==DUPLEX_FULL ) + tcntrl =FEC_TCNTRL_FDEN ;/* FD enable */ +else { + rcntrl |=FEC_RCNTRL_DRT ;/* disable Rx on Tx (HD) */ + tcntrl =0 ; + } +out_be32 (&fec->r_cntrl, rcntrl); +out_be32 (&fec->x_cntrl, tcntrl); + +/* Clear any outstanding interrupt. */ +out_be32 (&fec->ievent,0xffffffff ); + +/* Enable interrupts we wish to service. */ +out_be32 (&fec->imask,FEC_IMASK_ENABLE ); + +/* And last, enable the transmit and receive processing. */ +out_be32 (&fec->ecntrl,FEC_ECNTRL_ETHER_EN ); +out_be32 (&fec->r_des_active,0x01000000 ); + + priv->tx_full =0 ; +} + +/** +* fec_stop +* @dev: network device +* +* stop all activity on fec and empty dma buffers +*/ +static void fec_stop (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +unsigned long timeout; + +out_be32 (&fec->imask,FEC_IMASK_MII );/* disable all but MII interrupt */ + +/* Disable the rx and tx tasks. */ +bcom_disable (priv->rx_dmatsk); + +/* Wait for queues to drain, but only if we're in process context */ +if (!in_interrupt ()) { + timeout = jiffies +2 *HZ ; +while (time_before (jiffies, timeout) && + (!bcom_queue_empty (priv->tx_dmatsk) || + !bcom_queue_empty (priv->rx_dmatsk))) { +set_current_state (TASK_INTERRUPTIBLE ); +schedule_timeout (HZ /10 ); + } +if (time_after_eq (jiffies, timeout)) +dev_err (&dev->dev,"queues didn't drain\n" ); + } + +bcom_disable (priv->tx_dmatsk); + +/* Stop FEC */ +out_be32 (&fec->ecntrl,in_be32 (&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN ); + +return ; +} + +static int fec_ioctl (struct net_device *dev,struct ifreq *rq,int cmd) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; + +return phy_mii_ioctl (priv->phydev, mii, cmd); +} + +/* ======================================================================== */ +/* OF Driver */ +/* ======================================================================== */ + +static int __devinit +mpc52xx_fec_probe (struct of_device *op,const struct of_device_id *match) +{ +int rv; +struct net_device *ndev; +struct fec_priv *priv =NULL ; +struct resource mem; + +phys_addr_t rx_fifo; +phys_addr_t tx_fifo; + +/* Get the ether ndev & it's private zone */ + ndev =alloc_etherdev (sizeof (struct fec_priv )); +if (!ndev) +return -ENOMEM ; + + priv =netdev_priv (ndev); + + priv->ofdev = op; + +/* Reserve FEC control zone */ + rv =of_address_to_resource (op->node,0 , &mem); +if (rv) { + printk(KERN_ERR DRIVER_NAME ": " + "Error while parsing device node resource\n" ); +return rv; + } +if ((mem.end - mem.start +1 ) !=sizeof (struct mpc52xx_fec )) { + printk(KERN_ERR DRIVER_NAME +" - invalid resource size (%lx != %x), check mpc52xx_devices.c\n" , + (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec)); +return -EINVAL ; + } + +if (!request_mem_region (mem.start,sizeof (struct mpc52xx_fec ),DRIVER_NAME )) +return -EBUSY ; + +/* Init ether ndev with what we have */ + ndev->open = fec_open; + ndev->stop = fec_close; + ndev->hard_start_xmit = fec_hard_start_xmit; + ndev->do_ioctl = fec_ioctl; + ndev->get_stats = fec_get_stats; + ndev->set_mac_address = fec_set_mac_address; + ndev->set_multicast_list = fec_set_multicast_list; + ndev->tx_timeout = fec_tx_timeout; + ndev->watchdog_timeo =FEC_WATCHDOG_TIMEOUT ; + ndev->flags &= ~IFF_RUNNING ; + ndev->base_addr = mem.start; + + priv->t_irq = priv->r_irq = ndev->irq =NO_IRQ ;/* IRQ are free for now */ + +spin_lock_init (&priv->lock); + +/* ioremap the zones */ + priv->fec =ioremap (mem.start,sizeof (struct mpc52xx_fec )); + +if (!priv->fec) { + rv = -ENOMEM ; + goto probe_error; + } + +/* Bestcomm init */ + rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec , rfifo_data); + tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec , tfifo_data); + + priv->rx_dmatsk =bcom_fec_rx_init (FEC_RX_NUM_BD , rx_fifo,FEC_RX_BUFFER_SIZE ); + priv->tx_dmatsk =bcom_fec_tx_init (FEC_TX_NUM_BD , tx_fifo); + +if (!priv->rx_dmatsk || !priv->tx_dmatsk) { + printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" ); + rv = -ENOMEM ; + goto probe_error; + } + +/* Get the IRQ we need one by one */ +/* Control */ + ndev->irq =irq_of_parse_and_map (op->node,0 ); + +/* RX */ + priv->r_irq =bcom_get_task_irq (priv->rx_dmatsk); + +/* TX */ + priv->t_irq =bcom_get_task_irq (priv->tx_dmatsk); + +/* MAC address init */ +if (memcmp (mpc52xx_fec_mac_addr, null_mac,6 ) !=0 ) +memcpy (ndev->dev_addr, mpc52xx_fec_mac_addr,6 ); +else +fec_get_paddr (ndev, ndev->dev_addr); + +/* Phy speed */ + priv->phy_speed = ((mpc52xx_find_ipb_freq (op->node) >>20 ) /5 ) <<1 ; + + priv->msg_enable = (NETIF_MSG_IFUP <<1 ) -1 ; + priv->duplex =DUPLEX_HALF ; + +/* Hardware init */ +fec_hw_init (ndev); + +fec_reset_stats (ndev); + +/* Register the new network device */ + rv =register_netdev (ndev); +if (rv <0 ) + goto probe_error; + +/* We're done ! */ +dev_set_drvdata (&op->dev, ndev); + +return 0 ; + + +/* Error handling - free everything that might be allocated */ +probe_error: + +irq_dispose_mapping (ndev->irq); + +if (priv->rx_dmatsk) +bcom_fec_rx_release (priv->rx_dmatsk); +if (priv->tx_dmatsk) +bcom_fec_tx_release (priv->tx_dmatsk); + +if (priv->fec) +iounmap (priv->fec); + +release_mem_region (mem.start,sizeof (struct mpc52xx_fec )); + +free_netdev (ndev); + +return rv; +} + +static int +mpc52xx_fec_remove (struct of_device *op) +{ +struct net_device *ndev; +struct fec_priv *priv; + + ndev =dev_get_drvdata (&op->dev); +if (!ndev) +return 0 ; + priv =netdev_priv (ndev); + +unregister_netdev (ndev); + +irq_dispose_mapping (ndev->irq); + +bcom_fec_rx_release (priv->rx_dmatsk); +bcom_fec_tx_release (priv->tx_dmatsk); + +iounmap (priv->fec); + +release_mem_region (ndev->base_addr,sizeof (struct mpc52xx_fec )); + +free_netdev (ndev); + +dev_set_drvdata (&op->dev,NULL ); +return 0 ; +} + +#ifdef CONFIG_PM +static int mpc52xx_fec_of_suspend (struct of_device *op,pm_message_t state) +{ +struct net_device *dev =dev_get_drvdata (&op->dev); + +if (netif_running (dev)) +fec_close (dev); + +return 0 ; +} + +static int mpc52xx_fec_of_resume (struct of_device *op) +{ +struct net_device *dev =dev_get_drvdata (&op->dev); + +fec_hw_init (dev); +fec_reset_stats (dev); + +if (netif_running (dev)) +fec_open (dev); + +return 0 ; +} +#endif + +static struct of_device_id mpc52xx_fec_match[] = { + { + .type ="network" , + .compatible ="mpc5200-fec" , + }, + { } +}; + +MODULE_DEVICE_TABLE (of, mpc52xx_fec_match); + +static struct of_platform_driver mpc52xx_fec_driver = { + .owner =THIS_MODULE , + .name =DRIVER_NAME , + .match_table = mpc52xx_fec_match, + .probe = mpc52xx_fec_probe, + .remove = mpc52xx_fec_remove, +#ifdef CONFIG_PM + .suspend = mpc52xx_fec_of_suspend, + .resume = mpc52xx_fec_of_resume, +#endif +}; + + +/* ======================================================================== */ +/* Module */ +/* ======================================================================== */ + +static int __init +mpc52xx_fec_init (void ) +{ +int ret; +if ((ret =fec_mdio_init ())) { +printk (KERN_ERR "%s: %i fec_mdio_init failed\n" , __func__, __LINE__); +return ret; + } + +return of_register_platform_driver (&mpc52xx_fec_driver); +} + +static void __exit +mpc52xx_fec_exit (void ) +{ +of_unregister_platform_driver (&mpc52xx_fec_driver); +fec_mdio_exit (); +} + + +module_init (mpc52xx_fec_init); +module_exit (mpc52xx_fec_exit); + +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Dale Farnsworth" ); +MODULE_DESCRIPTION ("Ethernet driver for the Freescale MPC52xx FEC" ); +
drivers/net/fec_mpc52xx/fec.h renamed from fec.h +299 -0
299 lines not on this page · raw message
drivers/net/fec_mpc52xx/fec_phy.c renamed from fec_phy.c +229 -0
229 lines not on this page · raw message
drivers/net/fec_mpc52xx/fec_phy.h renamed from fec_phy.h +49 -0
49 lines not on this page · raw message
drivers/net/fec_mpc52xx/Kconfig renamed from Kconfig +24 -0
@@ -0,0 +1,24 @@ +menu "MPC5200 Networking Options" + depends PPC_MPC52xx && NET_ETHERNET + +config FEC_MPC52xx + tristate "FEC Ethernet" + depends on NET_ETHERNET + select PPC_BESTCOMM + select PPC_BESTCOMM_FEC + select CRC32 + ---help--- + This option enables support for the MPC5200's on-chip + Fast Ethernet Controller + +config USE_MDIO + bool "Use external Ethernet MII PHY" + select MII + depends FEC_MPC52xx + ---help--- + The MPC5200's FEC can connect to the Ethernet either with + an external MII PHY chip or 10 Mbps 7-wire interface + (Motorola? industry standard). + If your board uses an external PHY, say y, else n. + +endmenu
drivers/net/fec_mpc52xx/Makefile renamed from Makefile +7 -0
@@ -0,0 +1,7 @@ +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o + +fec_mpc52xx-objs := fec.o + +ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) +fec_mpc52xx-objs += fec_phy.o +endif
arch/powerpc/boot/dts/lite5200b.dts +17 -1
@@ -365,10 +365,26 @@ ethernet@3000 { device_type = "network"; compatible = "mpc5200b-fec\0mpc5200-fec"; - reg = <3000 800>; + reg = <3000 400>; mac-address = [ 02 03 04 05 06 07 ]; // Bad! interrupts = <2 5 0>; interrupt-parent = <&mpc5200_pic>; + phy-handle = <&phy0>; + }; + + mdio@3000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio"; + compatible = "mpc5200b-fec-phy"; + reg = <3000 400>; // fec range, since we need to setup fec interrupts + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co. + interrupt-parent = <&mpc5200_pic>; + + phy0:ethernet-phy@0 { + device_type = "ethernet-phy"; + reg = <0>; + }; }; ata@3a00 {
arch/powerpc/sysdev/bestcomm/fec.h +14 -0
@@ -22,6 +22,20 @@ struct bcom_fec_bd {#define BCOM_FEC_TX_BD_TFD 0x08000000ul/* transmit frame done */ #define BCOM_FEC_TX_BD_INT 0x04000000ul/* interrupt */ +#define BCOM_FEC_TX_BD_TC 0x04000000ul/* transmit CRC XXX same as ^? */ +#define BCOM_FEC_TX_BD_ABC 0x02000000ul/* append bad CRC */ + +#define BCOM_FEC_RX_BD_L 0x08000000ul/* buffer is last in frame */ +#define BCOM_FEC_RX_BD_BC 0x00800000ul/* DA is broadcast */ +#define BCOM_FEC_RX_BD_MC 0x00400000ul/* DA is multicast and not broadcast */ +#define BCOM_FEC_RX_BD_LG 0x00200000ul/* Rx frame length violation */ +#define BCOM_FEC_RX_BD_NO 0x00100000ul/* Rx non-octet aligned frame */ +#define BCOM_FEC_RX_BD_CR 0x00040000ul/* Rx CRC error */ +#define BCOM_FEC_RX_BD_OV 0x00020000ul/* overrun */ +#define BCOM_FEC_RX_BD_TR 0x00010000ul/* Rx frame truncated */ +#define BCOM_FEC_RX_BD_LEN_MASK 0x000007fful/* mask for length of received frame */ +#define BCOM_FEC_RX_BD_ERRORS (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \ + BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR) extern struct bcom_task *
Em Fri, Aug 10, 2007 at 11:51:53AM +0200, Domen Puncer escreveu:
Quoted 78 lines
Hi!
Not for merge (yet)! But please do review.
fec_mpc52xxdriver (not in-tree, but floating around) isn't in very good shape, so I tried to change that.
Diff against original is quite big (fec_phy.cis completely rewritten) and confuzing, so I'm including wholedrivers/net/fec_mpc52xx/.I still have 'make CONFIG_FEC_MPC52xx_MDIO=n compile and work' on my TODO, maybe even ethtool support.
Domen
arch/powerpc/boot/dts/lite5200b.dts | 18 arch/powerpc/sysdev/bestcomm/fec.h | 14 drivers/net/fec_mpc52xx/Kconfig | 24 drivers/net/fec_mpc52xx/Makefile | 7 drivers/net/fec_mpc52xx/fec.c | 1002 ++++++++++++++++++++++++++++++++++++ drivers/net/fec_mpc52xx/fec.h | 299 ++++++++++ drivers/net/fec_mpc52xx/fec_phy.c | 229 ++++++++ drivers/net/fec_mpc52xx/fec_phy.h | 49 + 8 files changed, 1641 insertions(+), 1 deletion(-)diff -pruN
dummy/fec.c./drivers/net/fec_mpc52xx/fec.cdrivers/net/fec_mpc52xx/fec.c renamed from fec.c +48
-0@@ -0,0 +1,1002 @@ +/* +* drivers/net/fec_mpc52xx/fec.c +* +* Driver for the MPC5200 Fast Ethernet Controller +* +* Originally written by Dale Farnsworth <[email protected]> and +* now maintained by Sylvain Munaut <[email protected]> +* +* Copyright (C) 2007 Sylvain Munaut <[email protected]> +* Copyrigth (C) 2003-2004 MontaVista, Software, Inc. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +*/ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/crc32.h> +#include <linux/hardirq.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> + +#include <asm/of_device.h> +#include <asm/of_platform.h> +#include <asm/io.h> +#include <asm/delay.h> +#include <asm/mpc52xx.h> + +#include <sysdev/bestcomm/bestcomm.h> +#include <sysdev/bestcomm/fec.h> + +#include "fec_phy.h" +#include "fec.h" + +#define DRIVER_NAME "mpc52xx-fec" + +static irqreturn_t fec_interrupt (int ,void *); +static irqreturn_t fec_rx_interrupt (int ,void *);
drivers/net/fec_mpc52xx/fec.c line 57
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +9
-0+static irqreturn_t fec_tx_interrupt (int ,void *); +static struct net_device_stats *fec_get_stats (struct net_device *); +static void fec_set_multicast_list (struct net_device *dev); +static void fec_hw_init (struct net_device *dev); +static void fec_stop (struct net_device *dev); +static void fec_start (struct net_device *dev); + +static u8 mpc52xx_fec_mac_addr[6 ]; +static u8 null_mac[6 ];
const
Quoted 13 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +13
-0+ +static void fec_tx_timeout (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); + +dev_warn (&dev->dev,"transmit timed out\n" ); + +fec_stop (dev); +fec_start (dev); + + priv->stats.tx_errors++; + +if (!priv->tx_full)
drivers/net/fec_mpc52xx/fec.c line 80
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10
-0+netif_wake_queue (dev); +} + +static void fec_set_paddr (struct net_device *dev,u8 *mac) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + +out_be32 (&fec->paddr1, *(u32 *)(&mac[0 ])); +out_be32 (&fec->paddr2, (*(u16 *)(&mac[4 ]) <<16 ) |FEC_PADDR2_TYPE );
spaces after the types on casts to pointers
drivers/net/fec_mpc52xx/fec.c line 89
Quoted 9 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +9
-0+} + +static void fec_get_paddr (struct net_device *dev,u8 *mac) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + + *(u32 *)(&mac[0 ]) =in_be32 (&fec->paddr1); + *(u16 *)(&mac[4 ]) =in_be32 (&fec->paddr2) >>16 ;
ditto
drivers/net/fec_mpc52xx/fec.c line 94
Quoted 5 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5
-0+} + +static int fec_set_mac_address (struct net_device *dev,void *addr) +{ +struct sockaddr *sock = (struct sockaddr *)addr;
no need for a cast, addr is a void pointer
drivers/net/fec_mpc52xx/fec.c line 99
Quoted 5 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5
-0+ +memcpy (dev->dev_addr, sock->sa_data, dev->addr_len); + +fec_set_paddr (dev, sock->sa_data); +return 0 ;
Why always return 0? make it void
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10
-0+} + +static void fec_free_rx_buffers (struct bcom_task *s) +{ +struct sk_buff *skb; + +while (!bcom_queue_empty (s)) { + skb =bcom_retrieve_buffer (s,NULL ,NULL ); +kfree_skb (skb); + }
drivers/net/fec_mpc52xx/fec.c line 119
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10
-0+} + +static int fec_alloc_rx_buffers (struct bcom_task *rxtsk) +{ +while (!bcom_queue_full (rxtsk)) { +struct sk_buff *skb; +struct bcom_fec_bd *bd; + + skb =dev_alloc_skb (FEC_RX_BUFFER_SIZE ); +if (skb ==0 )
Test against NULL
Quoted 44 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +44
-0+return -EAGAIN ; + +/* zero out the initial receive buffers to aid debugging */ +memset (skb->data,0 ,FEC_RX_BUFFER_SIZE ); + + bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer (rxtsk); + + bd->status =FEC_RX_BUFFER_SIZE ; + bd->skb_pa =virt_to_phys (skb->data); + +bcom_submit_next_buffer (rxtsk, skb); + } + +return 0 ; +} + +/* based on generic_adjust_link - fs_enet-main.c */ +static void fec_adjust_link (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct phy_device *phydev = priv->phydev; +int new_state =0 ; + +if (phydev->link !=PHY_DOWN ) { +if (phydev->duplex != priv->duplex) { + new_state =1 ; + priv->duplex = phydev->duplex; + } + +if (phydev->speed != priv->speed) { + new_state =1 ; + priv->speed = phydev->speed; + } + +if (priv->link ==PHY_DOWN ) { + new_state =1 ; + priv->link = phydev->link; +netif_schedule (dev); +netif_carrier_on (dev); +netif_start_queue (dev); + } + + }else if (priv->link) { + new_state =1 ;
drivers/net/fec_mpc52xx/fec.c line 173
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10
-0+ priv->link =PHY_DOWN ; + priv->speed =0 ; + priv->duplex =-1 ; +netif_stop_queue (dev); +netif_carrier_off (dev); + } + +if (new_state &&netif_msg_link (priv)) { +phy_print_status (phydev); + }
No need for {}, this if has only one statement
Quoted 797 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +797
-0+} + +static int fec_init_phy (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct phy_device *phydev; +char phy_id[BUS_ID_SIZE ]; + +struct device_node *dn, *phy_dn; +unsigned int phy_addr; +const phandle *ph; +const unsigned int *prop; +struct resource res; +int ret; + + dn = priv->ofdev->node; + ph =of_get_property (dn,"phy-handle" ,NULL ); +if (!ph) { +dev_err (&dev->dev,"can't find \"phy-handle\" in device tree\n" ); +return -ENODEV ; + } + phy_dn =of_find_node_by_phandle (*ph); + + prop =of_get_property (phy_dn,"reg" ,NULL ); + ret =of_address_to_resource (phy_dn->parent,0 , &res); +if (ret) { +dev_err (&dev->dev,"of_address_to_resource failed\n" ); +return ret; + } + + phy_addr = *prop; +of_node_put (phy_dn); + +snprintf (phy_id,BUS_ID_SIZE ,PHY_ID_FMT , res.start, phy_addr); + + priv->link =PHY_DOWN ; + priv->speed =0 ; + priv->duplex =-1 ; + + phydev =phy_connect (dev, phy_id, &fec_adjust_link,0 ,PHY_INTERFACE_MODE_MII ); +if (IS_ERR (phydev)) { +printk (KERN_ERR "%s: phy_connect failed\n" , dev->name); +return PTR_ERR (phydev); + } + + phydev->advertising &= ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half; + + priv->phydev = phydev; + +return 0 ; +} + +static int fec_open (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +int err = -EBUSY ; + +if (request_irq (dev->irq, &fec_interrupt,IRQF_DISABLED |IRQF_SHARED , +DRIVER_NAME "_ctrl" , dev)) { +dev_err (&dev->dev,"ctrl interrupt request failed\n" ); + goto out; + } +if (request_irq (priv->r_irq, &fec_rx_interrupt,IRQF_DISABLED , +DRIVER_NAME "_rx" , dev)) { +dev_err (&dev->dev,"rx interrupt request failed\n" ); + goto free_ctrl_irq; + } +if (request_irq (priv->t_irq, &fec_tx_interrupt,IRQF_DISABLED , +DRIVER_NAME "_tx" , dev)) { +dev_err (&dev->dev,"tx interrupt request failed\n" ); + goto free_2irqs; + } + +bcom_fec_rx_reset (priv->rx_dmatsk); +bcom_fec_tx_reset (priv->tx_dmatsk); + + err =fec_alloc_rx_buffers (priv->rx_dmatsk); +if (err) { +dev_err (&dev->dev,"fec_alloc_rx_buffers failed\n" ); + goto free_irqs; + } + + err =fec_init_phy (dev); +if (err) { +dev_err (&dev->dev,"fec_init_phy failed\n" ); + goto free_skbs; + } +bcom_enable (priv->rx_dmatsk); +bcom_enable (priv->tx_dmatsk); + +/* reset phy - this also wakes it from PDOWN */ +phy_write (priv->phydev,MII_BMCR ,BMCR_RESET ); +phy_start (priv->phydev); + +fec_start (dev); + +netif_start_queue (dev); + +return 0 ; + + free_skbs: +fec_free_rx_buffers (priv->rx_dmatsk); + + free_irqs: +free_irq (priv->t_irq, dev); + free_2irqs: +free_irq (priv->r_irq, dev); + free_ctrl_irq: +free_irq (dev->irq, dev); + out: + +return err; +} + +static int fec_close (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); + +netif_stop_queue (dev); + +fec_stop (dev); + +fec_free_rx_buffers (priv->rx_dmatsk); + +phy_disconnect (priv->phydev); + +free_irq (dev->irq, dev); +free_irq (priv->r_irq, dev); +free_irq (priv->t_irq, dev); + +/* power down phy */ +phy_stop (priv->phydev); +phy_write (priv->phydev,MII_BMCR ,BMCR_PDOWN ); + +return 0 ; +} + +/* This will only be invoked if your driver is _not_ in XOFF state. +* What this means is that you need not check it, and that this +* invariant will hold if you make sure that the netif_*_queue() +* calls are done at the proper times. +*/ +static int fec_hard_start_xmit (struct sk_buff *skb,struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct bcom_fec_bd *bd; + +if (bcom_queue_full (priv->tx_dmatsk)) { +if (net_ratelimit ()) +dev_err (&dev->dev,"transmit queue overrun\n" ); +return 1 ; + } + +spin_lock_irq (&priv->lock); + dev->trans_start = jiffies; + + bd = (struct bcom_fec_bd *) +bcom_prepare_next_buffer (priv->tx_dmatsk); + + bd->status = skb->len |BCOM_FEC_TX_BD_TFD |BCOM_FEC_TX_BD_INT ; + bd->skb_pa =virt_to_phys (skb->data); + +bcom_submit_next_buffer (priv->tx_dmatsk, skb); + +if (bcom_queue_full (priv->tx_dmatsk)) { + priv->tx_full =1 ; +netif_stop_queue (dev); + } + +spin_unlock_irq (&priv->lock); + +return 0 ; +} + +/* This handles BestComm transmit task interrupts +*/ +static irqreturn_t fec_tx_interrupt (int irq,void *dev_id) +{ +struct net_device *dev = dev_id; +struct fec_priv *priv =netdev_priv (dev); + +spin_lock (&priv->lock); + +while (bcom_buffer_done (priv->tx_dmatsk)) { +struct sk_buff *skb; + skb =bcom_retrieve_buffer (priv->tx_dmatsk,NULL ,NULL ); + + priv->tx_full =0 ; +dev_kfree_skb_irq (skb); + } + +if (netif_queue_stopped (dev) && !priv->tx_full) +netif_wake_queue (dev); + +spin_unlock (&priv->lock); + +return IRQ_HANDLED ; +} + +static irqreturn_t fec_rx_interrupt (int irq,void *dev_id) +{ +struct net_device *dev = dev_id; +struct fec_priv *priv =netdev_priv (dev); + +while (bcom_buffer_done (priv->rx_dmatsk)) { +struct sk_buff *skb; +struct sk_buff *rskb; +struct bcom_fec_bd *bd; +u32 status; + + rskb =bcom_retrieve_buffer (priv->rx_dmatsk, &status,NULL ); + +/* Test for errors in received frame */ +if (status &BCOM_FEC_RX_BD_ERRORS ) { +/* Drop packet and reuse the buffer */ + bd = (struct bcom_fec_bd *) +bcom_prepare_next_buffer (priv->rx_dmatsk); + + bd->status =FEC_RX_BUFFER_SIZE ; + bd->skb_pa =virt_to_phys (rskb->data); + +bcom_submit_next_buffer (priv->rx_dmatsk, rskb); + + priv->stats.rx_dropped++; + +continue ; + } + +/* skbs are allocated on open, so now we allocate a new one, +* and remove the old (with the packet) */ + skb =dev_alloc_skb (FEC_RX_BUFFER_SIZE ); +if (skb) { +/* Process the received skb */ +int length = status &BCOM_FEC_RX_BD_LEN_MASK ; + +skb_put (rskb, length -4 );/* length without CRC32 */ + + rskb->dev = dev; + rskb->protocol =eth_type_trans (rskb, dev); + +netif_rx (rskb); + dev->last_rx = jiffies; + }else { +/* Can't get a new one : reuse the same & drop pkt */ +dev_notice (&dev->dev,"Memory squeeze, dropping packet.\n" ); + priv->stats.rx_dropped++; + + skb = rskb; + } + + bd = (struct bcom_fec_bd *) +bcom_prepare_next_buffer (priv->rx_dmatsk); + + bd->status =FEC_RX_BUFFER_SIZE ; + bd->skb_pa =virt_to_phys (skb->data); + +bcom_submit_next_buffer (priv->rx_dmatsk, skb); + } + +return IRQ_HANDLED ; +} + +static irqreturn_t fec_interrupt (int irq,void *dev_id) +{ +struct net_device *dev = dev_id; +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +u32 ievent; + + ievent =in_be32 (&fec->ievent); + + ievent &= ~FEC_IEVENT_MII ;/* mii is handled separately */ +if (!ievent) +return IRQ_NONE ; + +out_be32 (&fec->ievent, ievent);/* clear pending events */ + +if (ievent & ~(FEC_IEVENT_RFIFO_ERROR |FEC_IEVENT_XFIFO_ERROR )) { +if (ievent & ~FEC_IEVENT_TFINT ) +dev_dbg (&dev->dev,"ievent: %08x\n" , ievent); +return IRQ_HANDLED ; + } + +if (net_ratelimit () && (ievent &FEC_IEVENT_RFIFO_ERROR )) +dev_warn (&dev->dev,"FEC_IEVENT_RFIFO_ERROR\n" ); +if (net_ratelimit () && (ievent &FEC_IEVENT_XFIFO_ERROR )) +dev_warn (&dev->dev,"FEC_IEVENT_XFIFO_ERROR\n" ); + +fec_stop (dev); +fec_hw_init (dev); +fec_start (dev); + +netif_wake_queue (dev); +return IRQ_HANDLED ; +} + +/* +* Get the current statistics. +* This may be called with the card open or closed. +*/ +static struct net_device_stats *fec_get_stats (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct net_device_stats *stats = &priv->stats; +struct mpc52xx_fec __iomem *fec = priv->fec; + +/* printk(KERN_ALERT "%s: %i, rmon_r_octets: %i, rmon_r_packets: %i, " +"ieee_r_octets_ok: %i, ieee_r_frame_ok: %i, " +"%i\n", +__func__, __LINE__, +in_be32(&fec->rmon_r_octets), in_be32(&fec->rmon_r_packets), +in_be32(&fec->ieee_r_octets_ok), in_be32(&fec->ieee_r_frame_ok), +0); +*/ + stats->rx_bytes =in_be32 (&fec->rmon_r_octets); + stats->rx_packets =in_be32 (&fec->rmon_r_packets); + stats->rx_errors =in_be32 (&fec->rmon_r_crc_align) + +in_be32 (&fec->rmon_r_undersize) + +in_be32 (&fec->rmon_r_oversize) + +in_be32 (&fec->rmon_r_frag) + +in_be32 (&fec->rmon_r_jab); + + stats->tx_bytes =in_be32 (&fec->rmon_t_octets); + stats->tx_packets =in_be32 (&fec->rmon_t_packets); + stats->tx_errors =in_be32 (&fec->rmon_t_crc_align) + +in_be32 (&fec->rmon_t_undersize) + +in_be32 (&fec->rmon_t_oversize) + +in_be32 (&fec->rmon_t_frag) + +in_be32 (&fec->rmon_t_jab); + + stats->multicast =in_be32 (&fec->rmon_r_mc_pkt); + stats->collisions =in_be32 (&fec->rmon_t_col); + +/* detailed rx_errors: */ + stats->rx_length_errors =in_be32 (&fec->rmon_r_undersize) + +in_be32 (&fec->rmon_r_oversize) + +in_be32 (&fec->rmon_r_frag) + +in_be32 (&fec->rmon_r_jab); + stats->rx_over_errors =in_be32 (&fec->r_macerr); + stats->rx_crc_errors =in_be32 (&fec->ieee_r_crc); + stats->rx_frame_errors =in_be32 (&fec->ieee_r_align); + stats->rx_fifo_errors =in_be32 (&fec->rmon_r_drop); + stats->rx_missed_errors =in_be32 (&fec->rmon_r_drop); + +/* detailed tx_errors: */ + stats->tx_aborted_errors =0 ; + stats->tx_carrier_errors =in_be32 (&fec->ieee_t_cserr); + stats->tx_fifo_errors =in_be32 (&fec->rmon_t_drop); + stats->tx_heartbeat_errors =in_be32 (&fec->ieee_t_sqe); + stats->tx_window_errors =in_be32 (&fec->ieee_t_lcol); + +return stats; +} + +/* +* Read MIB counters in order to reset them, +* then zero all the stats fields in memory +*/ +static void fec_reset_stats (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + +out_be32 (&fec->mib_control,FEC_MIB_DISABLE ); +memset_io (&fec->rmon_t_drop,0 , + (u32 )&fec->reserved10 - (u32)&fec->rmon_t_drop); +out_be32 (&fec->mib_control,0 ); + +memset (&priv->stats,0 ,sizeof (priv->stats)); +} + +/* +* Set or clear the multicast filter for this adaptor. +*/ +static void fec_set_multicast_list (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +u32 rx_control; + + rx_control =in_be32 (&fec->r_cntrl); + +if (dev->flags &IFF_PROMISC ) { + rx_control |=FEC_RCNTRL_PROM ; +out_be32 (&fec->r_cntrl, rx_control); + }else { + rx_control &= ~FEC_RCNTRL_PROM ; +out_be32 (&fec->r_cntrl, rx_control); + +if (dev->flags &IFF_ALLMULTI ) { +out_be32 (&fec->gaddr1,0xffffffff ); +out_be32 (&fec->gaddr2,0xffffffff ); + }else { +u32 crc; +int i; +struct dev_mc_list *dmi; +u32 gaddr1 =0x00000000 ; +u32 gaddr2 =0x00000000 ; + + dmi = dev->mc_list; +for (i=0 ; i<dev->mc_count; i++) { + crc =ether_crc_le (6 , dmi->dmi_addr) >>26 ; +if (crc >=32 ) + gaddr1 |=1 << (crc-32 ); +else + gaddr2 |=1 << crc; + dmi = dmi->next; + } +out_be32 (&fec->gaddr1, gaddr1); +out_be32 (&fec->gaddr2, gaddr2); + } + } +} + +static void __init fec_str2mac (char *str,unsigned char *mac) +{ +int i; +u64 val64; + + val64 =simple_strtoull (str,NULL ,16 ); + +for (i =0 ; i <6 ; i++) + mac[5 -i] = val64 >> (i*8 ); +} + +static int __init mpc52xx_fec_mac_setup (char *mac_address) +{ +fec_str2mac (mac_address, mpc52xx_fec_mac_addr); +return 0 ; +} + +/* XXX do we need this? */ +__setup ("mpc52xx-mac=" , mpc52xx_fec_mac_setup); + +/** +* fec_hw_init +* @dev: network device +* +* Setup various hardware setting, only needed once on start +*/ +static void fec_hw_init (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +int i; + +/* Whack a reset. We should wait for this. */ +out_be32 (&fec->ecntrl,FEC_ECNTRL_RESET ); +for (i =0 ; i <FEC_RESET_DELAY ; ++i) { +if ((in_be32 (&fec->ecntrl) &FEC_ECNTRL_RESET ) ==0 ) +break ; +udelay (1 ); + } +if (i ==FEC_RESET_DELAY ) +dev_err (&dev->dev,"FEC Reset timeout!\n" ); + +/* set pause to 0x20 frames */ +out_be32 (&fec->op_pause,FEC_OP_PAUSE_OPCODE |0x20 ); + +/* high service request will be deasserted when there's < 7 bytes in fifo +* low service request will be deasserted when there's < 4*7 bytes in fifo +*/ +out_be32 (&fec->rfifo_cntrl,FEC_FIFO_CNTRL_FRAME |FEC_FIFO_CNTRL_LTG_7 ); +out_be32 (&fec->tfifo_cntrl,FEC_FIFO_CNTRL_FRAME |FEC_FIFO_CNTRL_LTG_7 ); + +/* alarm when <= x bytes in FIFO */ +out_be32 (&fec->rfifo_alarm,0x0000030c ); +out_be32 (&fec->tfifo_alarm,0x00000100 ); + +/* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */ +out_be32 (&fec->x_wmrk,FEC_FIFO_WMRK_256B ); + +/* enable crc generation */ +out_be32 (&fec->xmit_fsm,FEC_XMIT_FSM_APPEND_CRC |FEC_XMIT_FSM_ENABLE_CRC ); +out_be32 (&fec->iaddr1,0x00000000 );/* No individual filter */ +out_be32 (&fec->iaddr2,0x00000000 );/* No individual filter */ + +/* set phy speed and enable MII interrupt +* this can't be done in phy driver, since it needs to be called +* before fec stuff (even on resume) */ +set_phy_speed (fec, priv->phy_speed); +out_be32 (&fec->imask,in_be32 (&fec->imask) |FEC_IMASK_MII ); +} + +/** +* fec_start +* @dev: network device +* +* This function is called to start or restart the FEC during a link +* change. This happens on fifo errors or when switching between half +* and full duplex. +*/ +static void fec_start (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +u32 rcntrl; +u32 tcntrl; +u32 tmp; + +/* clear sticky error bits */ + tmp =FEC_FIFO_STATUS_ERR |FEC_FIFO_STATUS_UF |FEC_FIFO_STATUS_OF ; +out_be32 (&fec->rfifo_status,in_be32 (&fec->rfifo_status) & tmp); +out_be32 (&fec->tfifo_status,in_be32 (&fec->tfifo_status) & tmp); + +/* FIFOs will reset on fec_enable */ +out_be32 (&fec->reset_cntrl,FEC_RESET_CNTRL_ENABLE_IS_RESET ); + +/* Set station address. */ +fec_set_paddr (dev, dev->dev_addr); + +fec_set_multicast_list (dev); + +/* set max frame len, enable flow control, select mii mode */ + rcntrl =FEC_RX_BUFFER_SIZE <<16 ;/* max frame length */ + rcntrl |=FEC_RCNTRL_FCE ; + rcntrl |=MII_RCNTL_MODE ; +if (priv->duplex ==DUPLEX_FULL ) + tcntrl =FEC_TCNTRL_FDEN ;/* FD enable */ +else { + rcntrl |=FEC_RCNTRL_DRT ;/* disable Rx on Tx (HD) */ + tcntrl =0 ; + } +out_be32 (&fec->r_cntrl, rcntrl); +out_be32 (&fec->x_cntrl, tcntrl); + +/* Clear any outstanding interrupt. */ +out_be32 (&fec->ievent,0xffffffff ); + +/* Enable interrupts we wish to service. */ +out_be32 (&fec->imask,FEC_IMASK_ENABLE ); + +/* And last, enable the transmit and receive processing. */ +out_be32 (&fec->ecntrl,FEC_ECNTRL_ETHER_EN ); +out_be32 (&fec->r_des_active,0x01000000 ); + + priv->tx_full =0 ; +} + +/** +* fec_stop +* @dev: network device +* +* stop all activity on fec and empty dma buffers +*/ +static void fec_stop (struct net_device *dev) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; +unsigned long timeout; + +out_be32 (&fec->imask,FEC_IMASK_MII );/* disable all but MII interrupt */ + +/* Disable the rx and tx tasks. */ +bcom_disable (priv->rx_dmatsk); + +/* Wait for queues to drain, but only if we're in process context */ +if (!in_interrupt ()) { + timeout = jiffies +2 *HZ ; +while (time_before (jiffies, timeout) && + (!bcom_queue_empty (priv->tx_dmatsk) || + !bcom_queue_empty (priv->rx_dmatsk))) { +set_current_state (TASK_INTERRUPTIBLE ); +schedule_timeout (HZ /10 ); + } +if (time_after_eq (jiffies, timeout)) +dev_err (&dev->dev,"queues didn't drain\n" ); + } + +bcom_disable (priv->tx_dmatsk); + +/* Stop FEC */ +out_be32 (&fec->ecntrl,in_be32 (&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN ); + +return ; +} + +static int fec_ioctl (struct net_device *dev,struct ifreq *rq,int cmd) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; + +return phy_mii_ioctl (priv->phydev, mii, cmd); +} + +/* ======================================================================== */ +/* OF Driver */ +/* ======================================================================== */ + +static int __devinit +mpc52xx_fec_probe (struct of_device *op,const struct of_device_id *match) +{ +int rv; +struct net_device *ndev; +struct fec_priv *priv =NULL ; +struct resource mem; + +phys_addr_t rx_fifo; +phys_addr_t tx_fifo; + +/* Get the ether ndev & it's private zone */ + ndev =alloc_etherdev (sizeof (struct fec_priv )); +if (!ndev) +return -ENOMEM ; + + priv =netdev_priv (ndev); + + priv->ofdev = op; + +/* Reserve FEC control zone */ + rv =of_address_to_resource (op->node,0 , &mem); +if (rv) { + printk(KERN_ERR DRIVER_NAME ": " + "Error while parsing device node resource\n" ); +return rv; + } +if ((mem.end - mem.start +1 ) !=sizeof (struct mpc52xx_fec )) { + printk(KERN_ERR DRIVER_NAME +" - invalid resource size (%lx != %x), check mpc52xx_devices.c\n" , + (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec)); +return -EINVAL ; + } + +if (!request_mem_region (mem.start,sizeof (struct mpc52xx_fec ),DRIVER_NAME )) +return -EBUSY ; + +/* Init ether ndev with what we have */ + ndev->open = fec_open; + ndev->stop = fec_close; + ndev->hard_start_xmit = fec_hard_start_xmit; + ndev->do_ioctl = fec_ioctl; + ndev->get_stats = fec_get_stats; + ndev->set_mac_address = fec_set_mac_address; + ndev->set_multicast_list = fec_set_multicast_list; + ndev->tx_timeout = fec_tx_timeout; + ndev->watchdog_timeo =FEC_WATCHDOG_TIMEOUT ; + ndev->flags &= ~IFF_RUNNING ; + ndev->base_addr = mem.start; + + priv->t_irq = priv->r_irq = ndev->irq =NO_IRQ ;/* IRQ are free for now */ + +spin_lock_init (&priv->lock); + +/* ioremap the zones */ + priv->fec =ioremap (mem.start,sizeof (struct mpc52xx_fec )); + +if (!priv->fec) { + rv = -ENOMEM ; + goto probe_error; + } + +/* Bestcomm init */ + rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec , rfifo_data); + tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec , tfifo_data); + + priv->rx_dmatsk =bcom_fec_rx_init (FEC_RX_NUM_BD , rx_fifo,FEC_RX_BUFFER_SIZE ); + priv->tx_dmatsk =bcom_fec_tx_init (FEC_TX_NUM_BD , tx_fifo); + +if (!priv->rx_dmatsk || !priv->tx_dmatsk) { + printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" ); + rv = -ENOMEM ; + goto probe_error; + } + +/* Get the IRQ we need one by one */ +/* Control */ + ndev->irq =irq_of_parse_and_map (op->node,0 ); + +/* RX */ + priv->r_irq =bcom_get_task_irq (priv->rx_dmatsk); + +/* TX */ + priv->t_irq =bcom_get_task_irq (priv->tx_dmatsk); + +/* MAC address init */ +if (memcmp (mpc52xx_fec_mac_addr, null_mac,6 ) !=0 ) +memcpy (ndev->dev_addr, mpc52xx_fec_mac_addr,6 ); +else +fec_get_paddr (ndev, ndev->dev_addr); + +/* Phy speed */ + priv->phy_speed = ((mpc52xx_find_ipb_freq (op->node) >>20 ) /5 ) <<1 ; + + priv->msg_enable = (NETIF_MSG_IFUP <<1 ) -1 ; + priv->duplex =DUPLEX_HALF ; + +/* Hardware init */ +fec_hw_init (ndev); + +fec_reset_stats (ndev); + +/* Register the new network device */ + rv =register_netdev (ndev); +if (rv <0 ) + goto probe_error; + +/* We're done ! */ +dev_set_drvdata (&op->dev, ndev); + +return 0 ; + + +/* Error handling - free everything that might be allocated */ +probe_error: + +irq_dispose_mapping (ndev->irq); + +if (priv->rx_dmatsk) +bcom_fec_rx_release (priv->rx_dmatsk); +if (priv->tx_dmatsk) +bcom_fec_tx_release (priv->tx_dmatsk); + +if (priv->fec) +iounmap (priv->fec); + +release_mem_region (mem.start,sizeof (struct mpc52xx_fec )); + +free_netdev (ndev); + +return rv; +} + +static int +mpc52xx_fec_remove (struct of_device *op) +{ +struct net_device *ndev; +struct fec_priv *priv; + + ndev =dev_get_drvdata (&op->dev); +if (!ndev) +return 0 ; + priv =netdev_priv (ndev); + +unregister_netdev (ndev); + +irq_dispose_mapping (ndev->irq); + +bcom_fec_rx_release (priv->rx_dmatsk); +bcom_fec_tx_release (priv->tx_dmatsk); + +iounmap (priv->fec); + +release_mem_region (ndev->base_addr,sizeof (struct mpc52xx_fec )); + +free_netdev (ndev); + +dev_set_drvdata (&op->dev,NULL ); +return 0 ; +} + +#ifdef CONFIG_PM +static int mpc52xx_fec_of_suspend (struct of_device *op,pm_message_t state) +{ +struct net_device *dev =dev_get_drvdata (&op->dev); + +if (netif_running (dev)) +fec_close (dev); + +return 0 ; +} + +static int mpc52xx_fec_of_resume (struct of_device *op) +{ +struct net_device *dev =dev_get_drvdata (&op->dev); + +fec_hw_init (dev); +fec_reset_stats (dev); + +if (netif_running (dev)) +fec_open (dev); + +return 0 ; +} +#endif + +static struct of_device_id mpc52xx_fec_match[] = { + { + .type ="network" , + .compatible ="mpc5200-fec" , + }, + { } +}; + +MODULE_DEVICE_TABLE (of, mpc52xx_fec_match); + +static struct of_platform_driver mpc52xx_fec_driver = { + .owner =THIS_MODULE , + .name =DRIVER_NAME , + .match_table = mpc52xx_fec_match, + .probe = mpc52xx_fec_probe, + .remove = mpc52xx_fec_remove, +#ifdef CONFIG_PM + .suspend = mpc52xx_fec_of_suspend, + .resume = mpc52xx_fec_of_resume, +#endif +}; +
drivers/net/fec_mpc52xx/fec.c line 980
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10
-0+ +/* ======================================================================== */ +/* Module */ +/* ======================================================================== */ + +static int __init +mpc52xx_fec_init (void ) +{ +int ret; +if ((ret =fec_mdio_init ())) {
Why not:
int ret = fec_mdio_init();
if (ret) {Less parenthesis, looks more clear
Quoted 711 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +22
-0+printk (KERN_ERR "%s: %i fec_mdio_init failed\n" , __func__, __LINE__); +return ret; + } + +return of_register_platform_driver (&mpc52xx_fec_driver); +} + +static void __exit +mpc52xx_fec_exit (void ) +{ +of_unregister_platform_driver (&mpc52xx_fec_driver); +fec_mdio_exit (); +} + + +module_init (mpc52xx_fec_init); +module_exit (mpc52xx_fec_exit); + +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Dale Farnsworth" ); +MODULE_DESCRIPTION ("Ethernet driver for the Freescale MPC52xx FEC" ); +diff -pruN
dummy/fec.h./drivers/net/fec_mpc52xx/fec.hdrivers/net/fec_mpc52xx/fec.h renamed from fec.h +299
-0@@ -0,0 +1,299 @@ +/* +* drivers/net/fec_mpc52xx/fec.h +* +* Driver for the MPC5200 Fast Ethernet Controller +* +* Author: Dale Farnsworth <[email protected]> +* +* 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under +* the terms of the GNU General Public License version 2. This program +* is licensed "as is" without any warranty of any kind, whether express +* or implied. +*/ + +#ifndef __DRIVERS_NET_MPC52XX_FEC_H__ +#define __DRIVERS_NET_MPC52XX_FEC_H__ + +#include <linux/mii.h> // XXX, still needed? +#include <linux/phy.h> + +/* Tunable constant */ +/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */ +#define FEC_RX_BUFFER_SIZE 1522/* max receive packet size */ +#define FEC_RX_NUM_BD 64 +#define FEC_TX_NUM_BD 64 + +#define FEC_RESET_DELAY 50/* uS */ + +#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000) + +struct fec_priv { +int duplex; +int tx_full; +int r_irq; +int t_irq; +struct mpc52xx_fec __iomem *fec; +struct bcom_task *rx_dmatsk; +struct bcom_task *tx_dmatsk; +spinlock_t lock; +struct net_device_stats stats; +int msg_enable; +#ifdef CONFIG_FEC_MPC52xx_MDIO +uint phy_speed; + +struct phy_device *phydev; +enum phy_state link; +int speed; + +struct of_device *ofdev; +#endif /* CONFIG_FEC_MPC52xx_MDIO */ +}; + + +/* ======================================================================== */ +/* Hardware register sets & bits */ +/* ======================================================================== */ + +struct mpc52xx_fec { +u32 fec_id;/* FEC + 0x000 */ +u32 ievent;/* FEC + 0x004 */ +u32 imask;/* FEC + 0x008 */ + +u32 reserved0[1 ];/* FEC + 0x00C */ +u32 r_des_active;/* FEC + 0x010 */ +u32 x_des_active;/* FEC + 0x014 */ +u32 r_des_active_cl;/* FEC + 0x018 */ +u32 x_des_active_cl;/* FEC + 0x01C */ +u32 ivent_set;/* FEC + 0x020 */ +u32 ecntrl;/* FEC + 0x024 */ + +u32 reserved1[6 ];/* FEC + 0x028-03C */ +u32 mii_data;/* FEC + 0x040 */ +u32 mii_speed;/* FEC + 0x044 */ +u32 mii_status;/* FEC + 0x048 */ + +u32 reserved2[5 ];/* FEC + 0x04C-05C */ +u32 mib_data;/* FEC + 0x060 */ +u32 mib_control;/* FEC + 0x064 */ + +u32 reserved3[6 ];/* FEC + 0x068-7C */ +u32 r_activate;/* FEC + 0x080 */ +u32 r_cntrl;/* FEC + 0x084 */ +u32 r_hash;/* FEC + 0x088 */ +u32 r_data;/* FEC + 0x08C */ +u32 ar_done;/* FEC + 0x090 */ +u32 r_test;/* FEC + 0x094 */ +u32 r_mib;/* FEC + 0x098 */ +u32 r_da_low;/* FEC + 0x09C */ +u32 r_da_high;/* FEC + 0x0A0 */ + +u32 reserved4[7 ];/* FEC + 0x0A4-0BC */ +u32 x_activate;/* FEC + 0x0C0 */ +u32 x_cntrl;/* FEC + 0x0C4 */ +u32 backoff;/* FEC + 0x0C8 */ +u32 x_data;/* FEC + 0x0CC */ +u32 x_status;/* FEC + 0x0D0 */ +u32 x_mib;/* FEC + 0x0D4 */ +u32 x_test;/* FEC + 0x0D8 */ +u32 fdxfc_da1;/* FEC + 0x0DC */ +u32 fdxfc_da2;/* FEC + 0x0E0 */ +u32 paddr1;/* FEC + 0x0E4 */ +u32 paddr2;/* FEC + 0x0E8 */ +u32 op_pause;/* FEC + 0x0EC */ + +u32 reserved5[4 ];/* FEC + 0x0F0-0FC */ +u32 instr_reg;/* FEC + 0x100 */ +u32 context_reg;/* FEC + 0x104 */ +u32 test_cntrl;/* FEC + 0x108 */ +u32 acc_reg;/* FEC + 0x10C */ +u32 ones;/* FEC + 0x110 */ +u32 zeros;/* FEC + 0x114 */ +u32 iaddr1;/* FEC + 0x118 */ +u32 iaddr2;/* FEC + 0x11C */ +u32 gaddr1;/* FEC + 0x120 */ +u32 gaddr2;/* FEC + 0x124 */ +u32 random;/* FEC + 0x128 */ +u32 rand1;/* FEC + 0x12C */ +u32 tmp;/* FEC + 0x130 */ + +u32 reserved6[3 ];/* FEC + 0x134-13C */ +u32 fifo_id;/* FEC + 0x140 */ +u32 x_wmrk;/* FEC + 0x144 */ +u32 fcntrl;/* FEC + 0x148 */ +u32 r_bound;/* FEC + 0x14C */ +u32 r_fstart;/* FEC + 0x150 */ +u32 r_count;/* FEC + 0x154 */ +u32 r_lag;/* FEC + 0x158 */ +u32 r_read;/* FEC + 0x15C */ +u32 r_write;/* FEC + 0x160 */ +u32 x_count;/* FEC + 0x164 */ +u32 x_lag;/* FEC + 0x168 */ +u32 x_retry;/* FEC + 0x16C */ +u32 x_write;/* FEC + 0x170 */ +u32 x_read;/* FEC + 0x174 */ + +u32 reserved7[2 ];/* FEC + 0x178-17C */ +u32 fm_cntrl;/* FEC + 0x180 */ +u32 rfifo_data;/* FEC + 0x184 */ +u32 rfifo_status;/* FEC + 0x188 */ +u32 rfifo_cntrl;/* FEC + 0x18C */ +u32 rfifo_lrf_ptr;/* FEC + 0x190 */ +u32 rfifo_lwf_ptr;/* FEC + 0x194 */ +u32 rfifo_alarm;/* FEC + 0x198 */ +u32 rfifo_rdptr;/* FEC + 0x19C */ +u32 rfifo_wrptr;/* FEC + 0x1A0 */ +u32 tfifo_data;/* FEC + 0x1A4 */ +u32 tfifo_status;/* FEC + 0x1A8 */ +u32 tfifo_cntrl;/* FEC + 0x1AC */ +u32 tfifo_lrf_ptr;/* FEC + 0x1B0 */ +u32 tfifo_lwf_ptr;/* FEC + 0x1B4 */ +u32 tfifo_alarm;/* FEC + 0x1B8 */ +u32 tfifo_rdptr;/* FEC + 0x1BC */ +u32 tfifo_wrptr;/* FEC + 0x1C0 */ + +u32 reset_cntrl;/* FEC + 0x1C4 */ +u32 xmit_fsm;/* FEC + 0x1C8 */ + +u32 reserved8[3 ];/* FEC + 0x1CC-1D4 */ +u32 rdes_data0;/* FEC + 0x1D8 */ +u32 rdes_data1;/* FEC + 0x1DC */ +u32 r_length;/* FEC + 0x1E0 */ +u32 x_length;/* FEC + 0x1E4 */ +u32 x_addr;/* FEC + 0x1E8 */ +u32 cdes_data;/* FEC + 0x1EC */ +u32 status;/* FEC + 0x1F0 */ +u32 dma_control;/* FEC + 0x1F4 */ +u32 des_cmnd;/* FEC + 0x1F8 */ +u32 data;/* FEC + 0x1FC */ + +u32 rmon_t_drop;/* FEC + 0x200 */ +u32 rmon_t_packets;/* FEC + 0x204 */ +u32 rmon_t_bc_pkt;/* FEC + 0x208 */ +u32 rmon_t_mc_pkt;/* FEC + 0x20C */ +u32 rmon_t_crc_align;/* FEC + 0x210 */ +u32 rmon_t_undersize;/* FEC + 0x214 */ +u32 rmon_t_oversize;/* FEC + 0x218 */ +u32 rmon_t_frag;/* FEC + 0x21C */ +u32 rmon_t_jab;/* FEC + 0x220 */ +u32 rmon_t_col;/* FEC + 0x224 */ +u32 rmon_t_p64;/* FEC + 0x228 */ +u32 rmon_t_p65to127;/* FEC + 0x22C */ +u32 rmon_t_p128to255;/* FEC + 0x230 */ +u32 rmon_t_p256to511;/* FEC + 0x234 */ +u32 rmon_t_p512to1023;/* FEC + 0x238 */ +u32 rmon_t_p1024to2047;/* FEC + 0x23C */ +u32 rmon_t_p_gte2048;/* FEC + 0x240 */ +u32 rmon_t_octets;/* FEC + 0x244 */ +u32 ieee_t_drop;/* FEC + 0x248 */ +u32 ieee_t_frame_ok;/* FEC + 0x24C */ +u32 ieee_t_1col;/* FEC + 0x250 */ +u32 ieee_t_mcol;/* FEC + 0x254 */ +u32 ieee_t_def;/* FEC + 0x258 */ +u32 ieee_t_lcol;/* FEC + 0x25C */ +u32 ieee_t_excol;/* FEC + 0x260 */ +u32 ieee_t_macerr;/* FEC + 0x264 */ +u32 ieee_t_cserr;/* FEC + 0x268 */ +u32 ieee_t_sqe;/* FEC + 0x26C */ +u32 t_fdxfc;/* FEC + 0x270 */ +u32 ieee_t_octets_ok;/* FEC + 0x274 */ + +u32 reserved9[2 ];/* FEC + 0x278-27C */ +u32 rmon_r_drop;/* FEC + 0x280 */ +u32 rmon_r_packets;/* FEC + 0x284 */ +u32 rmon_r_bc_pkt;/* FEC + 0x288 */ +u32 rmon_r_mc_pkt;/* FEC + 0x28C */ +u32 rmon_r_crc_align;/* FEC + 0x290 */ +u32 rmon_r_undersize;/* FEC + 0x294 */ +u32 rmon_r_oversize;/* FEC + 0x298 */ +u32 rmon_r_frag;/* FEC + 0x29C */ +u32 rmon_r_jab;/* FEC + 0x2A0 */ + +u32 rmon_r_resvd_0;/* FEC + 0x2A4 */ + +u32 rmon_r_p64;/* FEC + 0x2A8 */ +u32 rmon_r_p65to127;/* FEC + 0x2AC */ +u32 rmon_r_p128to255;/* FEC + 0x2B0 */ +u32 rmon_r_p256to511;/* FEC + 0x2B4 */ +u32 rmon_r_p512to1023;/* FEC + 0x2B8 */ +u32 rmon_r_p1024to2047;/* FEC + 0x2BC */ +u32 rmon_r_p_gte2048;/* FEC + 0x2C0 */ +u32 rmon_r_octets;/* FEC + 0x2C4 */ +u32 ieee_r_drop;/* FEC + 0x2C8 */ +u32 ieee_r_frame_ok;/* FEC + 0x2CC */ +u32 ieee_r_crc;/* FEC + 0x2D0 */ +u32 ieee_r_align;/* FEC + 0x2D4 */ +u32 r_macerr;/* FEC + 0x2D8 */ +u32 r_fdxfc;/* FEC + 0x2DC */ +u32 ieee_r_octets_ok;/* FEC + 0x2E0 */ + +u32 reserved10[7 ];/* FEC + 0x2E4-2FC */ + +u32 reserved11[64 ];/* FEC + 0x300-3FF */ +}; + +#define FEC_MIB_DISABLE 0x80000000 + +#define FEC_IEVENT_HBERR 0x80000000 +#define FEC_IEVENT_BABR 0x40000000 +#define FEC_IEVENT_BABT 0x20000000 +#define FEC_IEVENT_GRA 0x10000000 +#define FEC_IEVENT_TFINT 0x08000000 +#define FEC_IEVENT_MII 0x00800000 +#define FEC_IEVENT_LATE_COL 0x00200000 +#define FEC_IEVENT_COL_RETRY_LIM 0x00100000 +#define FEC_IEVENT_XFIFO_UN 0x00080000 +#define FEC_IEVENT_XFIFO_ERROR 0x00040000 +#define FEC_IEVENT_RFIFO_ERROR 0x00020000 + +#define FEC_IMASK_HBERR 0x80000000 +#define FEC_IMASK_BABR 0x40000000 +#define FEC_IMASK_BABT 0x20000000 +#define FEC_IMASK_GRA 0x10000000 +#define FEC_IMASK_MII 0x00800000 +#define FEC_IMASK_LATE_COL 0x00200000 +#define FEC_IMASK_COL_RETRY_LIM 0x00100000 +#define FEC_IMASK_XFIFO_UN 0x00080000 +#define FEC_IMASK_XFIFO_ERROR 0x00040000 +#define FEC_IMASK_RFIFO_ERROR 0x00020000 + +#define FEC_RCNTRL_MAX_FL_SHIFT 16 +#define FEC_RCNTRL_LOOP 0x01 +#define FEC_RCNTRL_DRT 0x02 +#define FEC_RCNTRL_MII_MODE 0x04 +#define FEC_RCNTRL_PROM 0x08 +#define FEC_RCNTRL_BC_REJ 0x10 +#define FEC_RCNTRL_FCE 0x20 + +#define FEC_TCNTRL_GTS 0x00000001 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_TFC_PAUSE 0x00000008 +#define FEC_TCNTRL_RFC_PAUSE 0x00000010 + +#define FEC_ECNTRL_RESET 0x00000001 +#define FEC_ECNTRL_ETHER_EN 0x00000002 + +#define FEC_PADDR2_TYPE 0x8808 + +#define FEC_OP_PAUSE_OPCODE 0x00010000 + +#define FEC_FIFO_WMRK_256B 0x3 + +#define FEC_FIFO_STATUS_ERR 0x00400000 +#define FEC_FIFO_STATUS_UF 0x00200000 +#define FEC_FIFO_STATUS_OF 0x00100000 + +#define FEC_FIFO_CNTRL_FRAME 0x08000000 +#define FEC_FIFO_CNTRL_LTG_7 0x07000000 + +#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000 +#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000 + +#define FEC_XMIT_FSM_APPEND_CRC 0x02000000 +#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000 + + +int __init fec_mdio_init (void ); +void __exit fec_mdio_exit(void); + +#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */ diff -pruN
dummy/fec_phy.c./drivers/net/fec_mpc52xx/fec_phy.cdrivers/net/fec_mpc52xx/fec_phy.c renamed from fec_phy.c +229
-0@@ -0,0 +1,229 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/phy.h> +#include <asm/io.h> +#include <asm/mpc52xx.h> +#include <asm/of_platform.h> +#include "fec_phy.h" +#include "fec.h" + +struct fec_mdio_priv { +int completed; +wait_queue_head_t wq; +struct mpc52xx_fec __iomem *regs; +int irq; +}; + +static int fec_mdio_read (struct mii_bus *bus,int phy_id,int reg) +{ +struct fec_mdio_priv *priv = bus->priv; +int tries =100 ; + +u32 request =FEC_MII_READ_FRAME ; + request |= (phy_id <<FEC_MII_DATA_PA_SHIFT ) &FEC_MII_DATA_PA_MSK ; + request |= (reg <<FEC_MII_DATA_RA_SHIFT ) &FEC_MII_DATA_RA_MSK ; + +out_be32 (&priv->regs->mii_data, request); + +/* wait for it to finish, this takes about 23 us on lite5200b */ +while (priv->completed ==0 && tries--) +udelay (5 ); + + priv->completed =0 ; + +if (tries ==0 ) +return -ETIMEDOUT ; + +return in_be32 (&priv->regs->mii_data) &FEC_MII_DATA_DATAMSK ; +} + +static int fec_mdio_write (struct mii_bus *bus,int phy_id,int reg,u16 data) +{ +struct fec_mdio_priv *priv = bus->priv; +u32 value = data; +int tries =100 ; + + value |=FEC_MII_WRITE_FRAME ; + value |= (phy_id <<FEC_MII_DATA_PA_SHIFT ) &FEC_MII_DATA_PA_MSK ; + value |= (reg <<FEC_MII_DATA_RA_SHIFT ) &FEC_MII_DATA_RA_MSK ; + +out_be32 (&priv->regs->mii_data, value); + +/* wait for request to finish */ +while (priv->completed ==0 && tries--) +udelay (5 ); + + priv->completed =0 ; + +if (tries ==0 ) +return -ETIMEDOUT ; + +return 0 ; +} + +static irqreturn_t fec_mdio_interrupt (int irq,void *dev_id) +{ +struct fec_mdio_priv *priv = dev_id; +struct mpc52xx_fec __iomem *fec; +int ievent; + + fec = priv->regs; + ievent =in_be32 (&fec->ievent); + + ievent &=FEC_IEVENT_MII ; +if (!ievent) +return IRQ_NONE ; + +out_be32 (&fec->ievent, ievent); + + priv->completed =1 ; +wake_up (&priv->wq); + +return IRQ_HANDLED ; +} + +static int fec_mdio_probe (struct of_device *of,const struct of_device_id *match) +{ +struct device *dev = &of->dev; +struct device_node *np = of->node; +struct device_node *child =NULL ; +struct mii_bus *bus; +struct fec_mdio_priv *priv; +struct resource res = {}; +int err; +int i; + + bus =kzalloc (sizeof (*bus),GFP_KERNEL ); +if (bus ==NULL ) +return -ENOMEM ; + priv =kzalloc (sizeof (*priv),GFP_KERNEL ); +if (priv ==NULL ) { + err = -ENOMEM ; + goto out_free; + } + + bus->name ="mpc52xx MII bus" ; + bus->read = fec_mdio_read; + bus->write = fec_mdio_write; + +/* setup irqs */ + bus->irq =kcalloc (sizeof (bus->irq[0 ]),PHY_MAX_ADDR ,GFP_KERNEL ); +if (bus->irq ==NULL ) { + err = -ENOMEM ; + goto out_free; + } +for (i=0 ; i<PHY_MAX_ADDR ; i++) + bus->irq[i] =PHY_POLL ; + +while ((child =of_get_next_child (np, child)) !=NULL ) { +int irq =irq_of_parse_and_map (child,0 ); +if (irq !=NO_IRQ ) { +const u32 *id =of_get_property (child,"reg" ,NULL ); + bus->irq[*id] = irq; + } + } + +/* setup registers */ + err =of_address_to_resource (np,0 , &res); +if (err) + goto out_free; + priv->regs =ioremap (res.start, res.end - res.start +1 ); +if (priv->regs ==NULL ) { + err = -ENOMEM ; + goto out_free; + } + + priv->irq =irq_of_parse_and_map (np,0 ); + err =request_irq (priv->irq, &fec_mdio_interrupt,IRQF_DISABLED |IRQF_SHARED , +"fec_mdio" , priv); +if (err) { +printk (KERN_ERR "%s: interrupt request failed with %i\n" , __func__, err); + goto out_unmap; + } + + bus->id = res.start; + bus->priv = priv; + + bus->dev = dev; +dev_set_drvdata (dev, bus); + +init_waitqueue_head (&priv->wq); + +/* set MII speed */ +out_be32 (&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq (of->node) >>20 ) /5 ) <<1 ); + +/* enable MII interrupt */ +out_be32 (&priv->regs->imask,in_be32 (&priv->regs->imask) |FEC_IMASK_MII ); + + err =mdiobus_register (bus); +if (err) + goto out_free_irq; + +return 0 ; + + out_free_irq: +free_irq (priv->irq, dev); +irq_dispose_mapping (priv->irq); + out_unmap: +iounmap (priv->regs); + out_free: +for (i=0 ; i<PHY_MAX_ADDR ; i++) +if (bus->irq[i]) +irq_dispose_mapping (bus->irq[i]); +kfree (bus->irq); +kfree (priv); +kfree (bus); + +return err; +} + +static int fec_mdio_remove (struct of_device *of) +{ +struct device *dev = &of->dev; +struct mii_bus *bus =dev_get_drvdata (dev); +struct fec_mdio_priv *priv = bus->priv; +int i; + +mdiobus_unregister (bus); +dev_set_drvdata (dev,NULL ); + +free_irq (priv->irq, dev); +irq_dispose_mapping (priv->irq); +iounmap (priv->regs); +for (i=0 ; i<PHY_MAX_ADDR ; i++) +if (bus->irq[i]) +irq_dispose_mapping (bus->irq[i]); +kfree (priv); +kfree (bus->irq); +kfree (bus); + +return 0 ; +} + + +static struct of_device_id fec_mdio_match[] = { + { + .type ="mdio" , + .compatible ="mpc5200b-fec-phy" , + }, + {}, +}; + +static struct of_platform_driver fec_mdio_driver = { + .name ="mpc5200b-fec-phy" , + .probe = fec_mdio_probe, + .remove = fec_mdio_remove, + .match_table = fec_mdio_match, +}; + + +int __init fec_mdio_init (void ) +{ +return of_register_platform_driver (&fec_mdio_driver); +} + +void __exit fec_mdio_exit(void) +{ +of_unregister_platform_driver (&fec_mdio_driver); +}diff -pruN
dummy/fec_phy.h./drivers/net/fec_mpc52xx/fec_phy.hdrivers/net/fec_mpc52xx/fec_phy.h renamed from fec_phy.h +49
-0@@ -0,0 +1,49 @@ +/* +* arch/ppc/52xx_io/fec_phy.h +* +* Driver for the MPC5200 Fast Ethernet Controller +* Based heavily on the MII support for the MPC8xx by Dan Malek +* +* Author: Dale Farnsworth <[email protected]> +* +* 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under +* the terms of the GNU General Public License version 2. This program +* is licensed "as is" without any warranty of any kind, whether express +* or implied. +*/ + +#define FEC_IMASK_ALL (FEC_IMASK_HBERR | FEC_IMASK_BABR | \ + FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_MII | \ + FEC_IMASK_LATE_COL | FEC_IMASK_COL_RETRY_LIM | \ + FEC_IMASK_XFIFO_UN | FEC_IMASK_XFIFO_ERROR | \ + FEC_IMASK_RFIFO_ERROR) + +#ifdef CONFIG_FEC_MPC52xx_MDIO +#define MII_RCNTL_MODE FEC_RCNTRL_MII_MODE +#define FEC_IMASK_ENABLE FEC_IMASK_ALL +#define set_phy_speed (fec, s) out_be32(&fec->mii_speed, s) +#else +#define MII_RCNTL_MODE 0 +#define FEC_IMASK_ENABLE (FEC_IMASK_ALL & ~FEC_IMASK_MII) +#define set_phy_speed (fec, s) do { } while (0) +#define fec_mii_start (dev) do { } while (0) +#define fec_mii (dev) printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n") +#define fec_mii_init (dev) do { } while (0) +#define fec_mii_suspend (dev) do { } while (0) +#define fec_mii_resume (dev) do { } while (0) +#endif /* CONFIG_FEC_MPC52xx_MDIO */ + +/* MII-related definitions */ +#define FEC_MII_DATA_ST 0x40000000/* Start frame */ +#define FEC_MII_DATA_OP_RD 0x20000000/* Perform read */ +#define FEC_MII_DATA_OP_WR 0x10000000/* Perform write */ +#define FEC_MII_DATA_PA_MSK 0x0f800000/* PHY Address mask */ +#define FEC_MII_DATA_RA_MSK 0x007c0000/* PHY Register mask */ +#define FEC_MII_DATA_TA 0x00020000/* Turnaround */ +#define FEC_MII_DATA_DATAMSK 0x0000ffff/* PHY data mask */ + +#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA) +#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA) + +#define FEC_MII_DATA_RA_SHIFT 0x12/* MII reg addr bits */ +#define FEC_MII_DATA_PA_SHIFT 0x17/* MII PHY addr bits */ diff -pruN dummy/Kconfig
./drivers/net/fec_mpc52xx/Kconfigdrivers/net/fec_mpc52xx/Kconfig renamed from Kconfig +24
-0@@ -0,0 +1,24 @@ +menu "MPC5200 Networking Options" + depends PPC_MPC52xx && NET_ETHERNET + +config FEC_MPC52xx + tristate "FEC Ethernet" + depends on NET_ETHERNET + select PPC_BESTCOMM + select PPC_BESTCOMM_FEC + select CRC32 + ---help--- + This option enables support for the MPC5200's on-chip + Fast Ethernet Controller + +config USE_MDIO + bool "Use external Ethernet MII PHY" + select MII + depends FEC_MPC52xx + ---help--- + The MPC5200's FEC can connect to the Ethernet either with + an external MII PHY chip or 10 Mbps 7-wire interface + (Motorola? industry standard). + If your board uses an external PHY, say y, else n. + +endmenudiff -pruN dummy/Makefile
./drivers/net/fec_mpc52xx/Makefiledrivers/net/fec_mpc52xx/Makefile renamed from Makefile +7
-0@@ -0,0 +1,7 @@ +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o + +fec_mpc52xx-objs := fec.o + +ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) +fec_mpc52xx-objs += fec_phy.o +endifIndex:
work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================arch/powerpc/boot/dts/lite5200b.dts +17
-1@@ -365,10 +365,26 @@ ethernet@3000 { device_type = "network"; compatible = "mpc5200b-fec\0mpc5200-fec"; - reg = <3000 800>; + reg = <3000 400>; mac-address = [ 02 03 04 05 06 07 ]; // Bad! interrupts = <2 5 0>; interrupt-parent = <&mpc5200_pic>; + phy-handle = <&phy0>; + }; + + mdio@3000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio"; + compatible = "mpc5200b-fec-phy"; + reg = <3000 400>; // fec range, since we need to setup fec interrupts + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co. + interrupt-parent = <&mpc5200_pic>; + + phy0:ethernet-phy@0 { + device_type = "ethernet-phy"; + reg = <0>; + }; }; ata@3a00 {Index:
work-powerpc.git/arch/powerpc/sysdev/bestcomm/fec.h
===================================================================arch/powerpc/sysdev/bestcomm/fec.h +14
-1@@ -22,6 +22,20 @@ struct bcom_fec_bd {#define BCOM_FEC_TX_BD_TFD 0x08000000ul/* transmit frame done */ #define BCOM_FEC_TX_BD_INT 0x04000000ul/* interrupt */ +#define BCOM_FEC_TX_BD_TC 0x04000000ul/* transmit CRC XXX same as ^? */ +#define BCOM_FEC_TX_BD_ABC 0x02000000ul/* append bad CRC */ + +#define BCOM_FEC_RX_BD_L 0x08000000ul/* buffer is last in frame */ +#define BCOM_FEC_RX_BD_BC 0x00800000ul/* DA is broadcast */ +#define BCOM_FEC_RX_BD_MC 0x00400000ul/* DA is multicast and not broadcast */ +#define BCOM_FEC_RX_BD_LG 0x00200000ul/* Rx frame length violation */ +#define BCOM_FEC_RX_BD_NO 0x00100000ul/* Rx non-octet aligned frame */ +#define BCOM_FEC_RX_BD_CR 0x00040000ul/* Rx CRC error */ +#define BCOM_FEC_RX_BD_OV 0x00020000ul/* overrun */ +#define BCOM_FEC_RX_BD_TR 0x00010000ul/* Rx frame truncated */ +#define BCOM_FEC_RX_BD_LEN_MASK 0x000007fful/* mask for length of received frame */ +#define BCOM_FEC_RX_BD_ERRORS (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \ + BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR) extern struct bcom_task * -To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 4 lines · Arnaldo Carvalho de Melo
Em Fri, Aug 10, 2007 at 11:51:53AM +0200, Domen Puncer escreveu:
Quoted 1 line
+static u8 null_mac[6];
const
OK.
...
Quoted 9 lines
drivers/net/fec_mpc52xx/fec.c line 80
Quoted 7 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +7
-0+static void fec_set_paddr (struct net_device *dev,u8 *mac) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + +out_be32 (&fec->paddr1, *(u32 *)(&mac[0 ])); +out_be32 (&fec->paddr2, (*(u16 *)(&mac[4 ]) <<16 ) |FEC_PADDR2_TYPE );spaces after the types on casts to pointers
I assume you mean: out_be32(&fec->paddr1, *(u32 *)(&mac[0]));
Quoted 12 lines
drivers/net/fec_mpc52xx/fec.c line 89
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +9
-0+} + +static void fec_get_paddr (struct net_device *dev,u8 *mac) +{ +struct fec_priv *priv =netdev_priv (dev); +struct mpc52xx_fec __iomem *fec = priv->fec; + + *(u32 *)(&mac[0 ]) =in_be32 (&fec->paddr1); + *(u16 *)(&mac[4 ]) =in_be32 (&fec->paddr2) >>16 ;ditto
OK.
Quoted 8 lines
drivers/net/fec_mpc52xx/fec.c line 94
Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5
-0+} + +static int fec_set_mac_address (struct net_device *dev,void *addr) +{ +struct sockaddr *sock = (struct sockaddr *)addr;no need for a cast, addr is a void pointer
Right, missed this one.
Quoted 8 lines
drivers/net/fec_mpc52xx/fec.c line 99
Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5
-0+ +memcpy (dev->dev_addr, sock->sa_data, dev->addr_len); + +fec_set_paddr (dev, sock->sa_data); +return 0 ;Why always return 0? make it void
Because struct net_device->set_mac_address's prototype is like that.
Quoted 15 lines
Quoted 15 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +14
-0+} + +static void fec_free_rx_buffers (struct bcom_task *s) +{ +struct sk_buff *skb; + +while (!bcom_queue_empty (s)) { + skb =bcom_retrieve_buffer (s,NULL ,NULL ); +kfree_skb (skb); + } +} + +static int fec_alloc_rx_buffers (struct bcom_task *rxtsk) +{
Quoted 8 lines
drivers/net/fec_mpc52xx/fec.c line 119
Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +6
-0+while (!bcom_queue_full (rxtsk)) { +struct sk_buff *skb; +struct bcom_fec_bd *bd; + + skb =dev_alloc_skb (FEC_RX_BUFFER_SIZE ); +if (skb ==0 )Test against NULL
Right. I also fixed other stuff sparse reports.
Quoted 3 lines
Quoted 3 lines
(quoted diff) +2
-0+ return -EAGAIN; +
...
Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c line 173
Quoted 4 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +4
-0+ +if (new_state &&netif_msg_link (priv)) { +phy_print_status (phydev); + }No need for {}, this if has only one statement
OK.
...
Quoted 8 lines
drivers/net/fec_mpc52xx/fec.c line 980
Quoted 5 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5
-0+static int __init +mpc52xx_fec_init (void ) +{ +int ret; +if ((ret =fec_mdio_init ())) {Why not:
Quoted 4 lines
int ret = fec_mdio_init(); if (ret) {Less parenthesis, looks more clear
I prefer it like that too.
Thanks Arnaldo!
Any other comments on code functionality, design?
Domen
Hi!
Quoted 8 lines · Domen Puncer
Index:
work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================arch/powerpc/boot/dts/lite5200b.dts +4
-0+ mdio@3000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio";
arch/powerpc/boot/dts/lite5200b.dts line 388
Quoted 10 lines
arch/powerpc/boot/dts/lite5200b.dts +9
-0+ compatible = "mpc5200b-fec-phy"; + reg = <3000 400>; // fec range, since we need to setup fec interrupts + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co. + interrupt-parent = <&mpc5200_pic>; + + phy0:ethernet-phy@0 { + device_type = "ethernet-phy"; + reg = <0>; + }; };
I am struggling with this part on Efika.
I would like to add this to the device tree from fixup_device_tree_efika() (arch/powerpc/kernel/prom_init.c).
AFAICS client-services doesn't offer anything like new-device, so I guess "interpret" or "call-method" will have to be used.
I have read some docs, but I'm still wandering in the dark. Can I please get an example?
Pretty please with a cherry on top?
Domen
Domen,
Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter Linux with more fixups. The Efika PHY isn't going to change to something else and it's a bog standard no-frills MII PHY anyway.
I think it is a distinction that the OF docs forgot to make, that the client interface is *all those Forth words* and not just the 6 or 7 distinct, special callable functions like claim (they exist because of the simple fact that claiming memory shouldn't involve claiming memory and such other paradoxes) and call-method. Call-method is a perfectly valid way of doing things.
But, I'd really recommend you please think of a different way.. if you want to spec out a device tree entry for it I'll update my script which I am probably going to stick as an 'official' Genesi support file in the next week.
If you insist on using prom_init and fixups, yaboot has the best examples of call-method and interpret, both readable and fairly easily available.
Signature · 2 lines
Matt Sealey <[email protected]> Genesi, Manager, Developer Relations
Quoted 35 lines · Domen Puncer
Hi!
Quoted 8 lines · Domen Puncer
Index:
work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================arch/powerpc/boot/dts/lite5200b.dts +4
-0+ mdio@3000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio";arch/powerpc/boot/dts/lite5200b.dts line 388
Quoted 10 lines
arch/powerpc/boot/dts/lite5200b.dts +9
-0+ compatible = "mpc5200b-fec-phy"; + reg = <3000 400>; // fec range, since we need to setup fec interrupts + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co. + interrupt-parent = <&mpc5200_pic>; + + phy0:ethernet-phy@0 { + device_type = "ethernet-phy"; + reg = <0>; + }; };I am struggling with this part on Efika.
I would like to add this to the device tree fromfixup_device_tree_efika()(arch/powerpc/kernel/prom_init.c).AFAICS client-services doesn't offer anything like new-device, so I guess "interpret" or "call-method" will have to be used.
I have read some docs, but I'm still wandering in the dark. Can I please get an example?
Pretty please with a cherry on top?Domen
Quoted 5 lines · Matt Sealey
Domen,
Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter Linux with more fixups. The Efika PHY isn't going to change to something else and it's a bog standard no-frills MII PHY anyway.
Fine with me, but I'm worried people won't update nvramrc.
Currently I have this:
--- start ---
s" /builtin" find-device
new-device
1 encode-int s" #address-cells" property 0 encode-int s" #size-cells" property s" mdio" 2dup device-name device-type s" mpc5200b-fec-phy" s" compatible" property 0xf0003000 0x400 reg
0x2 encode-int
0x5 encode-int
0x3 encode-int
encode+ encode+
s" interupts" property
new-device
s" ethernet-phy@0" device-name
s" ethernet-phy" device-type
0 encode-int s" reg" property
my-self \ save our phandle to stack ihandle>phandle
finish-device
finish-device
s" /builtin/ethernet" find-device
encode-int \ phy's phandle
s" phy-handle" property
device-end
--- end ---
But I have a problem with it, possibly due to my not-knowledge of Forth. Compatible keep getting set to:
compatible "/builtin/etherne"
<spin>
Quoted 3 lines
If you insist on using
prom_initand fixups, yaboot has the best examples of call-method and interpret, both readable and fairly easily available.
Thanks.
Domen
Quoted 37 lines
Quoted 27 lines · Domen Puncer
Quoted 8 lines
Index:
work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================arch/powerpc/boot/dts/lite5200b.dts +4
-0+ mdio@3000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio";arch/powerpc/boot/dts/lite5200b.dts line 388
Quoted 10 lines
arch/powerpc/boot/dts/lite5200b.dts +9
-0+ compatible = "mpc5200b-fec-phy"; + reg = <3000 400>; // fec range, since we need to setup fec interrupts + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co. + interrupt-parent = <&mpc5200_pic>; + + phy0:ethernet-phy@0 { + device_type = "ethernet-phy"; + reg = <0>; + }; };I am struggling with this part on Efika.
I would like to add this to the device tree fromfixup_device_tree_efika()(arch/powerpc/kernel/prom_init.c).AFAICS client-services doesn't offer anything like new-device, so I guess "interpret" or "call-method" will have to be used.
Quoted 6 lines
I have read some docs, but I'm still wandering in the dark. Can I please get an example?
Pretty please with a cherry on top?Domen
_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
Quoted 9 lines · Domen Puncer
Quoted 5 lines · Matt Sealey
Domen,
Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter Linux with more fixups. The Efika PHY isn't going to change to something else and it's a bog standard no-frills MII PHY anyway.
Fine with me, but I'm worried people won't update nvramrc.
...
Quoted 3 lines
But I have a problem with it, possibly due to my not-knowledge of Forth. Compatible keep getting set to:
compatible "/builtin/etherne"
I missed the encode-string.
Matt, can you please add attached Forth script to Efika updates.
Domen
s" /builtin" find-device
new-device
1 encode-int s" #address-cells" property
0 encode-int s" #size-cells" property
s" mdio" 2dup device-name device-type
s" mpc5200b-fec-phy" encode-string s" compatible" property 0xf0003000 0x400 reg
0x2 encode-int
0x5 encode-int
0x3 encode-int
encode+ encode+
s" interrupts" property
new-device
s" ethernet-phy" 2dup device-name device-type 0x10 encode-int s" reg" property
my-self \ save our phandle to stack
ihandle>phandle
finish-device
finish-device
s" /builtin/ethernet" find-device
encode-int \ phy's phandle
s" phy-handle" property
device-end
Are you sure this is correct for the Efika?
The MPC5200B manual makes a decent distinction between MII operation and straight MDIO?
Signature · 2 lines
Matt Sealey <[email protected]> Genesi, Manager, Developer Relations
Quoted 20 lines · Domen Puncer
Quoted 8 lines · Domen Puncer
Quoted 5 lines · Matt Sealey
Domen,
Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter Linux with more fixups. The Efika PHY isn't going to change to something else and it's a bog standard no-frills MII PHY anyway.
Fine with me, but I'm worried people won't update nvramrc.
...
Quoted 3 lines
But I have a problem with it, possibly due to my not-knowledge of Forth. Compatible keep getting set to:
compatible "/builtin/etherne"I missed the encode-string.
Matt, can you please add attached Forth script to Efika updates.
Domen
Quoted 1 line · Matt Sealey
Are you sure this is correct for the Efika?
It works (tm).
Quoted 3 lines
The MPC5200B manual makes a decent distinction between MII operation and straight MDIO?
Uh? From what I read MDIO are the lines of MII.
Domen
Quoted 26 lines
Signature · 3 lines
-- Matt Sealey <[email protected]> Genesi, Manager, Developer RelationsQuoted 20 lines · Domen Puncer
Quoted 8 lines · Domen Puncer
Quoted 5 lines · Matt Sealey
Domen,
Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter Linux with more fixups. The Efika PHY isn't going to change to something else and it's a bog standard no-frills MII PHY anyway.
Fine with me, but I'm worried people won't update nvramrc.
...
Quoted 3 lines
But I have a problem with it, possibly due to my not-knowledge of Forth. Compatible keep getting set to:
compatible "/builtin/etherne"I missed the encode-string.
Matt, can you please add attached Forth script to Efika updates.
Domen
RFC PATCH 1/1 net driver: mpc52xx fec
In reply to Domen PuncerHi!
new in this version:
- fixed stuff that was commented on.
- added 7-wire support (compile at least, if someone has the hardware, please test!)
- ethtool support
(this obsoletes Sylvain's patch that's floating around:
0008-drivers-net-Add-support-for-Freescale-MPC5200-SoC-i.patch)
If there are no objections, I would like this to be merged after bestcomm (mpc52xx dma engine) patches hit mainline, and that will hopefully be at the beginning of the 2.6.24 merge window.
--
Driver for ethernet on mpc5200/mpc5200b SoCs (FEC).
--- arch/powerpc/boot/dts/lite5200b.dts | 18 arch/powerpc/sysdev/bestcomm/fec.h | 15 drivers/net/Kconfig | 1 drivers/net/Makefile | 1 drivers/net/fec_mpc52xx/Kconfig | 25 drivers/net/fec_mpc52xx/Makefile | 7 drivers/net/fec_mpc52xx/fec.c | 1127 ++++++++++++++++++++++++++++++++++++ drivers/net/fec_mpc52xx/fec.h | 329 ++++++++++ drivers/net/fec_mpc52xx/fec_phy.c | 238 +++++++ 9 files changed, 1759 insertions(+), 2 deletions(-)
drivers/net/Kconfig +1 -0
@@ -1956,6 +1956,7 @@ config NE_H8300 controller on the Renesas H8/300 processor. source "drivers/net/fec_8xx/Kconfig" +source "drivers/net/fec_mpc52xx/Kconfig" source "drivers/net/fs_enet/Kconfig" endif # NET_ETHERNET
drivers/net/Makefile +1 -0
@@ -204,6 +204,7 @@ obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_FEC_8XX) += fec_8xx/ +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o obj-$(CONFIG_MLX4_CORE) += mlx4/
arch/powerpc/boot/dts/lite5200b.dts +17 -1
@@ -306,10 +306,26 @@ ethernet@3000 { device_type = "network"; compatible = "mpc5200b-fec\0mpc5200-fec"; - reg = <3000 800>; + reg = <3000 400>; mac-address = [ 02 03 04 05 06 07 ]; // Bad! interrupts = <2 5 0>; interrupt-parent = <&mpc5200_pic>; + phy-handle = <&phy0>; + }; + + mdio@3000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio"; + compatible = "mpc5200b-fec-phy"; + reg = <3000 400>; // fec range, since we need to setup fec interrupts + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co. + interrupt-parent = <&mpc5200_pic>; + + phy0:ethernet-phy@0 { + device_type = "ethernet-phy"; + reg = <0>; + }; }; ata@3a00 {
arch/powerpc/sysdev/bestcomm/fec.h +14 -1
@@ -21,7 +21,20 @@ struct bcom_fec_bd { };#define BCOM_FEC_TX_BD_TFD 0x08000000ul/* transmit frame done */ -#define BCOM_FEC_TX_BD_INT 0x04000000ul/* interrupt */ +#define BCOM_FEC_TX_BD_TC 0x04000000ul/* transmit CRC */ +#define BCOM_FEC_TX_BD_ABC 0x02000000ul/* append bad CRC */ + +#define BCOM_FEC_RX_BD_L 0x08000000ul/* buffer is last in frame */ +#define BCOM_FEC_RX_BD_BC 0x00800000ul/* DA is broadcast */ +#define BCOM_FEC_RX_BD_MC 0x00400000ul/* DA is multicast and not broadcast */ +#define BCOM_FEC_RX_BD_LG 0x00200000ul/* Rx frame length violation */ +#define BCOM_FEC_RX_BD_NO 0x00100000ul/* Rx non-octet aligned frame */ +#define BCOM_FEC_RX_BD_CR 0x00040000ul/* Rx CRC error */ +#define BCOM_FEC_RX_BD_OV 0x00020000ul/* overrun */ +#define BCOM_FEC_RX_BD_TR 0x00010000ul/* Rx frame truncated */ +#define BCOM_FEC_RX_BD_LEN_MASK 0x000007fful/* mask for length of received frame */ +#define BCOM_FEC_RX_BD_ERRORS (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \ + BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR) extern struct bcom_task *
drivers/net/fec_mpc52xx/Kconfig new file +25 -0
@@ -0,0 +1,25 @@ +menu "MPC5200 Networking Options" + depends PPC_MPC52xx && NET_ETHERNET + +config FEC_MPC52xx + tristate "FEC Ethernet" + depends on NET_ETHERNET + select PPC_BESTCOMM + select PPC_BESTCOMM_FEC + select CRC32 + ---help--- + This option enables support for the MPC5200's on-chip + Fast Ethernet Controller + +config FEC_MPC52xx_MDIO + bool "Use external Ethernet MII PHY" + depends on FEC_MPC52xx + select PHYLIB + default y + ---help--- + The MPC5200's FEC can connect to the Ethernet either with + an external MII PHY chip or 10 Mbps 7-wire interface + (Motorola? industry standard). + If your board uses an external PHY, say y, else n. + +endmenu
drivers/net/fec_mpc52xx/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o + +fec_mpc52xx-objs := fec.o + +ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) +fec_mpc52xx-objs += fec_phy.o +endif
drivers/net/fec_mpc52xx/fec.c new file +1127 -0
1,127 lines not on this page · raw message
drivers/net/fec_mpc52xx/fec.h new file +329 -0
329 lines not on this page · raw message
drivers/net/fec_mpc52xx/fec_phy.c new file +238 -0
238 lines not on this page · raw message
Quoted 7 lines · Domen Puncer
Hi!
new in this version:
- fixed stuff that was commented on.
- added 7-wire support (compile at least, if someone has the hardware, please test!)
- ethtool support
Thanks for this work Domen, comments below...
This is a large patch, and it should be broken up into logical changes. ie. split into dts changes, bestcomm changes, fec driver and mdio driver. Easier to review that way. The bestcomm and dts changes don't need to go to the netdev list.
Quoted 16 lines
drivers/net/fec_mpc52xx/Kconfig new file +13
-0@@ -0,0 +1,25 @@ +menu "MPC5200 Networking Options" + depends PPC_MPC52xx && NET_ETHERNET + +config FEC_MPC52xx + tristate "FEC Ethernet" + depends on NET_ETHERNET + select PPC_BESTCOMM + select PPC_BESTCOMM_FEC + select CRC32 + ---help--- + This option enables support for the MPC5200's on-chip + Fast Ethernet Controller +
drivers/net/fec_mpc52xx/Kconfig line 23
Quoted 10 lines
drivers/net/fec_mpc52xx/Kconfig new file +10
-0+config FEC_MPC52xx_MDIO + bool "Use external Ethernet MII PHY" + depends on FEC_MPC52xx + select PHYLIB + default y + ---help--- + The MPC5200's FEC can connect to the Ethernet either with + an external MII PHY chip or 10 Mbps 7-wire interface + (Motorola? industry standard). + If your board uses an external PHY, say y, else n.
This option should change. Either build the MDIO driver into the FEC driver unconditionally and drop this option, or make the MDIO driver independent from the FEC driver (it does use the MDIO bus infrastructure after all). Either way the FEC driver should detect the phy type at runtime (possibly based on the presence/absence of a phy-handle property) instead of being hard compiled. 5200 support is now multiplatform after all.
If you drop the MDIO config option, then I'd also consider eliminating driver/net/fec_mpc52xx/Kconfig entirely and rolling the single MPC52xx_FEC option into drivers/net/Kconfig.
Quoted 7 lines
drivers/net/fec_mpc52xx/Kconfig new file +2
-0+ +endmenuIndex: linux.git/drivers/net/fec_mpc52xx/Makefile
===================================================================
drivers/net/fec_mpc52xx/Makefile line 7
Quoted 7 lines
drivers/net/fec_mpc52xx/Makefile new file +7
-0@@ -0,0 +1,7 @@ +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o + +fec_mpc52xx-objs := fec.o + +ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) +fec_mpc52xx-objs += fec_phy.o +endif
Hmm, is the phy driver separate or not? You've got the logic in place to probe MDIO separately from the FEC driver, yet they are linked as a single driver.
Quoted 51 lines
Index:
linux.git/drivers/net/fec_mpc52xx/fec.c
===================================================================drivers/net/fec_mpc52xx/fec.c new file +46
-0@@ -0,0 +1,1127 @@ +/* +* drivers/drivers/net/fec_mpc52xx/fec.c +* +* Driver for the MPC5200 Fast Ethernet Controller +* +* Originally written by Dale Farnsworth <[email protected]> and +* now maintained by Sylvain Munaut <[email protected]> +* +* Copyright (C) 2007 Domen Puncer, Telargo, Inc. +* Copyright (C) 2007 Sylvain Munaut <[email protected]> +* Copyright (C) 2003-2004 MontaVista, Software, Inc. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +*/ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/crc32.h> +#include <linux/hardirq.h> +#include <linux/delay.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> + +#include <asm/of_device.h> +#include <asm/of_platform.h> +#include <asm/io.h> +#include <asm/delay.h> +#include <asm/mpc52xx.h> + +#include <sysdev/bestcomm/bestcomm.h> +#include <sysdev/bestcomm/fec.h> + +#include "fec.h" + +#define DRIVER_NAME "mpc52xx-fec"
drivers/net/fec_mpc52xx/fec.c line 56
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c new file +10
-0+ +static irqreturn_t fec_interrupt (int ,void *); +static irqreturn_t fec_rx_interrupt (int ,void *); +static irqreturn_t fec_tx_interrupt (int ,void *); +static struct net_device_stats *fec_get_stats (struct net_device *); +static void fec_set_multicast_list (struct net_device *dev); +static void fec_hw_init (struct net_device *dev); +static void fec_stop (struct net_device *dev); +static void fec_start (struct net_device *dev); +static void fec_reset (struct net_device *dev);
Nit: Are all these forward decls needed?
drivers/net/fec_mpc52xx/fec.c line 58
Quoted 2 lines
drivers/net/fec_mpc52xx/fec.c new file +2
-0+ +static u8 mpc52xx_fec_mac_addr[6 ];
Why isn't this part of struct fec_priv?
drivers/net/fec_mpc52xx/fec.c line 59
Quoted 1 line
drivers/net/fec_mpc52xx/fec.c new file +1
-0+static const u8 null_mac[6 ];
null_mac?!? Just for comparing a mac addr against 0?
<snip>
drivers/net/fec_mpc52xx/fec.c line 60
Quoted 1 line
drivers/net/fec_mpc52xx/fec.c new file +1
-0+#ifdef CONFIG_FEC_MPC52xx_MDIO
Once again; don't make this a conditional compile; detect at runtime.
<snip>
Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c new file +6
-0+static void __init fec_str2mac (char *str,unsigned char *mac) +{ +int i; +u64 val64; + + val64 =simple_strtoull (str,NULL ,16 );
drivers/net/fec_mpc52xx/fec.c line 651
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c new file +10
-0+ +for (i =0 ; i <6 ; i++) + mac[5 -i] = val64 >> (i*8 ); +} + +static int __init mpc52xx_fec_mac_setup (char *mac_address) +{ +fec_str2mac (mac_address, mpc52xx_fec_mac_addr); +return 0 ; +}
fec_str2mac is called in *1* place. I'd roll it into mpc52xx_fec_mac_setup.
Quoted 3 lines
drivers/net/fec_mpc52xx/fec.c new file +3
-0+ +__setup ("mpc52xx-mac=" , mpc52xx_fec_mac_setup); +
Signature · 4 lines
Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. [email protected] (403) 399-0195
Quoted 9 lines · Grant Likely
Quoted 7 lines · Domen Puncer
Hi!
new in this version:
- fixed stuff that was commented on.
- added 7-wire support (compile at least, if someone has the hardware, please test!)
- ethtool support
Quoted 6 lines
Thanks for this work Domen, comments below...
This is a large patch, and it should be broken up into logical changes. ie. split into dts changes, bestcomm changes, fec driver and mdio driver. Easier to review that way. The bestcomm and dts changes don't need to go to the netdev list.
A similar patch that is already broken up is available for Efika.
http://dev.gentoo.org/~nixnut/efika/efika-patches-2.6.22.tar.bz2
Signature · 2 lines
Jon Smirl [email protected]
Quoted 12 lines · Jon Smirl
Quoted 11 lines · Grant Likely
Quoted 7 lines · Domen Puncer
Hi!
new in this version:
- fixed stuff that was commented on.
- added 7-wire support (compile at least, if someone has the hardware, please test!)
- ethtool supportThanks for this work Domen, comments below...
Quoted 7 lines
Quoted 4 lines
This is a large patch, and it should be broken up into logical changes. ie. split into dts changes, bestcomm changes, fec driver and mdio driver. Easier to review that way. The bestcomm and dts changes don't need to go to the netdev list.
A similar patch that is already broken up is available for Efika.
http://dev.gentoo.org/~nixnut/efika/efika-patches-2.6.22.tar.bz2
No. That series is Sylvain's full patchset including the old FEC driver. Domen's patch is a reworked FEC driver, and it only replaces patch 0008 from that series. However, this patch should be split up further because it makes changes to both the device tree and the bestcomm code.
Cheers,
g.
Signature · 4 lines
Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. [email protected] (403) 399-0195
Quoted 10 lines · Grant Likely
Quoted 7 lines · Domen Puncer
Hi!
new in this version:
- fixed stuff that was commented on.
- added 7-wire support (compile at least, if someone has the hardware, please test!)
- ethtool supportThanks for this work Domen, comments below...
Thanks for reviewing and sorry for not replying sooner, I lost the mail.
Quoted 5 lines
This is a large patch, and it should be broken up into logical changes. ie. split into dts changes, bestcomm changes, fec driver and mdio driver. Easier to review that way. The bestcomm and dts changes don't need to go to the netdev list.
OK.
Quoted 29 lines
Quoted 10 lines
drivers/net/fec_mpc52xx/Kconfig new file +10
-0+config FEC_MPC52xx + tristate "FEC Ethernet" + depends on NET_ETHERNET + select PPC_BESTCOMM + select PPC_BESTCOMM_FEC + select CRC32 + ---help--- + This option enables support for the MPC5200's on-chip + Fast Ethernet Controller +drivers/net/fec_mpc52xx/Kconfig line 23
Quoted 10 lines
drivers/net/fec_mpc52xx/Kconfig new file +10
-0+config FEC_MPC52xx_MDIO + bool "Use external Ethernet MII PHY" + depends on FEC_MPC52xx + select PHYLIB + default y + ---help--- + The MPC5200's FEC can connect to the Ethernet either with + an external MII PHY chip or 10 Mbps 7-wire interface + (Motorola? industry standard). + If your board uses an external PHY, say y, else n.This option should change. Either build the MDIO driver into the FEC driver unconditionally and drop this option, or make the MDIO driver independent from the FEC driver (it does use the MDIO bus infrastructure after all). Either way the FEC driver should detect the phy type at runtime (possibly based on the presence/absence of a phy-handle property) instead of being hard compiled. 5200 support is now multiplatform after all.
Quoted 3 lines
If you drop the MDIO config option, then I'd also consider eliminating driver/net/fec_mpc52xx/Kconfig entirely and rolling the single
MPC52xx_FECoption intodrivers/net/Kconfig.
Right. I separated it.
Quoted 11 lines
drivers/net/fec_mpc52xx/fec.c line 56
Quoted 9 lines
drivers/net/fec_mpc52xx/fec.c new file +9
-0+static irqreturn_t fec_interrupt (int ,void *); +static irqreturn_t fec_rx_interrupt (int ,void *); +static irqreturn_t fec_tx_interrupt (int ,void *); +static struct net_device_stats *fec_get_stats (struct net_device *); +static void fec_set_multicast_list (struct net_device *dev); +static void fec_hw_init (struct net_device *dev); +static void fec_stop (struct net_device *dev); +static void fec_start (struct net_device *dev); +static void fec_reset (struct net_device *dev);Nit: Are all these forward decls needed?
Some aren't - cleaned.
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ +static u8 mpc52xx_fec_mac_addr[6];Why isn't this part of struct
fec_priv?
Because at __setup time, there's no fec_priv instance. OTOH, does anyone even use mpc52xx-mac=?
Quoted 4 lines
Quoted 2 lines
+static const u8 null_mac[6];
null_mac?!? Just for comparing a mac addr against 0?
right, is_zero_ether_addr is the right thing.
Quoted 28 lines
<snip>
Quoted 1 line
+#ifdef
CONFIG_FEC_MPC52xx_MDIOOnce again; don't make this a conditional compile; detect at runtime.
<snip>
Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c new file +6
-0+static void __init fec_str2mac (char *str,unsigned char *mac) +{ +int i; +u64 val64; + + val64 =simple_strtoull (str,NULL ,16 );drivers/net/fec_mpc52xx/fec.c line 651
Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c new file +10
-0+ +for (i =0 ; i <6 ; i++) + mac[5 -i] = val64 >> (i*8 ); +} + +static int __init mpc52xx_fec_mac_setup (char *mac_address) +{ +fec_str2mac (mac_address, mpc52xx_fec_mac_addr); +return 0 ; +}
fec_str2macis called in *1* place. I'd roll it intompc52xx_fec_mac_setup.
Quoted 4 lines
drivers/net/fec_mpc52xx/fec.c line 654
Quoted 3 lines
drivers/net/fec_mpc52xx/fec.c new file +3
-0+ +__setup ("mpc52xx-mac=" , mpc52xx_fec_mac_setup); +
OK.
Updated and split version at:
http://coderock.org/tmp/fec-v3rc1/
I'll repost to lists once I run-test them.
Domen
Quoted 11 lines
Signature · 9 lines
-- Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. [email protected] (403) 399-0195 _______________________________________________ Linuxppc-embedded mailing list [email protected] https://ozlabs.org/mailman/listinfo/linuxppc-embedded
Quoted 4 lines · Domen Puncer
Updated and split version at:
http://coderock.org/tmp/fec-v3rc1/I'll repost to lists once I run-test them.
When applying those patches, the build did die with :
ERROR: "phy_mii_ioctl" [drivers/net/fec_mpc52xx/fec_mpc52xx.ko] undefined!
Apparently, phy_mii_ioctl is not an exported symbol.
Domen, did you maybe forget a little snipplet when you cut the patches in different pieces ? Or did i mess up applying them ?
Friendly,
Sven Luther
PATCH 1/1 phy: export phy_mii_ioctl
Export phy_mii_ioctl, so network drivers can use it when built as modules too.
---
Quoted 11 lines · Sven Luther
Quoted 4 lines · Domen Puncer
Updated and split version at:
http://coderock.org/tmp/fec-v3rc1/I'll repost to lists once I run-test them.
When applying those patches, the build did die with :
ERROR: "
phy_mii_ioctl" [drivers/net/fec_mpc52xx/fec_mpc52xx.ko] undefined!
Quoted 8 lines
Apparently,
phy_mii_ioctlis not an exported symbol.Domen, did you maybe forget a little snipplet when you cut the patches in different pieces ? Or did i mess up applying them ?
Friendly,
Sven Luther
drivers/net/phy/phy.c | 1 + 1 files changed, 1 insertion(+)
drivers/net/phy/phy.c +1 -0
@@ -409,6 +409,7 @@ int phy_mii_ioctl(struct phy_device *phyreturn 0 ; } +EXPORT_SYMBOL (phy_mii_ioctl);/** * phy_start_aneg - start auto-negotiation for this PHY device
Re: [PATCH] phy: export phy_mii_ioctl
Quoted 2 lines · Domen Puncer
Export
phy_mii_ioctl, so network drivers can use it when built as modules too.
Domen, do you want to collect all of these changes for MPC5200 FEC in to a single patch series? The code is getting scattered around, I'll check it over to make sure it is all working. I have these patches applied individually and they all work.
It builds on this series:
[PATCH 0/7] MPC52xx Bestcomm submission for 2.6.24
If you can put this together is a clean series, I should be able to layer support for the Phytec pcm030 on top of it.
It would be these three combined...
http://coderock.org/tmp/fec-v3rc1/
drivers/net/fec_mpc52xx/fec.c +4 -2
@@ -1087,11 +1087,13 @@ static struct of_platform_driver mpc52xx_fec_driver = {/* ======================================================================== */ /* Module */ /* ======================================================================== */ +extern int fec_mdio_init (void ); +void fec_mdio_exit (void );static int __init mpc52xx_fec_init (void ) { -#ifdef FEC_MPC52xx_MDIO +#ifdef CONFIG_FEC_MPC52xx_MDIOint ret; ret =fec_mdio_init ();if (ret) {
@@ -1106,7 +1108,7 @@ static void __exitmpc52xx_fec_exit (void) {of_unregister_platform_driver (&mpc52xx_fec_driver); -#ifdef FEC_MPC52xx_MDIO +#ifdef CONFIG_FEC_MPC52xx_MDIOfec_mdio_exit ();#endif }
Quoted 47 lines
Signed-off-by Domen Puncer <[email protected]>---
Quoted 11 lines · Sven Luther
Quoted 4 lines · Domen Puncer
Updated and split version at:
http://coderock.org/tmp/fec-v3rc1/I'll repost to lists once I run-test them.
When applying those patches, the build did die with :
ERROR: "
phy_mii_ioctl" [drivers/net/fec_mpc52xx/fec_mpc52xx.ko] undefined!Quoted 8 lines
Apparently,
phy_mii_ioctlis not an exported symbol.Domen, did you maybe forget a little snipplet when you cut the patches in different pieces ? Or did i mess up applying them ?
Friendly,
Sven Luther
drivers/net/phy/phy.c | 1 + 1 files changed, 1 insertion(+)Index:
linux.git/drivers/net/phy/phy.c
===================================================================drivers/net/phy/phy.c +1
-0@@ -409,6 +409,7 @@ int phy_mii_ioctl(struct phy_device *phyreturn 0 ; } +EXPORT_SYMBOL (phy_mii_ioctl);/** * phy_start_aneg - start auto-negotiation for this PHY device _______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
Signature · 2 lines
Jon Smirl [email protected]
Re: [PATCH] phy: export phy_mii_ioctl
(I edited Cc: -jeff, +sven, hope you don't mind)
Quoted 12 lines · Jon Smirl
Quoted 2 lines · Domen Puncer
Export
phy_mii_ioctl, so network drivers can use it when built as modules too.Domen, do you want to collect all of these changes for MPC5200 FEC in to a single patch series? The code is getting scattered around, I'll check it over to make sure it is all working. I have these patches applied individually and they all work.
It builds on this series:
[PATCH 0/7] MPC52xx Bestcomm submission for 2.6.24
Quoted 6 lines
If you can put this together is a clean series, I should be able to layer support for the Phytec pcm030 on top of it.
It would be these three combined...
http://coderock.org/tmp/fec-v3rc2/
export_phy_mii_ioctl
fec_driver-bestcomm
fec_driver-dts
fec_driver-fec
fec_driver-phy
Built (on top of 7 bestcomm patches) and ran it built-in and as module on Efika.
Order of applying only matters for phy part, which has to be after the fec driver.
More testing and getting it to work properly on Phytec pcm030 would be great.
Domen
Re: [PATCH] phy: export phy_mii_ioctl
Quoted 2 lines · Domen Puncer
More testing and getting it to work properly on Phytec pcm030 would be great.
I compiled it as a module:
CC [M] drivers/net/fec_mpc52xx/fec.odrivers/net/fec_mpc52xx/fec.c:613: warning: 'mpc52xx_fec_mac_setup' defined but not used
This code needs to be enclosed in "#ifndef MODULE". But why aren't you using module_param() to make a string parameter and then copy it into mpc52xx_fec_mac_addr[] if the parameter is not null?
If it is a module param you need to use fec_mpc52xx_phy.mpc52xx-mac="xxxx" instead of just mpc52xx-mac. The way it is not you can't use mpc52xx-mac when built as a module.
static int __init mpc52xx_fec_mac_setup(char *mac_address)
{
int i;
u64 val64;
val64 = simple_strtoull(mac_address, NULL, 16);
for (i = 0; i < 6; i++)
mpc52xx_fec_mac_addr[5-i] = val64 >> (i*8);
return 0;
}__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
Signature · 2 lines
Jon Smirl [email protected]
Re: [PATCH] phy: export phy_mii_ioctl
Quoted 4 lines · Jon Smirl
Quoted 2 lines · Domen Puncer
More testing and getting it to work properly on Phytec pcm030 would be great.
Quoted 8 lines
I compiled it as a module:
CC [M]drivers/net/fec_mpc52xx/fec.odrivers/net/fec_mpc52xx/fec.c:613: warning: 'mpc52xx_fec_mac_setup' defined but not usedThis code needs to be enclosed in "#ifndef MODULE". But why aren't you using
module_param()to make a string parameter and then copy it into mpc52xx_fec_mac_addr[] if the parameter is not null?
Right,
Patch at the end.
When compiled as module use "modprobe fec_mpc52xx mac=foo", when built-in add to boot line: "fec_mpc52xx.mac=foo"
As for link-up-printk in the middle of DHCP requests... is it really that big of a problem?
This sort of things happen when printk doesn't have the whole line... getting rid of link-up message would just hide it (it can show ie. when an usb device is bound to scsi layer).
Domen
--- drivers/net/fec_mpc52xx/fec.c | 18 ++---------------- 1 files changed, 2 insertions(+), 16 deletions(-)
drivers/net/fec_mpc52xx/fec.c +2 -16
@@ -53,6 +53,8 @@ static void fec_start(struct net_devicestatic void fec_reset (struct net_device *dev);static u8 mpc52xx_fec_mac_addr[6 ]; +module_param_array_named (mac, mpc52xx_fec_mac_addr, byte,NULL ,0 ); +MODULE_PARM_DESC (mac,"six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe" );static void fec_tx_timeout (struct net_device *dev) {
@@ -609,22 +611,6 @@ static void fec_set_multicast_list(struc } } -static int __init mpc52xx_fec_mac_setup (char *mac_address) -{ -int i; -u64 val64; - - val64 =simple_strtoull (mac_address,NULL ,16 ); - -for (i =0 ; i <6 ; i++) - mpc52xx_fec_mac_addr[5 -i] = val64 >> (i*8 ); - -return 0 ; -} - -__setup ("mpc52xx-mac=" ,mpc52xx_fec_mac_setup); - -/** * fec_hw_init * @dev: network device
Re: [PATCH] phy: export phy_mii_ioctl
Quoted 3 lines · Domen Puncer
Patch at the end.
When compiled as module use "modprobefec_mpc52xxmac=foo", when built-in add to boot line: "fec_mpc52xx.mac=foo"
This patch series is working for me now.
This needs a cleanup too, but it is unrelated....
CC drivers/serial/mpc52xx_uart.odrivers/serial/mpc52xx_uart.c: In function 'mpc52xx_console_setup':drivers/serial/mpc52xx_uart.c:760: warning: format '%lx' expects type 'long unsigned int', but argument 2 has type 'resource_size_t' drivers/serial/mpc52xx_uart.c: In function 'mpc52xx_uart_of_probe':drivers/serial/mpc52xx_uart.c:978: warning: format '%lx' expects type 'long unsigned int', but argument 3 has type 'resource_size_t'
Signature · 2 lines
Jon Smirl [email protected]
Re: [PATCH] phy: export phy_mii_ioctl
Quoted 1 line · Jon Smirl
This needs a cleanup too, but it is unrelated....
Another set of related warnings that need clean up....
CC drivers/spi/mpc52xx_psc_spi.odrivers/spi/mpc52xx_psc_spi.c: In function 'mpc52xx_psc_spi_activate_cs':drivers/spi/mpc52xx_psc_spi.c:110: warning: passing argument 1 of 'in_be16' from incompatible pointer type drivers/spi/mpc52xx_psc_spi.c:116: warning: passing argument 1 of 'out_be16' from incompatible pointer type drivers/spi/mpc52xx_psc_spi.c: In function 'mpc52xx_psc_spi_port_config':drivers/spi/mpc52xx_psc_spi.c:417: warning: passing argument 1 of 'out_be16' from incompatible pointer type
Signature · 2 lines
Jon Smirl [email protected]
Re: [PATCH] phy: export phy_mii_ioctl
In reply to Domen PuncerQuoted 2 lines · Domen Puncer
More testing and getting it to work properly on Phytec pcm030 would be great.
Do we want to do anything about this?
[ 1.569657] net eth0: attached phy 0 to driver Generic PHY [ 2.576013] Sending DHCP requests .<6>PHY: f0003000:00 - Link is Up - 100/Full [ 4.612000] ., OK [ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, my
address is 192.168.1.5
What is happening is the printk for "<6>PHY: f0003000:00 - Link is Up
- 100/Full" is done in an interrupt and it comes in the middle of the kernel doing DHCP and printing ... without a CR.
Two possible solutions, get rid of the link-up message or wait in in the initial driver load until the link is up. Or we could leave it the way it is, but some people may report this as a bug.
Signature · 2 lines
Jon Smirl [email protected]
RE: [PATCH] phy: export phy_mii_ioctl
Hello Jon,
I´m also working with a Phytec pcm030, but I can´t get it booted...
Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over these with this new ones that Domen released. The base kernel I´m using is 2.6.22.6 from kernel.org.
Although I used the patch that creates pcm030.c in arch/platforms/52xx/ and compiled using this file, it gets halted at booting time.
Bytes transferred = 5091 (13e3 hex)
## Booting image at 00500000 ...
Image Name: Linux-2.6.22.6 Created: 2007-09-19 8:53:02 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 1196911 Bytes = 1.1 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at 0x400000
(No more output and boot is halted)
Are you using any other patch for the platform or any other kernel, because I tried to apply these patches to a 2.6.20 kernel and are not successful.
Bests,
Pedro.
Quoted 11 lines
Date: Tue, 18 Sep 2007 15:29:09 -0400> From: [email protected]
To: [email protected]> Subject: Re: [PATCH] phy: exportphy_mii_ioctl
CC: [email protected]; [email protected]Quoted 4 lines · Domen Puncer
More testing and getting it to work properly on Phytec pcm030 would be great.>> Do we want to do anything about this?
[ 1.569657] net eth0: attached phy 0 to driver Generic PHY[ 2.576013] Sending DHCP requests .PHY: f0003000:00 - Link is Up - 100/Full> [ 4.612000] ., OK [ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, myaddress is 192.168.1.5
Quoted 8 lines
Quoted 1 line
What is happening is the printk for "PHY: f0003000:00 - Link is Up
- 100/Full" is done in an interrupt and it comes in the middle of the> kernel doing DHCP and printing ... without a CR.
Quoted 1 line
Two possible solutions, get rid of the link-up message or wait in in
the initial driver load until the link is up. Or we could leave it the way it is, but some people may report this as a bug.
Quoted 1 line
Quoted 1 line
--> Jon Smirl> [email protected]
_______________________________________________
Linuxppc-embedded mailing list> [email protected]> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
_________________________________________________________________
Busca desde cualquier página Web con una protección excepcional. Consigue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com
Re: [PATCH] phy: export phy_mii_ioctl
Pedro,
Quoted 6 lines · Pedro Luis D. L.
I=B4m also working with a Phytec pcm030, but I can=B4t get it booted... Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over these with this new ones that Domen released. The base kernel I=B4m using is 2.6.22.6 from kernel.org.
Although I used the patch that createspcm030.cinarch/platforms/52xx/a=
nd
Quoted 8 lines
compiled using this file, it gets halted at booting time.
Bytes transferred =3D 5091 (13e3 hex)
## Booting image at 00500000 ...Image Name: Linux-2.6.22.6 Created: 2007-09-19 8:53:02 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 1196911 Bytes =3D 1.1 MB
Quoted 7 lines
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at0x400000(No more output and boot is halted)
Check your oftree! Most of the time this behaviour means its a wrong oftree=
in=20
use.
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
RE: [PATCH] phy: export phy_mii_ioctl
Quoted 7 lines · Juergen
Pedro,
Quoted 3 lines · Pedro Luis D. L.
I=B4m also working with a Phytec pcm030, but I can=B4t get it booted... Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over thes=
e
Quoted 3 lines
Quoted 3 lines
with this new ones that Domen released. The base kernel I=B4m using is 2.6.22.6 from kernel.org.
Although I used the patch that createspcm030.cinarch/platforms/52xx/=
and
Quoted 14 lines
Quoted 14 lines
compiled using this file, it gets halted at booting time.
Bytes transferred =3D 5091 (13e3 hex)
## Booting image at 00500000 ...Image Name: Linux-2.6.22.6 Created: 2007-09-19 8:53:02 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 1196911 Bytes =3D 1.1 MBLoad Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at0x400000
Quoted 3 lines
Quoted 1 line
(No more output and boot is halted)
=20
Check your oftree! Most of the time this behaviour means its a wrong oftre=
e in=20
Quoted 1 line
use.
I=B4m using an specific pcm030.dts oftree that works for the 2.6.20 kernel.=
I=B4m not quite familiar with the oftree stuff, but I thought it should wo=
rk also for the 2.6.22.6.
Is there any other dts file? Where can I find it?
Pedro.
PD: Sorry. I sent the previous message to Jon, Domen and someone else too b= esides the list. I had some problems with the browser... Even sent twice th= e message :-(
Quoted 9 lines
Juergen
=20
--=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
Pengutronix - Linux Solutions for Science and Industry
Handelsregister: Amtsgericht Hildesheim, HRA 2686
Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
_________________________________________________________________
Llama a tus amigos de PC a PC: =A1Es GRATIS!
http://get.live.com/messenger/overview=
Re: [PATCH] phy: export phy_mii_ioctl
Pedro,
Quoted 1 line · Pedro Luis D. L.
I=B4m using an specific
pcm030.dtsoftree that works for the 2.6.20 kerne=
l.
Quoted 1 line
I=B4m not quite familiar with the oftree stuff, but I thought it should w=
ork
Quoted 1 line
also for the 2.6.22.6. Is there any other dts file? Where can I find it?
dts patch sent offline.
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
RE: [PATCH] phy: export phy_mii_ioctl
Quoted 5 lines
Pedro,
=20Quoted 1 line · Pedro Luis D. L.
I=B4m using an specific
pcm030.dtsoftree that works for the 2.6.20 kern=
el.
Quoted 1 line
Quoted 1 line
I=B4m not quite familiar with the oftree stuff, but I thought it should =
work
Quoted 3 lines
Quoted 1 line
also for the 2.6.22.6. Is there any other dts file? Where can I find it?
=20
dts patch sent offline.
Thanks for the patch, Juergen. Received and applied, but still doesn't boot= .
I=B4m starting to suspect there should be something else...
Pedro.
Quoted 7 lines
Juergen
--=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
Pengutronix - Linux Solutions for Science and Industry
Handelsregister: Amtsgericht Hildesheim, HRA 2686
Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
_________________________________________________________________
Consigue el nuevo Windows Live Messenger
http://get.live.com/messenger/overview=
Re: [PATCH] phy: export phy_mii_ioctl
In reply to Pedro Luis D. L.Quoted 5 lines · Pedro Luis D. L.
Hello Jon,
I=B4m also working with a Phytec pcm030, but I can=B4t get it booted... Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over these=
with this new ones that Domen released.
Quoted 2 lines
The base kernel I=B4m using is 2.6.22.6 from kernel.org. Although I used the patch that creates
pcm030.cinarch/platforms/52xx/a=
nd compiled using this file, it gets halted at booting time.
Quoted 7 lines
Bytes transferred =3D 5091 (13e3 hex)
## Booting image at 00500000 ...Image Name: Linux-2.6.22.6 Created: 2007-09-19 8:53:02 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 1196911 Bytes =3D 1.1 MB
Quoted 7 lines
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at0x400000(No more output and boot is halted)
The root name of your device tree needs to match the name in pcm030.c pcm030_probe(void). If they don't match this happens.
--=20
Jon Smirl
[email protected]
RE: [PATCH] phy: export phy_mii_ioctl
Quoted 6 lines · Jon Smirl
Quoted 5 lines · Pedro Luis D. L.
Hello Jon,
I=B4m also working with a Phytec pcm030, but I can=B4t get it booted... Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over thes=
e with this new ones that Domen released.
Quoted 2 lines
Quoted 2 lines
The base kernel I=B4m using is 2.6.22.6 from kernel.org. Although I used the patch that creates
pcm030.cinarch/platforms/52xx/=
and compiled using this file, it gets halted at booting time.
Quoted 13 lines
Quoted 13 lines
Bytes transferred =3D 5091 (13e3 hex)
## Booting image at 00500000 ...Image Name: Linux-2.6.22.6 Created: 2007-09-19 8:53:02 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 1196911 Bytes =3D 1.1 MBLoad Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at0x400000
Quoted 2 lines
Quoted 1 line
(No more output and boot is halted)
=20
=20
I checked that and both are the same:
In pcm030.c:
static int __init pcm030_probe(void)
{
unsigned long node =3D of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(node, "pcm030"))
return 0;
return 1;
}define_machine(pcm030) {
.name =3D "pcm030",
.probe =3D pcm030_probe,
.setup_arch =3D pcm030_setup_arch,
.restart =3D mpc52xx_restart,
.init =3D pcm030_init,
.init_IRQ =3D mpc52xx_init_irq,
.get_irq =3D mpc52xx_get_irq,
.show_cpuinfo =3D pcm030_show_cpuinfo,
.calibrate_decr =3D generic_calibrate_decr,
};in pcm030.dts:
model =3D "pcm030"; compatible =3D "pcm030\0mpc5200b\0mpc52xx"; #address-cells =3D ; #size-cells =3D ;
And it still doesn=B4t boot...
I know it sounds hard, but... Can I skip the "if (!of_flat_dt_is_compatible= (node, "pcm030"))" line?
This pcm030.c and pcm030.dts files work and boot with 2.6.20 kernel...
Pedro Dominguez
=20
_________________________________________________________________
Consigue el nuevo Windows Live Messenger
http://get.live.com/messenger/overview=
RE: [PATCH] phy: export phy_mii_ioctl
In reply to Jon SmirlHello Jon,
I´m also working with a Phytec pcm030, but I can´t get it booted...
Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over these with this new ones that Domen released. The base kernel I´m using is 2.6.22.6 from kernel.org.
Although I used the patch that creates pcm030.c in arch/platforms/52xx/ and compiled using this file, it gets halted at booting time.
Bytes transferred = 5091 (13e3 hex)
## Booting image at 00500000 ...
Image Name: Linux-2.6.22.6 Created: 2007-09-19 8:53:02 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 1196911 Bytes = 1.1 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at 0x400000
(No more output and boot is halted)
Are you using any other patch for the platform or any other kernel, because I tried to apply these patches to a 2.6.20 kernel and are not successful.
Bests,
Pedro.
Quoted 11 lines
Date: Tue, 18 Sep 2007 15:29:09 -0400> From: [email protected]
To: [email protected]> Subject: Re: [PATCH] phy: exportphy_mii_ioctl
CC: [email protected]; [email protected]Quoted 4 lines · Domen Puncer
More testing and getting it to work properly on Phytec pcm030 would be great.>> Do we want to do anything about this?
[ 1.569657] net eth0: attached phy 0 to driver Generic PHY[ 2.576013] Sending DHCP requests .PHY: f0003000:00 - Link is Up - 100/Full> [ 4.612000] ., OK [ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, myaddress is 192.168.1.5
Quoted 8 lines
Quoted 1 line
What is happening is the printk for "PHY: f0003000:00 - Link is Up
- 100/Full" is done in an interrupt and it comes in the middle of the> kernel doing DHCP and printing ... without a CR.
Quoted 1 line
Two possible solutions, get rid of the link-up message or wait in in
the initial driver load until the link is up. Or we could leave it the way it is, but some people may report this as a bug.
Quoted 1 line
Quoted 1 line
--> Jon Smirl> [email protected]
_______________________________________________
Linuxppc-embedded mailing list> [email protected]> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
_________________________________________________________________
Busca desde cualquier página Web con una protección excepcional. Consigue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com
Jeff Garzik
AppliedRe: [PATCH] phy: export phy_mii_ioctl
In reply to Domen PuncerQuoted 4 lines · Domen Puncer
Export
phy_mii_ioctl, so network drivers can use it when built as modules too.Signed-off-by Domen Puncer <[email protected]>
applied
Hi Domen,
On Sun, Sep 02, 2007 at 09:41:43AM +0200, Domen Puncer wrote:
+ */
Quoted 29 lines
(quoted diff) +29
-0+static void fec_start(struct net_device *dev) +{ + struct fec_priv *priv = netdev_priv(dev); + struct mpc52xx_fec __iomem *fec = priv->fec; + u32 rcntrl; + u32 tcntrl; + u32 tmp; + + /* clear sticky error bits */ + tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF; + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp); + out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp); + + /* FIFOs will reset on fec_enable */ + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET); + + /* Set station address. */ + fec_set_paddr(dev, dev->dev_addr); + + fec_set_multicast_list(dev); + + /* set max frame len, enable flow control, select mii mode */ + rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ + rcntrl |= FEC_RCNTRL_FCE; + rcntrl |= MII_RCNTL_MODE; + if (priv->duplex == DUPLEX_FULL) + tcntrl = FEC_TCNTRL_FDEN; /* FD enable */ + else { + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
Review
Quoted 10 lines
(quoted diff) +10
-0+ tcntrl = 0; + } + out_be32(&fec->r_cntrl, rcntrl); + out_be32(&fec->x_cntrl, tcntrl); + + /* Clear any outstanding interrupt. */ + out_be32(&fec->ievent, 0xffffffff); + + /* Enable interrupts we wish to service. */ + out_be32(&fec->imask, FEC_IMASK_ENABLE);
This disables phy interrupts.
Quoted 9 lines
(quoted diff) +9
-0+static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct fec_mdio_priv *priv = bus->priv; + int tries = 100; + + u32 request = FEC_MII_READ_FRAME; + request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; + request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; +
Review
Quoted 10 lines
(quoted diff) +10
-0+ out_be32(&priv->regs->mii_data, request); + + /* wait for it to finish, this takes about 23 us on lite5200b */ + while (priv->completed == 0 && tries--) + udelay(5); + + priv->completed = 0; + + if (tries == 0) + return -ETIMEDOUT;
This does not work as expected. When a timeout occurs tries is -1 not 0, so the test above will never trigger.
Using --tries instead of tries-- reveals another bug. We get a timeout everytime now, because MII interrupts are accidently disabled in fec_start().
We cannot use a waitqueue or similar for waiting for the mii transfer because we are atomic here.
A simple fix is provided below. It removes the need for the interrupt handler in the phy handling routines. Anyway, it might be better to fix the phy layer not to use atomic contexts, so this patch might not be the way to go.
Regards,
Sascha
+
Review
Quoted 7 lines
(quoted diff) +4
-0+static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match) +{ + struct device *dev = &of->dev; + init_waitqueue_head(&priv->wq);
This waitqueue is never used. wake_up() is called in the interrupt handler, but noone ever sleeps on the queue.
--- drivers/net/fec_mpc52xx/fec.c | 7 +--- drivers/net/fec_mpc52xx/fec_phy.c | 59 +++++++------------------------------- 2 files changed, 15 insertions(+), 51 deletions(-)
drivers/net/fec_mpc52xx/fec.c +3 -4
@@ -265,7 +265,6 @@ static void fec_phy_hw_init(struct fec_preturn ;out_be32 (&fec->mii_speed, priv->phy_speed); -out_be32 (&fec->imask,in_be32 (&fec->imask) |FEC_IMASK_MII ); }static int fec_open (struct net_device *dev)
@@ -654,7 +653,7 @@ static void fec_hw_init(struct net_devicout_be32 (&fec->iaddr1,0x00000000 );/* No individual filter */ out_be32 (&fec->iaddr2,0x00000000 );/* No individual filter */ -/* set phy speed and enable MII interrupt +/* set phy speed. * this can't be done in phy driver, since it needs to be called * before fec stuff (even on resume) */ fec_phy_hw_init (priv);
@@ -730,8 +729,8 @@ static void fec_stop(struct net_device *struct mpc52xx_fec __iomem *fec = priv->fec;unsigned long timeout; -/* disable all but MII interrupt */ -out_be32 (&fec->imask,in_be32 (&fec->imask) &FEC_IMASK_MII ); +/* disable all interrupts */ +out_be32 (&fec->imask,0 );/* Disable the rx task. */ bcom_disable (priv->rx_dmatsk);
drivers/net/fec_mpc52xx/fec_phy.c +12 -47
131 lines not on this page · raw message
--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de
Quoted 2 lines · Sascha Hauer
Hi Domen,
Hi Sascha!
Quoted 37 lines · Domen Puncer
+ */
Quoted 34 lines
(quoted diff) +34
-0+static void fec_start(struct net_device *dev) +{ + struct fec_priv *priv = netdev_priv(dev); + struct mpc52xx_fec __iomem *fec = priv->fec; + u32 rcntrl; + u32 tcntrl; + u32 tmp; + + /* clear sticky error bits */ + tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF; + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp); + out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp); + + /* FIFOs will reset on fec_enable */ + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET); + + /* Set station address. */ + fec_set_paddr(dev, dev->dev_addr); + + fec_set_multicast_list(dev); + + /* set max frame len, enable flow control, select mii mode */ + rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ + rcntrl |= FEC_RCNTRL_FCE; + rcntrl |= MII_RCNTL_MODE; + if (priv->duplex == DUPLEX_FULL) + tcntrl = FEC_TCNTRL_FDEN; /* FD enable */ + else { + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */ + tcntrl = 0; + } + out_be32(&fec->r_cntrl, rcntrl); + out_be32(&fec->x_cntrl, tcntrl); +
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ /* Clear any outstanding interrupt. */ + out_be32(&fec->ievent, 0xffffffff); + + /* Enable interrupts we wish to service. */ + out_be32(&fec->imask, FEC_IMASK_ENABLE);This disables phy interrupts.
Right, oops.
Quoted 19 lines
Quoted 19 lines
(quoted diff) +17
-0+static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct fec_mdio_priv *priv = bus->priv; + int tries = 100; + + u32 request = FEC_MII_READ_FRAME; + request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; + request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; + + out_be32(&priv->regs->mii_data, request); + + /* wait for it to finish, this takes about 23 us on lite5200b */ + while (priv->completed == 0 && tries--) + udelay(5); + + priv->completed = 0; +
Quoted 8 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (tries == 0) + return -ETIMEDOUT;This does not work as expected. When a timeout occurs tries is -1 not 0, so the test above will never trigger.
Using --tries instead of tries-- reveals another bug. We get a timeout everytime now, because MII interrupts are accidently disabled infec_start().
Oh, double bug made it work! ;-)
Quoted 7 lines
We cannot use a waitqueue or similar for waiting for the mii transfer because we are atomic here.
A simple fix is provided below. It removes the need for the interrupt handler in the phy handling routines. Anyway, it might be better to fix the phy layer not to use atomic contexts, so this patch might not be the way to go.
Doh, looks like this was the problem with wq's, but I forgot to remove them, when I "fixed" the code.
Quoted 18 lines
Regards,
Sascha+
Review
Quoted 7 lines
(quoted diff) +4
-0+static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match) +{ + struct device *dev = &of->dev; + init_waitqueue_head(&priv->wq);This waitqueue is never used.
wake_up()is called in the interrupt handler, but noone ever sleeps on the queue.
Quoted 4 lines
--- drivers/net/fec_mpc52xx/fec.c | 7 +--- drivers/net/fec_mpc52xx/fec_phy.c | 59 +++++++------------------------------- 2 files changed, 15 insertions(+), 51 deletions(-)
The patch looks ok to me.
Domen
Quoted 1 line · Domen Puncer
The patch looks ok to me.
Short update: even with the patch, the driver doesn't work on an rt-preempt enabled kernel, or at least not reliable. It survives normal traffic and ping -f, but dies when running nmap against the box, with a set RFIFO_ERROR flag.
More research needs to be done.
Robert
Signature · 2 lines
Pengutronix - Linux Solutions for Science and Industry Entwicklungszentrum Nord http://www.pengutronix.de
Quoted 9 lines · Domen Puncer
Not for merge (yet)! But please do review.
fec_mpc52xxdriver (not in-tree, but floating around) isn't in very good shape, so I tried to change that.
Diff against original is quite big (fec_phy.cis completely rewritten) and confuzing, so I'm including wholedrivers/net/fec_mpc52xx/.I still have 'make CONFIG_FEC_MPC52xx_MDIO=3Dn compile and work' on my TODO, maybe even ethtool support.
Currently I'm trying with your fec driver and Sylvain Munaut's bestcomm dri= ver=20
*and* rt-preemt 2.6.23-rc8-rt1 and now I'm getting this error while stress= =20
test the network:
BUG: scheduling while atomic: softirq-timer/0/0x00000002/5, CPU#0 Call Trace: [c0309e00] [c0007ddc] show_stack+0x3c/0x194 (unreliable) [c0309e30] [c0017934] __schedule_bug+0x38/0x48 [c0309e40] [c01c8f24] __schedule+0x3e8/0x428 [c0309e70] [c01c96d4] schedule+0x54/0xf0 [c0309e80] [c01c9e8c] schedule_timeout+0x68/0xe4 [c0309ec0] [c00282dc] msleep+0x1c/0x34 [c0309ed0] [c0125fb8] fec_stop+0xbc/0x1a8 [c0309ef0] [c0126530] fec_reset+0x20/0xb0 [c0309f10] [c0127840] fec_tx_timeout+0x3c/0xa4 [c0309f30] [c016b5dc] dev_watchdog+0x13c/0x14c [c0309f50] [c0027c90] run_timer_softirq+0x2e4/0x444 [c0309f90] [c00239a4] ksoftirqd+0x134/0x214 [c0309fd0] [c0034d94] kthread+0x48/0x84 [c0309ff0] [c000f828] kernel_thread+0x44/0x60
Do you have an idea what happens?
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
Quoted 32 lines · Juergen Beisert
Quoted 9 lines · Domen Puncer
Not for merge (yet)! But please do review.
fec_mpc52xxdriver (not in-tree, but floating around) isn't in very good shape, so I tried to change that.
Diff against original is quite big (fec_phy.cis completely rewritten) and confuzing, so I'm including wholedrivers/net/fec_mpc52xx/.I still have 'make CONFIG_FEC_MPC52xx_MDIO=n compile and work' on my TODO, maybe even ethtool support.
Currently I'm trying with your fec driver and Sylvain Munaut's bestcomm driver *and* rt-preemt 2.6.23-rc8-rt1 and now I'm getting this error while stress test the network:
BUG: scheduling while atomic: softirq-timer/0/0x00000002/5, CPU#0 Call Trace: [c0309e00] [c0007ddc] show_stack+0x3c/0x194 (unreliable) [c0309e30] [c0017934] __schedule_bug+0x38/0x48 [c0309e40] [c01c8f24] __schedule+0x3e8/0x428 [c0309e70] [c01c96d4] schedule+0x54/0xf0 [c0309e80] [c01c9e8c] schedule_timeout+0x68/0xe4 [c0309ec0] [c00282dc] msleep+0x1c/0x34 [c0309ed0] [c0125fb8] fec_stop+0xbc/0x1a8 [c0309ef0] [c0126530] fec_reset+0x20/0xb0 [c0309f10] [c0127840] fec_tx_timeout+0x3c/0xa4 [c0309f30] [c016b5dc] dev_watchdog+0x13c/0x14c [c0309f50] [c0027c90] run_timer_softirq+0x2e4/0x444 [c0309f90] [c00239a4] ksoftirqd+0x134/0x214 [c0309fd0] [c0034d94] kthread+0x48/0x84 [c0309ff0] [c000f828] kernel_thread+0x44/0x60
Quoted 1 line
Do you have an idea what happens?
The call to msleep() is inside a block protected with
:#define in_interrupt() (irq_count())
if (!in_interrupt)
The stack trace looks like it is in a timer interrupt so shouldn't irq_count be non-zero?
Could there be some lack of coordination on irq_count and the timer tick with the preempt patch applied? Or does irq_count() not count soft irqs?
(!in_interrupt) may be the wrong way to protect this code.
Signature · 2 lines
Jon Smirl [email protected]
Quoted 11 lines · Jon Smirl
The call to
msleep()is inside a block protected with
:#definein_interrupt()(irq_count())
if (!in_interrupt)The stack trace looks like it is in a timer interrupt so shouldn't
irq_countbe non-zero?
Could there be some lack of coordination onirq_countand the timer tick with the preempt patch applied? Or doesirq_count()not count soft irqs?(!in_interrupt) may be the wrong way to protect this code.
I think in_atomic() is what you want.
-Scott
Quoted 13 lines · Scott Wood
Quoted 12 lines · Jon Smirl
The call to
msleep()is inside a block protected with:#define
in_interrupt()(irq_count())if (!in_interrupt)
The stack trace looks like it is in a timer interrupt so shouldn't
irq_countbe non-zero?
Could there be some lack of coordination onirq_countand the timer tick with the preempt patch applied? Or doesirq_count()not count soft irqs?
Quoted 3 lines
Quoted 1 line
(!in_interrupt) may be the wrong way to protect this code.
I think
in_atomic()is what you want.
I tried with in_atomic(). The BUG report is gone, but the problem still=20 exists.=20
While network stress testing:=20
[...]
NETDEV WATCHDOG: eth0: transmit timed out net eth0: transmit timed out net eth0: queues didn't drain net eth0: tx: index: 35, outdex: 36 net eth0: rx: index: 24, outdex: 25 PHY: f0003000:00 - Link is Down PHY: f0003000:00 - Link is Up - 100/Full
The link is up again, but any connection is dead (no answers to ping etc.).= =20
But the serial console is still working. I'm not sure if the RT-Preempt pat= ch=20
*causes* this behavior or only *discover* it. Any idea?
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=C2=A0Pengutronix - Linux Solutions for Science and Industry
=C2=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=C2=A0 =C2=A0 =C2=A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
Quoted 13 lines · Juergen Beisert
I tried with
in_atomic(). The BUG report is gone, but the problem still exists.While network stress testing:
[...]
NETDEV WATCHDOG: eth0: transmit timed out net eth0: transmit timed out net eth0: queues didn't drain net eth0: tx: index: 35, outdex: 36 net eth0: rx: index: 24, outdex: 25 PHY: f0003000:00 - Link is Down PHY: f0003000:00 - Link is Up - 100/Full
Quoted 1 line
The link is up again, but any connection is dead (no answers to ping etc.). But the serial console is still working. I'm not sure if the RT-Preempt patch *causes* this behavior or only *discover* it. Any idea?
I'd try looking at the driver's locking to make sure that it's correct.
-Scott
Hi,
Quoted 14 lines · Juergen Beisert
I tried with
in_atomic(). The BUG report is gone, but the problem still exists.While network stress testing:
[...]
NETDEV WATCHDOG: eth0: transmit timed out net eth0: transmit timed out net eth0: queues didn't drain net eth0: tx: index: 35, outdex: 36 net eth0: rx: index: 24, outdex: 25 PHY: f0003000:00 - Link is Down PHY: f0003000:00 - Link is Up - 100/Full
Quoted 3 lines
The link is up again, but any connection is dead (no answers to ping etc.). But the serial console is still working. I'm not sure if the RT-Preempt patch *causes* this behavior or only *discover* it. Any idea?
We finally solved this problem. It has nothing to do with locking though. The problem is that the bcom engine was not reenabled after resetting the fec. The following patch solves this.
Reenable the bestcom engine after resetting the mpc52xx fec controller.
--- drivers/net/fec_mpc52xx/fec.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/fec_mpc52xx/fec.c +3 -0
@@ -788,6 +788,9 @@ static void fec_reset(struct net_devicefec_alloc_rx_buffers (priv->rx_dmatsk); +bcom_enable (priv->rx_dmatsk); +bcom_enable (priv->tx_dmatsk); +fec_start (dev); }
Quoted 12 lines
Juergen
Signature · 9 lines
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de Pengutronix - Linux Solutions for Science and Industry Handelsregister: Amtsgericht Hildesheim, HRA 2686 Vertretung Sued/Muenchen, Germany Phone: +49-8766-939 228 | Fax: +49-5121-206917-9 _______________________________________________ Linuxppc-embedded mailing list [email protected] https://ozlabs.org/mailman/listinfo/linuxppc-embedded
Signature · 2 lines
Pengutronix - Linux Solutions for Science and Industry Entwicklungszentrum Nord http://www.pengutronix.de
Quoted 12 lines · Juergen Beisert
While network stress testing:
[...]
NETDEV WATCHDOG: eth0: transmit timed out net eth0: transmit timed out net eth0: queues didn't drain net eth0: tx: index: 35, outdex: 36 net eth0: rx: index: 24, outdex: 25 PHY: f0003000:00 - Link is Down PHY: f0003000:00 - Link is Up - 100/Full
Quoted 3 lines
The link is up again, but any connection is dead (no answers to ping etc.). But the serial console is still working. I'm not sure if the RT-Preempt patch *causes* this behavior or only *discover* it. Any idea?
While the previous patch I sent fixed the reset path for the fec controller this patch makes sure the chip does not have to be resetted. Problem was that we ran out of receive buffers when we nmapped our board (nmap sends lots of small packages in a short period of time). By increasing the number of rx buffers this problem does not appear anymore.
This patch produces a significant memory overhead to the driver of about 340k, so we might want to have this configurable as a module parameter. Let me know what the preferred way is, I can update the patch accordingly.
Sascha
Increase the number of RX packets in the fec_mpc52xx driver. This is necessary to no run out of rx packets when lots of small packets arrive in short time (for example when nmapping the board)
--- drivers/net/fec_mpc52xx/fec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/fec_mpc52xx/fec.h +1 -1
@@ -19,7 +19,7 @@/* Tunable constant */ /* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */ #define FEC_RX_BUFFER_SIZE 1522/* max receive packet size */ -#define FEC_RX_NUM_BD 64 +#define FEC_RX_NUM_BD 256#define FEC_TX_NUM_BD 64#define FEC_RESET_DELAY 50/* uS */
Signature · 2 lines
Pengutronix - Linux Solutions for Science and Industry Entwicklungszentrum Nord http://www.pengutronix.de
Quoted 10 lines · Sascha Hauer
While the previous patch I sent fixed the reset path for the fec controller this patch makes sure the chip does not have to be resetted. Problem was that we ran out of receive buffers when we nmapped our board (nmap sends lots of small packages in a short period of time). By increasing the number of rx buffers this problem does not appear anymore.
This patch produces a significant memory overhead to the driver of about 340k, so we might want to have this configurable as a module parameter. Let me know what the preferred way is, I can update the patch accordingly.
Is nmap sending UPD packets, why does the chip need to receive everything without dropping packets? It we do get into receive overrun, is everything recovering correctly?
As another test you could slow everything down by forcing the net to 10Mb.
It may be interesting to explore why the small packets aren't being processed fast enough, there could be other bugs lurking.
Signature · 2 lines
Jon Smirl [email protected]
Quoted 10 lines · Juergen Beisert
Quoted 9 lines · Domen Puncer
Not for merge (yet)! But please do review.
fec_mpc52xxdriver (not in-tree, but floating around) isn't in very good shape, so I tried to change that.
Diff against original is quite big (fec_phy.cis completely rewritten) and confuzing, so I'm including wholedrivers/net/fec_mpc52xx/.I still have 'make CONFIG_FEC_MPC52xx_MDIO=3Dn compile and work' on my TODO, maybe even ethtool support.
I add a few more debug outputs and now with this driver I can run a
$ nmap <ip>
from my host against the target and target's network stops always at the sa= me=20
point.
The last output from the driver is (with DEBUG macro defined):
net eth0: ievent: 08020000
and no further interrupt occurs anymore (I checked all three interrupt entr= y=20
functions)
nmap on host's side outputs:
Starting Nmap 4.20 ( http://insecure.org ) at 2007-09-28 16:56 CEST Interesting ports on 192.168.23.226:
Not shown: 852 filtered ports, 843 closed ports
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnet
Nmap finished: 1 IP address (1 host up) scanned in 14.120 seconds
But I can't run it a second time, as the network on target's side doesn't=20 respond. Any idea?
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
Quoted 2 lines · Juergen Beisert
But I can't run it a second time, as the network on target's side doesn't respond. Any idea?
Do the stress tests complete on a non-rt kernel?
That will narrow down the type of bug being looked for.
Signature · 2 lines
Jon Smirl [email protected]
Quoted 2 lines · Jon Smirl
Quoted 1 line · Juergen Beisert
But I can't run it a second time, as the network on target's side doesn=
't
Quoted 3 lines
Quoted 1 line
respond. Any idea?
Do the stress tests complete on a non-rt kernel?
I tried it again:
1) Target runs 2.6.23-rc8 without rt-preempt:
@host$ nmap 192.168.23.226
Starting Nmap 4.20 ( http://insecure.org ) at 2007-10-01 10:20 CEST Interesting ports on 192.168.23.226:
Not shown: 1695 closed ports
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnet
Nmap finished: 1 IP address (1 host up) scanned in 0.581 seconds
Target continues to work. Does not make a difference if the root filesystem=
is=20
jffs2 or nfs.
2) Same target runs 2.6.23-rc8-rt1
@host$ nmap 192.168.23.226
Starting Nmap 4.20 ( http://insecure.org ) at 2007-10-01 10:15 CEST Interesting ports on 192.168.23.226:
Not shown: 871 filtered ports, 824 closed ports
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnet
Nmap finished: 1 IP address (1 host up) scanned in 14.116 seconds
Network on target dies. But can be reactivated by an "ifconfig eth0 down;=20 ifconfig eth0 up". I included some printk statements into the fec.c source = to=20
see what interrupts are happen.
"r" means fec_rx_interrupt was entered, "t" means fec_tx_interrupt was ente= red=20
and "p" means fec_interrupt was entered. This is the output of the=20 nmap "attack" above:
rtrtrrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
at this point: fec_hard_start_xmit, stop queue
t
at this point: fec_tx_interrupt, wake queue
tp
<7>net eth0: ievent: 08020000
=2E..at this point the network is dead.
BTW: Without rt-preempt none of the wake/stop queue events and no=20 fec_interrupt occurs. I only see a long list of "r"s and "t"s...
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
Quoted 55 lines · Juergen Beisert
2) Same target runs 2.6.23-rc8-rt1
@host$ nmap 192.168.23.226Starting Nmap 4.20 ( http://insecure.org ) at 2007-10-01 10:15 CEST Interesting ports on 192.168.23.226:
Not shown: 871 filtered ports, 824 closed ports
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnetNmap finished: 1 IP address (1 host up) scanned in 14.116 seconds
Network on target dies. But can be reactivated by an "ifconfig eth0 down; ifconfig eth0 up". I included some printk statements into the
fec.csource to see what interrupts are happen."r" means
fec_rx_interruptwas entered, "t" meansfec_tx_interruptwas entered and "p" meansfec_interruptwas entered. This is the output of the nmap "attack" above:rtrtrrr
at this point:fec_hard_start_xmit, stop queue
rrt
at this point:fec_tx_interrupt, wake queue
ttrr
at this point:fec_hard_start_xmit, stop queue
rrt
at this point:fec_tx_interrupt, wake queue
ttrr
at this point:fec_hard_start_xmit, stop queue
rrt
at this point:fec_tx_interrupt, wake queue
ttrr
at this point:fec_hard_start_xmit, stop queue
rrt
at this point:fec_tx_interrupt, wake queue
ttrr
at this point:fec_hard_start_xmit, stop queue
rrt
at this point:fec_tx_interrupt, wake queue
ttrr
at this point:fec_hard_start_xmit, stop queue
rrt
at this point:fec_tx_interrupt, wake queue
ttr
at this point:fec_hard_start_xmit, stop queue
rrt
at this point:fec_tx_interrupt, wake queue
at this point:fec_hard_start_xmit, stop queue
t
at this point:fec_tx_interrupt, wake queue
tp
<7>net eth0: ievent: 08020000
Quoted 4 lines
...at this point the network is dead.
BTW: Without rt-preempt none of the wake/stop queue events and no
fec_interruptoccurs. I only see a long list of "r"s and "t"s...
We tried again with rt-preempt and increased the priority of FEC's three=20
interrupts: And now it survives the nmap "attack". But we don't know now if= =20
we only changed the behavior or fixed the bug?
BTW: Is it possible that fec_interrupt(() doesn' handle FEC_IEVENT_RFIFO_ER= ROR =20
and FEC_IEVENT_XFIFO_ERROR)) incorrectly? The lines makes more sense with t= he=20
following patch (but we are not sure about authors real intention).
@@ -506,7 +484,7 @@ static irqreturn_t fec_interrupt(int irq
out_be32(&fec->ievent, ievent); /* clear pending events */
=2D if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+ if (!(ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR))) {
if (ievent & ~FEC_IEVENT_TFINT)
dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
return IRQ_HANDLED;Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9