From: Domen Puncer <hidden> Date: 2007-08-10 09:51:58
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(-)
diff -pruN dummy/fec.c ./drivers/net/fec_mpc52xx/fec.c
@@ -0,0 +1,1002 @@+/*+*drivers/net/fec_mpc52xx/fec.c+*+*DriverfortheMPC5200FastEthernetController+*+*OriginallywrittenbyDaleFarnsworth<dfarnsworth@mvista.com>and+*nowmaintainedbySylvainMunaut<tnt@246tNt.com>+*+*Copyright(C)2007SylvainMunaut<tnt@246tNt.com>+*Copyrigth(C)2003-2004MontaVista,Software,Inc.+*+*ThisfileislicensedunderthetermsoftheGNUGeneralPublicLicense+*version2.Thisprogramislicensed"as is"withoutanywarrantyofany+*kind,whetherexpressorimplied.+*+*/++#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"++staticirqreturn_tfec_interrupt(int,void*);+staticirqreturn_tfec_rx_interrupt(int,void*);+staticirqreturn_tfec_tx_interrupt(int,void*);+staticstructnet_device_stats*fec_get_stats(structnet_device*);+staticvoidfec_set_multicast_list(structnet_device*dev);+staticvoidfec_hw_init(structnet_device*dev);+staticvoidfec_stop(structnet_device*dev);+staticvoidfec_start(structnet_device*dev);++staticu8mpc52xx_fec_mac_addr[6];+staticu8null_mac[6];++staticvoidfec_tx_timeout(structnet_device*dev)+{+structfec_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);+}++staticvoidfec_set_paddr(structnet_device*dev,u8*mac)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;++out_be32(&fec->paddr1,*(u32*)(&mac[0]));+out_be32(&fec->paddr2,(*(u16*)(&mac[4])<<16)|FEC_PADDR2_TYPE);+}++staticvoidfec_get_paddr(structnet_device*dev,u8*mac)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;++*(u32*)(&mac[0])=in_be32(&fec->paddr1);+*(u16*)(&mac[4])=in_be32(&fec->paddr2)>>16;+}++staticintfec_set_mac_address(structnet_device*dev,void*addr)+{+structsockaddr*sock=(structsockaddr*)addr;++memcpy(dev->dev_addr,sock->sa_data,dev->addr_len);++fec_set_paddr(dev,sock->sa_data);+return0;+}++staticvoidfec_free_rx_buffers(structbcom_task*s)+{+structsk_buff*skb;++while(!bcom_queue_empty(s)){+skb=bcom_retrieve_buffer(s,NULL,NULL);+kfree_skb(skb);+}+}++staticintfec_alloc_rx_buffers(structbcom_task*rxtsk)+{+while(!bcom_queue_full(rxtsk)){+structsk_buff*skb;+structbcom_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=(structbcom_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);+}++return0;+}++/* based on generic_adjust_link - fs_enet-main.c */+staticvoidfec_adjust_link(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structphy_device*phydev=priv->phydev;+intnew_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);+}++}elseif(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);+}+}++staticintfec_init_phy(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structphy_device*phydev;+charphy_id[BUS_ID_SIZE];++structdevice_node*dn,*phy_dn;+unsignedintphy_addr;+constphandle*ph;+constunsignedint*prop;+structresourceres;+intret;++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");+returnret;+}++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);+returnPTR_ERR(phydev);+}++phydev->advertising&=ADVERTISED_10baseT_Half|ADVERTISED_100baseT_Half;++priv->phydev=phydev;++return0;+}++staticintfec_open(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+interr=-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");+gotoout;+}+if(request_irq(priv->r_irq,&fec_rx_interrupt,IRQF_DISABLED,+DRIVER_NAME"_rx",dev)){+dev_err(&dev->dev,"rx interrupt request failed\n");+gotofree_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");+gotofree_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");+gotofree_irqs;+}++err=fec_init_phy(dev);+if(err){+dev_err(&dev->dev,"fec_init_phy failed\n");+gotofree_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);++return0;++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:++returnerr;+}++staticintfec_close(structnet_device*dev)+{+structfec_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);++return0;+}++/* This will only be invoked if your driver is _not_ in XOFF state.+*Whatthismeansisthatyouneednotcheckit,andthatthis+*invariantwillholdifyoumakesurethatthenetif_*_queue()+*callsaredoneatthepropertimes.+*/+staticintfec_hard_start_xmit(structsk_buff*skb,structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structbcom_fec_bd*bd;++if(bcom_queue_full(priv->tx_dmatsk)){+if(net_ratelimit())+dev_err(&dev->dev,"transmit queue overrun\n");+return1;+}++spin_lock_irq(&priv->lock);+dev->trans_start=jiffies;++bd=(structbcom_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);++return0;+}++/* This handles BestComm transmit task interrupts+*/+staticirqreturn_tfec_tx_interrupt(intirq,void*dev_id)+{+structnet_device*dev=dev_id;+structfec_priv*priv=netdev_priv(dev);++spin_lock(&priv->lock);++while(bcom_buffer_done(priv->tx_dmatsk)){+structsk_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);++returnIRQ_HANDLED;+}++staticirqreturn_tfec_rx_interrupt(intirq,void*dev_id)+{+structnet_device*dev=dev_id;+structfec_priv*priv=netdev_priv(dev);++while(bcom_buffer_done(priv->rx_dmatsk)){+structsk_buff*skb;+structsk_buff*rskb;+structbcom_fec_bd*bd;+u32status;++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=(structbcom_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,+*andremovetheold(withthepacket)*/+skb=dev_alloc_skb(FEC_RX_BUFFER_SIZE);+if(skb){+/* Process the received skb */+intlength=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=(structbcom_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);+}++returnIRQ_HANDLED;+}++staticirqreturn_tfec_interrupt(intirq,void*dev_id)+{+structnet_device*dev=dev_id;+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+u32ievent;++ievent=in_be32(&fec->ievent);++ievent&=~FEC_IEVENT_MII;/* mii is handled separately */+if(!ievent)+returnIRQ_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);+returnIRQ_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);+returnIRQ_HANDLED;+}++/*+*Getthecurrentstatistics.+*Thismaybecalledwiththecardopenorclosed.+*/+staticstructnet_device_stats*fec_get_stats(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structnet_device_stats*stats=&priv->stats;+structmpc52xx_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);++returnstats;+}++/*+*ReadMIBcountersinordertoresetthem,+*thenzeroallthestatsfieldsinmemory+*/+staticvoidfec_reset_stats(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_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));+}++/*+*Setorclearthemulticastfilterforthisadaptor.+*/+staticvoidfec_set_multicast_list(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+u32rx_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{+u32crc;+inti;+structdev_mc_list*dmi;+u32gaddr1=0x00000000;+u32gaddr2=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);+}+}+}++staticvoid__initfec_str2mac(char*str,unsignedchar*mac)+{+inti;+u64val64;++val64=simple_strtoull(str,NULL,16);++for(i=0;i<6;i++)+mac[5-i]=val64>>(i*8);+}++staticint__initmpc52xx_fec_mac_setup(char*mac_address)+{+fec_str2mac(mac_address,mpc52xx_fec_mac_addr);+return0;+}++/* XXX do we need this? */+__setup("mpc52xx-mac=",mpc52xx_fec_mac_setup);++/**+*fec_hw_init+*@dev:networkdevice+*+*Setupvarioushardwaresetting,onlyneededonceonstart+*/+staticvoidfec_hw_init(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+inti;++/* 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+*lowservicerequestwillbedeassertedwhenthere's<4*7bytesinfifo+*/+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+*thiscan'tbedoneinphydriver,sinceitneedstobecalled+*beforefecstuff(evenonresume)*/+set_phy_speed(fec,priv->phy_speed);+out_be32(&fec->imask,in_be32(&fec->imask)|FEC_IMASK_MII);+}++/**+*fec_start+*@dev:networkdevice+*+*ThisfunctioniscalledtostartorrestarttheFECduringalink+*change.Thishappensonfifoerrorsorwhenswitchingbetweenhalf+*andfullduplex.+*/+staticvoidfec_start(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+u32rcntrl;+u32tcntrl;+u32tmp;++/* 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:networkdevice+*+*stopallactivityonfecandemptydmabuffers+*/+staticvoidfec_stop(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+unsignedlongtimeout;++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;+}++staticintfec_ioctl(structnet_device*dev,structifreq*rq,intcmd)+{+structfec_priv*priv=netdev_priv(dev);+structmii_ioctl_data*mii=(structmii_ioctl_data*)&rq->ifr_data;++returnphy_mii_ioctl(priv->phydev,mii,cmd);+}++/* ======================================================================== */+/* OF Driver */+/* ======================================================================== */++staticint__devinit+mpc52xx_fec_probe(structof_device*op,conststructof_device_id*match)+{+intrv;+structnet_device*ndev;+structfec_priv*priv=NULL;+structresourcemem;++phys_addr_trx_fifo;+phys_addr_ttx_fifo;++/* Get the ether ndev & it's private zone */+ndev=alloc_etherdev(sizeof(structfec_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_ERRDRIVER_NAME": "+"Error while parsing device node resource\n");+returnrv;+}+if((mem.end-mem.start+1)!=sizeof(structmpc52xx_fec)){+printk(KERN_ERRDRIVER_NAME+" - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",+(unsignedlong)(mem.end-mem.start+1),sizeof(structmpc52xx_fec));+return-EINVAL;+}++if(!request_mem_region(mem.start,sizeof(structmpc52xx_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(structmpc52xx_fec));++if(!priv->fec){+rv=-ENOMEM;+gotoprobe_error;+}++/* Bestcomm init */+rx_fifo=ndev->base_addr+offsetof(structmpc52xx_fec,rfifo_data);+tx_fifo=ndev->base_addr+offsetof(structmpc52xx_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_ERRDRIVER_NAME": Can not init SDMA tasks\n");+rv=-ENOMEM;+gotoprobe_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)+gotoprobe_error;++/* We're done ! */+dev_set_drvdata(&op->dev,ndev);++return0;+++/* 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(structmpc52xx_fec));++free_netdev(ndev);++returnrv;+}++staticint+mpc52xx_fec_remove(structof_device*op)+{+structnet_device*ndev;+structfec_priv*priv;++ndev=dev_get_drvdata(&op->dev);+if(!ndev)+return0;+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(structmpc52xx_fec));++free_netdev(ndev);++dev_set_drvdata(&op->dev,NULL);+return0;+}++#ifdef CONFIG_PM+staticintmpc52xx_fec_of_suspend(structof_device*op,pm_message_tstate)+{+structnet_device*dev=dev_get_drvdata(&op->dev);++if(netif_running(dev))+fec_close(dev);++return0;+}++staticintmpc52xx_fec_of_resume(structof_device*op)+{+structnet_device*dev=dev_get_drvdata(&op->dev);++fec_hw_init(dev);+fec_reset_stats(dev);++if(netif_running(dev))+fec_open(dev);++return0;+}+#endif++staticstructof_device_idmpc52xx_fec_match[]={+{+.type="network",+.compatible="mpc5200-fec",+},+{}+};++MODULE_DEVICE_TABLE(of,mpc52xx_fec_match);++staticstructof_platform_drivermpc52xx_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 */+/* ======================================================================== */++staticint__init+mpc52xx_fec_init(void)+{+intret;+if((ret=fec_mdio_init())){+printk(KERN_ERR"%s: %i fec_mdio_init failed\n",__func__,__LINE__);+returnret;+}++returnof_register_platform_driver(&mpc52xx_fec_driver);+}++staticvoid__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");+
@@ -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"++structfec_mdio_priv{+intcompleted;+wait_queue_head_twq;+structmpc52xx_fec__iomem*regs;+intirq;+};++staticintfec_mdio_read(structmii_bus*bus,intphy_id,intreg)+{+structfec_mdio_priv*priv=bus->priv;+inttries=100;++u32request=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;++returnin_be32(&priv->regs->mii_data)&FEC_MII_DATA_DATAMSK;+}++staticintfec_mdio_write(structmii_bus*bus,intphy_id,intreg,u16data)+{+structfec_mdio_priv*priv=bus->priv;+u32value=data;+inttries=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;++return0;+}++staticirqreturn_tfec_mdio_interrupt(intirq,void*dev_id)+{+structfec_mdio_priv*priv=dev_id;+structmpc52xx_fec__iomem*fec;+intievent;++fec=priv->regs;+ievent=in_be32(&fec->ievent);++ievent&=FEC_IEVENT_MII;+if(!ievent)+returnIRQ_NONE;++out_be32(&fec->ievent,ievent);++priv->completed=1;+wake_up(&priv->wq);++returnIRQ_HANDLED;+}++staticintfec_mdio_probe(structof_device*of,conststructof_device_id*match)+{+structdevice*dev=&of->dev;+structdevice_node*np=of->node;+structdevice_node*child=NULL;+structmii_bus*bus;+structfec_mdio_priv*priv;+structresourceres={};+interr;+inti;++bus=kzalloc(sizeof(*bus),GFP_KERNEL);+if(bus==NULL)+return-ENOMEM;+priv=kzalloc(sizeof(*priv),GFP_KERNEL);+if(priv==NULL){+err=-ENOMEM;+gotoout_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;+gotoout_free;+}+for(i=0;i<PHY_MAX_ADDR;i++)+bus->irq[i]=PHY_POLL;++while((child=of_get_next_child(np,child))!=NULL){+intirq=irq_of_parse_and_map(child,0);+if(irq!=NO_IRQ){+constu32*id=of_get_property(child,"reg",NULL);+bus->irq[*id]=irq;+}+}++/* setup registers */+err=of_address_to_resource(np,0,&res);+if(err)+gotoout_free;+priv->regs=ioremap(res.start,res.end-res.start+1);+if(priv->regs==NULL){+err=-ENOMEM;+gotoout_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);+gotoout_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)+gotoout_free_irq;++return0;++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);++returnerr;+}++staticintfec_mdio_remove(structof_device*of)+{+structdevice*dev=&of->dev;+structmii_bus*bus=dev_get_drvdata(dev);+structfec_mdio_priv*priv=bus->priv;+inti;++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);++return0;+}+++staticstructof_device_idfec_mdio_match[]={+{+.type="mdio",+.compatible="mpc5200b-fec-phy",+},+{},+};++staticstructof_platform_driverfec_mdio_driver={+.name="mpc5200b-fec-phy",+.probe=fec_mdio_probe,+.remove=fec_mdio_remove,+.match_table=fec_mdio_match,+};+++int__initfec_mdio_init(void)+{+returnof_register_platform_driver(&fec_mdio_driver);+}++void__exitfec_mdio_exit(void)+{+of_unregister_platform_driver(&fec_mdio_driver);+}
@@ -365,10 +365,26 @@ethernet@3000{device_type="network";compatible="mpc5200b-fec\0mpc5200-fec";-reg=<3000800>;+reg=<3000400>;mac-address=[020304050607];// Bad!interrupts=<250>;interrupt-parent=<&mpc5200_pic>;+phy-handle=<&phy0>;+};++mdio@3000{+#address-cells=<1>;+#size-cells=<0>;+device_type="mdio";+compatible="mpc5200b-fec-phy";+reg=<3000400>;// fec range, since we need to setup fec interrupts+interrupts=<250>;// 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{
From: Arnaldo Carvalho de Melo <hidden> Date: 2007-08-10 13:02:38
Em Fri, Aug 10, 2007 at 11:51:53AM +0200, Domen Puncer escreveu:
quoted hunk
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(-)
diff -pruN dummy/fec.c ./drivers/net/fec_mpc52xx/fec.c
@@ -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"++structfec_mdio_priv{+intcompleted;+wait_queue_head_twq;+structmpc52xx_fec__iomem*regs;+intirq;+};++staticintfec_mdio_read(structmii_bus*bus,intphy_id,intreg)+{+structfec_mdio_priv*priv=bus->priv;+inttries=100;++u32request=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;++returnin_be32(&priv->regs->mii_data)&FEC_MII_DATA_DATAMSK;+}++staticintfec_mdio_write(structmii_bus*bus,intphy_id,intreg,u16data)+{+structfec_mdio_priv*priv=bus->priv;+u32value=data;+inttries=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;++return0;+}++staticirqreturn_tfec_mdio_interrupt(intirq,void*dev_id)+{+structfec_mdio_priv*priv=dev_id;+structmpc52xx_fec__iomem*fec;+intievent;++fec=priv->regs;+ievent=in_be32(&fec->ievent);++ievent&=FEC_IEVENT_MII;+if(!ievent)+returnIRQ_NONE;++out_be32(&fec->ievent,ievent);++priv->completed=1;+wake_up(&priv->wq);++returnIRQ_HANDLED;+}++staticintfec_mdio_probe(structof_device*of,conststructof_device_id*match)+{+structdevice*dev=&of->dev;+structdevice_node*np=of->node;+structdevice_node*child=NULL;+structmii_bus*bus;+structfec_mdio_priv*priv;+structresourceres={};+interr;+inti;++bus=kzalloc(sizeof(*bus),GFP_KERNEL);+if(bus==NULL)+return-ENOMEM;+priv=kzalloc(sizeof(*priv),GFP_KERNEL);+if(priv==NULL){+err=-ENOMEM;+gotoout_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;+gotoout_free;+}+for(i=0;i<PHY_MAX_ADDR;i++)+bus->irq[i]=PHY_POLL;++while((child=of_get_next_child(np,child))!=NULL){+intirq=irq_of_parse_and_map(child,0);+if(irq!=NO_IRQ){+constu32*id=of_get_property(child,"reg",NULL);+bus->irq[*id]=irq;+}+}++/* setup registers */+err=of_address_to_resource(np,0,&res);+if(err)+gotoout_free;+priv->regs=ioremap(res.start,res.end-res.start+1);+if(priv->regs==NULL){+err=-ENOMEM;+gotoout_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);+gotoout_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)+gotoout_free_irq;++return0;++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);++returnerr;+}++staticintfec_mdio_remove(structof_device*of)+{+structdevice*dev=&of->dev;+structmii_bus*bus=dev_get_drvdata(dev);+structfec_mdio_priv*priv=bus->priv;+inti;++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);++return0;+}+++staticstructof_device_idfec_mdio_match[]={+{+.type="mdio",+.compatible="mpc5200b-fec-phy",+},+{},+};++staticstructof_platform_driverfec_mdio_driver={+.name="mpc5200b-fec-phy",+.probe=fec_mdio_probe,+.remove=fec_mdio_remove,+.match_table=fec_mdio_match,+};+++int__initfec_mdio_init(void)+{+returnof_register_platform_driver(&fec_mdio_driver);+}++void__exitfec_mdio_exit(void)+{+of_unregister_platform_driver(&fec_mdio_driver);+}
@@ -365,10 +365,26 @@ethernet@3000{device_type="network";compatible="mpc5200b-fec\0mpc5200-fec";-reg=<3000800>;+reg=<3000400>;mac-address=[020304050607];// Bad!interrupts=<250>;interrupt-parent=<&mpc5200_pic>;+phy-handle=<&phy0>;+};++mdio@3000{+#address-cells=<1>;+#size-cells=<0>;+device_type="mdio";+compatible="mpc5200b-fec-phy";+reg=<3000400>;// fec range, since we need to setup fec interrupts+interrupts=<250>;// 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{
@@ -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)externstructbcom_task*-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
--- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts+++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
+ 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>;
+ };
};
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
From: Matt Sealey <hidden> Date: 2007-08-19 15:38:21
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.
--
Matt Sealey [off-list ref]
Genesi, Manager, Developer Relations
Domen Puncer wrote:
--- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts+++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
+ 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>;
+ };
};
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
From: Domen Puncer <hidden> Date: 2007-08-20 08:31:42
On 19/08/07 16:39 +0100, Matt Sealey wrote:
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>
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.
--- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts+++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
+ 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>;
+ };
};
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
From: Domen Puncer <hidden> Date: 2007-08-20 13:17:06
On 20/08/07 10:31 +0200, Domen Puncer wrote:
On 19/08/07 16:39 +0100, Matt Sealey wrote:
quoted
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.
...
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
From: Matt Sealey <hidden> Date: 2007-08-20 19:01:38
Are you sure this is correct for the Efika?
The MPC5200B manual makes a decent distinction between MII operation and
straight MDIO?
--
Matt Sealey [off-list ref]
Genesi, Manager, Developer Relations
Domen Puncer wrote:
On 20/08/07 10:31 +0200, Domen Puncer wrote:
quoted
On 19/08/07 16:39 +0100, Matt Sealey wrote:
quoted
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
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
From: Domen Puncer <hidden> Date: 2007-08-21 05:49:58
On 20/08/07 20:02 +0100, Matt Sealey wrote:
Are you sure this is correct for the Efika?
It works (tm).
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
--
Matt Sealey [off-list ref]
Genesi, Manager, Developer Relations
Domen Puncer wrote:
quoted
On 20/08/07 10:31 +0200, Domen Puncer wrote:
quoted
On 19/08/07 16:39 +0100, Matt Sealey wrote:
quoted
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
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
From: Domen Puncer <hidden> Date: 2007-09-03 14:43:29
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
(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).
Signed-off-by: Domen Puncer <redacted>
---
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(-)
Index: linux.git/drivers/net/Kconfig
===================================================================
@@ -306,10 +306,26 @@ethernet@3000{device_type="network";compatible="mpc5200b-fec\0mpc5200-fec";-reg=<3000800>;+reg=<3000400>;mac-address=[020304050607];// Bad!interrupts=<250>;interrupt-parent=<&mpc5200_pic>;+phy-handle=<&phy0>;+};++mdio@3000{+#address-cells=<1>;+#size-cells=<0>;+device_type="mdio";+compatible="mpc5200b-fec-phy";+reg=<3000400>;// fec range, since we need to setup fec interrupts+interrupts=<250>;// 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{
@@ -0,0 +1,1127 @@+/*+*drivers/drivers/net/fec_mpc52xx/fec.c+*+*DriverfortheMPC5200FastEthernetController+*+*OriginallywrittenbyDaleFarnsworth<dfarnsworth@mvista.com>and+*nowmaintainedbySylvainMunaut<tnt@246tNt.com>+*+*Copyright(C)2007DomenPuncer,Telargo,Inc.+*Copyright(C)2007SylvainMunaut<tnt@246tNt.com>+*Copyright(C)2003-2004MontaVista,Software,Inc.+*+*ThisfileislicensedunderthetermsoftheGNUGeneralPublicLicense+*version2.Thisprogramislicensed"as is"withoutanywarrantyofany+*kind,whetherexpressorimplied.+*+*/++#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"++staticirqreturn_tfec_interrupt(int,void*);+staticirqreturn_tfec_rx_interrupt(int,void*);+staticirqreturn_tfec_tx_interrupt(int,void*);+staticstructnet_device_stats*fec_get_stats(structnet_device*);+staticvoidfec_set_multicast_list(structnet_device*dev);+staticvoidfec_hw_init(structnet_device*dev);+staticvoidfec_stop(structnet_device*dev);+staticvoidfec_start(structnet_device*dev);+staticvoidfec_reset(structnet_device*dev);++staticu8mpc52xx_fec_mac_addr[6];+staticconstu8null_mac[6];++staticvoidfec_tx_timeout(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);++dev_warn(&dev->dev,"transmit timed out\n");++fec_reset(dev);++priv->stats.tx_errors++;++if(!priv->tx_full)+netif_wake_queue(dev);+}++staticvoidfec_set_paddr(structnet_device*dev,u8*mac)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;++out_be32(&fec->paddr1,*(u32*)(&mac[0]));+out_be32(&fec->paddr2,(*(u16*)(&mac[4])<<16)|FEC_PADDR2_TYPE);+}++staticvoidfec_get_paddr(structnet_device*dev,u8*mac)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;++*(u32*)(&mac[0])=in_be32(&fec->paddr1);+*(u16*)(&mac[4])=in_be32(&fec->paddr2)>>16;+}++staticintfec_set_mac_address(structnet_device*dev,void*addr)+{+structsockaddr*sock=addr;++memcpy(dev->dev_addr,sock->sa_data,dev->addr_len);++fec_set_paddr(dev,sock->sa_data);+return0;+}++staticvoidfec_free_rx_buffers(structbcom_task*s)+{+structsk_buff*skb;++while(!bcom_queue_empty(s)){+skb=bcom_retrieve_buffer(s,NULL,NULL);+kfree_skb(skb);+}+}++staticintfec_alloc_rx_buffers(structbcom_task*rxtsk)+{+while(!bcom_queue_full(rxtsk)){+structsk_buff*skb;+structbcom_fec_bd*bd;++skb=dev_alloc_skb(FEC_RX_BUFFER_SIZE);+if(skb==NULL)+return-EAGAIN;++/* zero out the initial receive buffers to aid debugging */+memset(skb->data,0,FEC_RX_BUFFER_SIZE);++bd=(structbcom_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);+}++return0;+}++#ifdef CONFIG_FEC_MPC52xx_MDIO+/* based on generic_adjust_link from fs_enet-main.c */+staticvoidfec_adjust_link(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structphy_device*phydev=priv->phydev;+intnew_state=0;++if(phydev->link!=PHY_DOWN){+if(phydev->duplex!=priv->duplex){+structmpc52xx_fec__iomem*fec=priv->fec;+u32rcntrl;+u32tcntrl;++new_state=1;+priv->duplex=phydev->duplex;++rcntrl=in_be32(&fec->r_cntrl);+tcntrl=in_be32(&fec->x_cntrl);++rcntrl&=~FEC_RCNTRL_DRT;+tcntrl&=~FEC_TCNTRL_FDEN;+if(phydev->duplex==DUPLEX_FULL)+tcntrl|=FEC_TCNTRL_FDEN;/* FD enable */+else+rcntrl|=FEC_RCNTRL_DRT;/* disable Rx on Tx (HD) */++out_be32(&fec->r_cntrl,rcntrl);+out_be32(&fec->x_cntrl,tcntrl);+}++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);+}++}elseif(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);+}++staticintfec_init_phy(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structphy_device*phydev;+charphy_id[BUS_ID_SIZE];++structdevice_node*dn,*phy_dn;+unsignedintphy_addr;+constphandle*ph;+constunsignedint*prop;+structresourceres;+intret;++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");+returnret;+}++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)){+dev_err(&dev->dev,"phy_connect failed\n");+returnPTR_ERR(phydev);+}+dev_info(&dev->dev,"attached phy %i to driver %s\n",+phydev->addr,phydev->drv->name);++priv->phydev=phydev;++return0;+}++staticintfec_phy_start(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+interr;++err=fec_init_phy(dev);+if(err){+dev_err(&dev->dev,"fec_init_phy failed\n");+returnerr;+}++/* reset phy - this also wakes it from PDOWN */+phy_write(priv->phydev,MII_BMCR,BMCR_RESET);+phy_start(priv->phydev);++return0;+}++staticvoidfec_phy_stop(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);++phy_disconnect(priv->phydev);+/* power down phy */+phy_stop(priv->phydev);+phy_write(priv->phydev,MII_BMCR,BMCR_PDOWN);+}++staticintfec_phy_mii_ioctl(structfec_priv*priv,+structmii_ioctl_data*mii_data,intcmd)+{+returnphy_mii_ioctl(priv->phydev,mii_data,cmd);+}++staticvoidfec_phy_hw_init(structfec_priv*priv)+{+structmpc52xx_fec__iomem*fec=priv->fec;++out_be32(&fec->mii_speed,priv->phy_speed);+out_be32(&fec->imask,in_be32(&fec->imask)|FEC_IMASK_MII);+}+#else+staticinlineintfec_phy_start(structnet_device*dev){return0;}+staticinlinevoidfec_phy_stop(structnet_device*dev){}+staticinlineintfec_phy_mii_ioctl(structfec_priv*priv,+structmii_ioctl_data*mii_data,intcmd){return-ENOTSUPP;}+staticinlinevoidfec_phy_hw_init(structfec_priv*priv){}+#endif++staticintfec_open(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+interr=-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");+gotoout;+}+if(request_irq(priv->r_irq,&fec_rx_interrupt,IRQF_DISABLED,+DRIVER_NAME"_rx",dev)){+dev_err(&dev->dev,"rx interrupt request failed\n");+gotofree_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");+gotofree_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");+gotofree_irqs;+}++err=fec_phy_start(dev);+if(err)+gotofree_skbs;++bcom_enable(priv->rx_dmatsk);+bcom_enable(priv->tx_dmatsk);++fec_start(dev);++netif_start_queue(dev);++return0;++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:++returnerr;+}++staticintfec_close(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);++netif_stop_queue(dev);++fec_stop(dev);++fec_free_rx_buffers(priv->rx_dmatsk);++free_irq(dev->irq,dev);+free_irq(priv->r_irq,dev);+free_irq(priv->t_irq,dev);++fec_phy_stop(dev);++return0;+}++/* This will only be invoked if your driver is _not_ in XOFF state.+*Whatthismeansisthatyouneednotcheckit,andthatthis+*invariantwillholdifyoumakesurethatthenetif_*_queue()+*callsaredoneatthepropertimes.+*/+staticintfec_hard_start_xmit(structsk_buff*skb,structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structbcom_fec_bd*bd;++if(bcom_queue_full(priv->tx_dmatsk)){+if(net_ratelimit())+dev_err(&dev->dev,"transmit queue overrun\n");+return1;+}++spin_lock_irq(&priv->lock);+dev->trans_start=jiffies;++bd=(structbcom_fec_bd*)+bcom_prepare_next_buffer(priv->tx_dmatsk);++bd->status=skb->len|BCOM_FEC_TX_BD_TFD|BCOM_FEC_TX_BD_TC;+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);++return0;+}++/* This handles BestComm transmit task interrupts+*/+staticirqreturn_tfec_tx_interrupt(intirq,void*dev_id)+{+structnet_device*dev=dev_id;+structfec_priv*priv=netdev_priv(dev);++spin_lock(&priv->lock);++while(bcom_buffer_done(priv->tx_dmatsk)){+structsk_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);++returnIRQ_HANDLED;+}++staticirqreturn_tfec_rx_interrupt(intirq,void*dev_id)+{+structnet_device*dev=dev_id;+structfec_priv*priv=netdev_priv(dev);++while(bcom_buffer_done(priv->rx_dmatsk)){+structsk_buff*skb;+structsk_buff*rskb;+structbcom_fec_bd*bd;+u32status;++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=(structbcom_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,+*andremovetheold(withthepacket)*/+skb=dev_alloc_skb(FEC_RX_BUFFER_SIZE);+if(skb){+/* Process the received skb */+intlength=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=(structbcom_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);+}++returnIRQ_HANDLED;+}++staticirqreturn_tfec_interrupt(intirq,void*dev_id)+{+structnet_device*dev=dev_id;+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+u32ievent;++ievent=in_be32(&fec->ievent);++ievent&=~FEC_IEVENT_MII;/* mii is handled separately */+if(!ievent)+returnIRQ_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);+returnIRQ_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_reset(dev);++netif_wake_queue(dev);+returnIRQ_HANDLED;+}++/*+*Getthecurrentstatistics.+*Thismaybecalledwiththecardopenorclosed.+*/+staticstructnet_device_stats*fec_get_stats(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structnet_device_stats*stats=&priv->stats;+structmpc52xx_fec__iomem*fec=priv->fec;++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);++returnstats;+}++/*+*ReadMIBcountersinordertoresetthem,+*thenzeroallthestatsfieldsinmemory+*/+staticvoidfec_reset_stats(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;++out_be32(&fec->mib_control,FEC_MIB_DISABLE);+memset_io(&fec->rmon_t_drop,0,(__forceu32)&fec->reserved10-+(__forceu32)&fec->rmon_t_drop);+out_be32(&fec->mib_control,0);++memset(&priv->stats,0,sizeof(priv->stats));+}++/*+*Setorclearthemulticastfilterforthisadaptor.+*/+staticvoidfec_set_multicast_list(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+u32rx_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{+u32crc;+inti;+structdev_mc_list*dmi;+u32gaddr1=0x00000000;+u32gaddr2=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);+}+}+}++staticvoid__initfec_str2mac(char*str,unsignedchar*mac)+{+inti;+u64val64;++val64=simple_strtoull(str,NULL,16);++for(i=0;i<6;i++)+mac[5-i]=val64>>(i*8);+}++staticint__initmpc52xx_fec_mac_setup(char*mac_address)+{+fec_str2mac(mac_address,mpc52xx_fec_mac_addr);+return0;+}++__setup("mpc52xx-mac=",mpc52xx_fec_mac_setup);++/**+*fec_hw_init+*@dev:networkdevice+*+*Setupvarioushardwaresetting,onlyneededonceonstart+*/+staticvoidfec_hw_init(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+inti;++/* 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+*lowservicerequestwillbedeassertedwhenthere's<4*7bytesinfifo+*/+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+*thiscan'tbedoneinphydriver,sinceitneedstobecalled+*beforefecstuff(evenonresume)*/+fec_phy_hw_init(priv);+}++/**+*fec_start+*@dev:networkdevice+*+*ThisfunctioniscalledtostartorrestarttheFECduringalink+*change.Thishappensonfifoerrorsorwhenswitchingbetweenhalf+*andfullduplex.+*/+staticvoidfec_start(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+u32rcntrl;+u32tcntrl;+u32tmp;++/* 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:networkdevice+*+*stopallactivityonfecandemptydmabuffers+*/+staticvoidfec_stop(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;+unsignedlongtimeout;++/* disable all but MII interrupt */+out_be32(&fec->imask,in_be32(&fec->imask)&FEC_IMASK_MII);++/* Disable the rx task. */+bcom_disable(priv->rx_dmatsk);++/* Wait for tx queue to drain, but only if we're in process context */+if(!in_interrupt()){+timeout=jiffies+msecs_to_jiffies(2000);+while(time_before(jiffies,timeout)&&+!bcom_queue_empty(priv->tx_dmatsk))+msleep(100);++if(time_after_eq(jiffies,timeout))+dev_err(&dev->dev,"queues didn't drain\n");+#if 1+if(time_after_eq(jiffies,timeout)){+dev_err(&dev->dev," tx: index: %i, outdex: %i\n",+priv->tx_dmatsk->index,+priv->tx_dmatsk->outdex);+dev_err(&dev->dev," rx: index: %i, outdex: %i\n",+priv->rx_dmatsk->index,+priv->rx_dmatsk->outdex);+}+#endif+}++bcom_disable(priv->tx_dmatsk);++/* Stop FEC */+out_be32(&fec->ecntrl,in_be32(&fec->ecntrl)&~FEC_ECNTRL_ETHER_EN);++return;+}++/* reset fec and bestcomm tasks */+staticvoidfec_reset(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+structmpc52xx_fec__iomem*fec=priv->fec;++fec_stop(dev);++out_be32(&fec->rfifo_status,in_be32(&fec->rfifo_status));+out_be32(&fec->reset_cntrl,FEC_RESET_CNTRL_RESET_FIFO);++fec_free_rx_buffers(priv->rx_dmatsk);++fec_hw_init(dev);++phy_stop(priv->phydev);+phy_write(priv->phydev,MII_BMCR,BMCR_RESET);+phy_start(priv->phydev);++bcom_fec_rx_reset(priv->rx_dmatsk);+bcom_fec_tx_reset(priv->tx_dmatsk);++fec_alloc_rx_buffers(priv->rx_dmatsk);++fec_start(dev);+}+++/* ethtool interface */+staticvoidfec_get_drvinfo(structnet_device*dev,+structethtool_drvinfo*info)+{+strcpy(info->driver,DRIVER_NAME);+}++staticintfec_get_settings(structnet_device*dev,structethtool_cmd*cmd)+{+structfec_priv*priv=netdev_priv(dev);+returnphy_ethtool_gset(priv->phydev,cmd);+}++staticintfec_set_settings(structnet_device*dev,structethtool_cmd*cmd)+{+structfec_priv*priv=netdev_priv(dev);+returnphy_ethtool_sset(priv->phydev,cmd);+}++staticu32fec_get_msglevel(structnet_device*dev)+{+structfec_priv*priv=netdev_priv(dev);+returnpriv->msg_enable;+}++staticvoidfec_set_msglevel(structnet_device*dev,u32level)+{+structfec_priv*priv=netdev_priv(dev);+priv->msg_enable=level;+}++staticconststructethtool_opsfec_ethtool_ops={+.get_drvinfo=fec_get_drvinfo,+.get_settings=fec_get_settings,+.set_settings=fec_set_settings,+.get_link=ethtool_op_get_link,+.get_msglevel=fec_get_msglevel,+.set_msglevel=fec_set_msglevel,+};+++staticintfec_ioctl(structnet_device*dev,structifreq*rq,intcmd)+{+structfec_priv*priv=netdev_priv(dev);++returnfec_phy_mii_ioctl(priv,if_mii(rq),cmd);+}++/* ======================================================================== */+/* OF Driver */+/* ======================================================================== */++staticint__devinit+mpc52xx_fec_probe(structof_device*op,conststructof_device_id*match)+{+intrv;+structnet_device*ndev;+structfec_priv*priv=NULL;+structresourcemem;++phys_addr_trx_fifo;+phys_addr_ttx_fifo;++/* Get the ether ndev & it's private zone */+ndev=alloc_etherdev(sizeof(structfec_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_ERRDRIVER_NAME": "+"Error while parsing device node resource\n");+returnrv;+}+if((mem.end-mem.start+1)!=sizeof(structmpc52xx_fec)){+printk(KERN_ERRDRIVER_NAME+" - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",+(unsignedlong)(mem.end-mem.start+1),sizeof(structmpc52xx_fec));+return-EINVAL;+}++if(!request_mem_region(mem.start,sizeof(structmpc52xx_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->ethtool_ops=&fec_ethtool_ops;+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(structmpc52xx_fec));++if(!priv->fec){+rv=-ENOMEM;+gotoprobe_error;+}++/* Bestcomm init */+rx_fifo=ndev->base_addr+offsetof(structmpc52xx_fec,rfifo_data);+tx_fifo=ndev->base_addr+offsetof(structmpc52xx_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_ERRDRIVER_NAME": Can not init SDMA tasks\n");+rv=-ENOMEM;+gotoprobe_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_FULL;++/* Hardware init */+fec_hw_init(ndev);++fec_reset_stats(ndev);++/* Register the new network device */+rv=register_netdev(ndev);+if(rv<0)+gotoprobe_error;++/* We're done ! */+dev_set_drvdata(&op->dev,ndev);++return0;+++/* 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(structmpc52xx_fec));++free_netdev(ndev);++returnrv;+}++staticint+mpc52xx_fec_remove(structof_device*op)+{+structnet_device*ndev;+structfec_priv*priv;++ndev=dev_get_drvdata(&op->dev);+if(!ndev)+return0;+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(structmpc52xx_fec));++free_netdev(ndev);++dev_set_drvdata(&op->dev,NULL);+return0;+}++#ifdef CONFIG_PM+staticintmpc52xx_fec_of_suspend(structof_device*op,pm_message_tstate)+{+structnet_device*dev=dev_get_drvdata(&op->dev);++if(netif_running(dev))+fec_close(dev);++return0;+}++staticintmpc52xx_fec_of_resume(structof_device*op)+{+structnet_device*dev=dev_get_drvdata(&op->dev);++fec_hw_init(dev);+fec_reset_stats(dev);++if(netif_running(dev))+fec_open(dev);++return0;+}+#endif++staticstructof_device_idmpc52xx_fec_match[]={+{+.type="network",+.compatible="mpc5200-fec",+},+{}+};++MODULE_DEVICE_TABLE(of,mpc52xx_fec_match);++staticstructof_platform_drivermpc52xx_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 */+/* ======================================================================== */++staticint__init+mpc52xx_fec_init(void)+{+intret;+ret=fec_mdio_init();+if(ret){+printk(KERN_ERRDRIVER_NAME": fec_mdio_init failed\n");+returnret;+}++returnof_register_platform_driver(&mpc52xx_fec_driver);+}++staticvoid__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");+
@@ -0,0 +1,238 @@+/*+*DriverfortheMPC5200FastEthernetController-PHY/MIIpart+*+*Copyright(C)2007DomenPuncer,Telargo,Inc.+*+*ThisfileislicensedunderthetermsoftheGNUGeneralPublicLicense+*version2.Thisprogramislicensed"as is"withoutanywarrantyofany+*kind,whetherexpressorimplied.+*/++#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.h"++structfec_mdio_priv{+intcompleted;+wait_queue_head_twq;+structmpc52xx_fec__iomem*regs;+intirq;+};++staticintfec_mdio_read(structmii_bus*bus,intphy_id,intreg)+{+structfec_mdio_priv*priv=bus->priv;+inttries=100;++u32request=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;++returnin_be32(&priv->regs->mii_data)&FEC_MII_DATA_DATAMSK;+}++staticintfec_mdio_write(structmii_bus*bus,intphy_id,intreg,u16data)+{+structfec_mdio_priv*priv=bus->priv;+u32value=data;+inttries=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;++return0;+}++staticirqreturn_tfec_mdio_interrupt(intirq,void*dev_id)+{+structfec_mdio_priv*priv=dev_id;+structmpc52xx_fec__iomem*fec;+intievent;++fec=priv->regs;+ievent=in_be32(&fec->ievent);++ievent&=FEC_IEVENT_MII;+if(!ievent)+returnIRQ_NONE;++out_be32(&fec->ievent,ievent);++priv->completed=1;+wake_up(&priv->wq);++returnIRQ_HANDLED;+}++staticintfec_mdio_probe(structof_device*of,conststructof_device_id*match)+{+structdevice*dev=&of->dev;+structdevice_node*np=of->node;+structdevice_node*child=NULL;+structmii_bus*bus;+structfec_mdio_priv*priv;+structresourceres={};+interr;+inti;++bus=kzalloc(sizeof(*bus),GFP_KERNEL);+if(bus==NULL)+return-ENOMEM;+priv=kzalloc(sizeof(*priv),GFP_KERNEL);+if(priv==NULL){+err=-ENOMEM;+gotoout_free;+}++bus->name="mpc52xx MII bus";+bus->read=fec_mdio_read;+bus->write=fec_mdio_write;++/* setup irqs */+bus->irq=kmalloc(sizeof(bus->irq[0])*PHY_MAX_ADDR,GFP_KERNEL);+if(bus->irq==NULL){+err=-ENOMEM;+gotoout_free;+}+for(i=0;i<PHY_MAX_ADDR;i++)+bus->irq[i]=PHY_POLL;++while((child=of_get_next_child(np,child))!=NULL){+intirq=irq_of_parse_and_map(child,0);+if(irq!=NO_IRQ){+constu32*id=of_get_property(child,"reg",NULL);+bus->irq[*id]=irq;+}+}++/* setup registers */+err=of_address_to_resource(np,0,&res);+if(err)+gotoout_free;+priv->regs=ioremap(res.start,res.end-res.start+1);+if(priv->regs==NULL){+err=-ENOMEM;+gotoout_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);+gotoout_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)+gotoout_free_irq;++return0;++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]!=PHY_POLL)+irq_dispose_mapping(bus->irq[i]);+kfree(bus->irq);+kfree(priv);+kfree(bus);++returnerr;+}++staticintfec_mdio_remove(structof_device*of)+{+structdevice*dev=&of->dev;+structmii_bus*bus=dev_get_drvdata(dev);+structfec_mdio_priv*priv=bus->priv;+inti;++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);++return0;+}+++staticstructof_device_idfec_mdio_match[]={+{+.type="mdio",+.compatible="mpc5200b-fec-phy",+},+{},+};++staticstructof_platform_driverfec_mdio_driver={+.name="mpc5200b-fec-phy",+.probe=fec_mdio_probe,+.remove=fec_mdio_remove,+.match_table=fec_mdio_match,+};+++int__initfec_mdio_init(void)+{+returnof_register_platform_driver(&fec_mdio_driver);+}++void__exitfec_mdio_exit(void)+{+of_unregister_platform_driver(&fec_mdio_driver);+}
From: Grant Likely <hidden> Date: 2007-09-03 15:57:55
On 9/2/07, Domen Puncer [off-list ref] wrote:
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.
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.
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.
From: Jon Smirl <hidden> Date: 2007-09-03 16:09:09
On 9/3/07, Grant Likely [off-list ref] wrote:
On 9/2/07, Domen Puncer [off-list ref] wrote:
quoted
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.
From: Grant Likely <hidden> Date: 2007-09-03 16:41:52
On 9/3/07, Jon Smirl [off-list ref] wrote:
On 9/3/07, Grant Likely [off-list ref] wrote:
quoted
On 9/2/07, Domen Puncer [off-list ref] wrote:
quoted
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.
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.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
From: Domen Puncer <hidden> Date: 2007-09-15 12:15:50
On 03/09/07 09:57 -0600, Grant Likely wrote:
On 9/2/07, Domen Puncer [off-list ref] wrote:
quoted
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...
Thanks for reviewing and sorry for not replying sooner, I lost the
mail.
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
+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.
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.
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
From: Domen Puncer <hidden> Date: 2007-09-17 20:21:42
Export phy_mii_ioctl, so network drivers can use it when built
as modules too.
Signed-off-by: Domen Puncer <redacted>
---
On 17/09/07 11:53 +0200, Sven Luther wrote:
On Sat, Sep 15, 2007 at 02:14:44PM +0200, Domen Puncer wrote:
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
From: Jon Smirl <hidden> Date: 2007-09-17 22:08:29
On 9/17/07, Domen Puncer [off-list ref] wrote:
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/
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
From: Domen Puncer <hidden> Date: 2007-09-18 15:16:26
(I edited Cc: -jeff, +sven, hope you don't mind)
On 17/09/07 18:08 -0400, Jon Smirl wrote:
On 9/17/07, Domen Puncer [off-list ref] wrote:
quoted
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/
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
From: Jon Smirl <hidden> Date: 2007-09-18 19:17:38
On 9/18/07, Domen Puncer [off-list ref] wrote:
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.o
drivers/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);
--
Jon Smirl
jonsmirl@gmail.com
From: Jon Smirl <hidden> Date: 2007-09-18 19:29:11
On 9/18/07, Domen Puncer [off-list ref] wrote:
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.
--
Jon Smirl
jonsmirl@gmail.com
From: Pedro Luis D. L. <hidden> Date: 2007-09-19 08:54:15
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 w=
ith 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 creates pcm030.c in arch/platforms/52xx/ and=
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
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.
On 9/18/07, Domen Puncer wrote:=20
More testing and getting it to work properly on Phytec pcm030 would=20
be great.>> Do we want to do anything about this?=20
[ 1.569657] net eth0: attached phy 0 to driver Generic PHY=20
[ 2.576013] Sending DHCP requests .PHY: f0003000:00 - Link is Up=20
- 100/Full> [ 4.612000] ., OK=20
[ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, my=20
address is 192.168.1.5
quoted
What is happening is the printk for "PHY: f0003000:00 - Link is Up=20
- 100/Full" is done in an interrupt and it comes in the middle of the> ke=
rnel doing DHCP and printing ... without a CR.=20
quoted
Two possible solutions, get rid of the link-up message or wait in in=20
the initial driver load until the link is up. Or we could leave it the=20
way it is, but some people may report this as a bug.
abs.org/mailman/listinfo/linuxppc-embedded
_________________________________________________________________
Busca desde cualquier p=E1gina Web con una protecci=F3n excepcional. Consig=
ue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com=
From: Pedro Luis D. L. <hidden> Date: 2007-09-19 08:54:42
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 w=
ith 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 creates pcm030.c in arch/platforms/52xx/ and=
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
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.
On 9/18/07, Domen Puncer wrote:=20
More testing and getting it to work properly on Phytec pcm030 would=20
be great.>> Do we want to do anything about this?=20
[ 1.569657] net eth0: attached phy 0 to driver Generic PHY=20
[ 2.576013] Sending DHCP requests .PHY: f0003000:00 - Link is Up=20
- 100/Full> [ 4.612000] ., OK=20
[ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, my=20
address is 192.168.1.5
quoted
What is happening is the printk for "PHY: f0003000:00 - Link is Up=20
- 100/Full" is done in an interrupt and it comes in the middle of the> ke=
rnel doing DHCP and printing ... without a CR.=20
quoted
Two possible solutions, get rid of the link-up message or wait in in=20
the initial driver load until the link is up. Or we could leave it the=20
way it is, but some people may report this as a bug.
abs.org/mailman/listinfo/linuxppc-embedded
_________________________________________________________________
Busca desde cualquier p=E1gina Web con una protecci=F3n excepcional. Consig=
ue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com=
Pedro,
On Wednesday 19 September 2007 10:54, Pedro Luis D. L. wrote:
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 creates pcm030.c in arch/platforms/52xx/ a=
nd
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
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)
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
From: Pedro Luis D. L. <hidden> Date: 2007-09-19 11:38:59
Juergen wrote:
Pedro,
On Wednesday 19 September 2007 10:54, Pedro Luis D. L. wrote:
quoted
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
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 creates pcm030.c in arch/platforms/52xx/ =
and
quoted
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
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)
=20
Check your oftree! Most of the time this behaviour means its a wrong oftre=
e in=20
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 :-(
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
From: Domen Puncer <hidden> Date: 2007-09-19 11:56:23
On 18/09/07 15:17 -0400, Jon Smirl wrote:
On 9/18/07, Domen Puncer [off-list ref] wrote:
quoted
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.o
drivers/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?
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(-)
Index: linux.git/drivers/net/fec_mpc52xx/fec.c
===================================================================
From: Jon Smirl <hidden> Date: 2007-09-19 13:56:50
On 9/19/07, Pedro Luis D. L. [off-list ref] wrote:
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.
The base kernel I=B4m using is 2.6.22.6 from kernel.org.
Although I used the patch that creates pcm030.c in arch/platforms/52xx/ a=
nd 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
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)
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
jonsmirl@gmail.com
From: Pedro Luis D. L. <hidden> Date: 2007-09-19 14:31:07
On 9/19/07, Jon Smirl wrote:
On 9/19/07, Pedro Luis D. L. wrote:
quoted
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
The base kernel I=B4m 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.
quoted
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
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)
=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=
From: Jon Smirl <hidden> Date: 2007-09-19 18:44:57
On 9/19/07, Domen Puncer [off-list ref] wrote:
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"
This patch series is working for me now.
This needs a cleanup too, but it is unrelated....
CC drivers/serial/mpc52xx_uart.o
drivers/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'
--
Jon Smirl
jonsmirl@gmail.com
From: Jon Smirl <hidden> Date: 2007-09-19 21:18:12
On 9/19/07, Jon Smirl [off-list ref] wrote:
This needs a cleanup too, but it is unrelated....
Another set of related warnings that need clean up....
CC drivers/spi/mpc52xx_psc_spi.o
drivers/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
--
Jon Smirl
jonsmirl@gmail.com
On Friday 10 August 2007 11:51, Domen Puncer wrote:
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=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
From: Jon Smirl <hidden> Date: 2007-09-27 18:12:36
On 9/27/07, Juergen Beisert [off-list ref] wrote:
On Friday 10 August 2007 11:51, Domen Puncer wrote:
quoted
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.
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
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.
--
Jon Smirl
jonsmirl@gmail.com
From: Scott Wood <hidden> Date: 2007-09-27 18:43:28
Jon Smirl wrote:
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.
On Thursday 27 September 2007 20:43, Scott Wood wrote:
Jon Smirl wrote:
quoted
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.
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
On Thursday 27 September 2007 19:07, Juergen Beisert wrote:
On Friday 10 August 2007 11:51, Domen Puncer wrote:
quoted
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=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
From: Scott Wood <hidden> Date: 2007-09-28 15:40:23
Juergen Beisert wrote:
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
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
On Friday 28 September 2007 17:38, Jon Smirl wrote:
On 9/28/07, Juergen Beisert [off-list ref] wrote:
quoted
But I can't run it a second time, as the network on target's side doesn=
't
quoted
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
On Monday 01 October 2007 10:35, Juergen Beisert wrote:
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;
ifconfig eth0 up". I included some printk statements into the fec.c source
to see what interrupts are happen.
"r" means fec_rx_interrupt was entered, "t" means fec_tx_interrupt was
entered and "p" means fec_interrupt was 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
...at this point the network is dead.
BTW: Without rt-preempt none of the wake/stop queue events and no
fec_interrupt occurs. 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).
+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;
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
+
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(-)
Index: linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec.c
===================================================================
@@ -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.*thiscan'tbedoneinphydriver,sinceitneedstobecalled*beforefecstuff(evenonresume)*/fec_phy_hw_init(priv);
@@ -730,8 +729,8 @@ static void fec_stop(struct net_device *structmpc52xx_fec__iomem*fec=priv->fec;unsignedlongtimeout;-/* 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);
@@ -18,29 +18,28 @@#include"fec.h"structfec_mdio_priv{-intcompleted;-wait_queue_head_twq;structmpc52xx_fec__iomem*regs;-intirq;};staticintfec_mdio_read(structmii_bus*bus,intphy_id,intreg){structfec_mdio_priv*priv=bus->priv;+structmpc52xx_fec__iomem*fec;inttries=100;-u32request=FEC_MII_READ_FRAME;++fec=priv->regs;+out_be32(&fec->ievent,FEC_IEVENT_MII);+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--)+while(!(in_be32(&fec->ievent)&FEC_IEVENT_MII)&&--tries)udelay(5);-priv->completed=0;-if(tries==0)return-ETIMEDOUT;
@@ -50,9 +49,13 @@ static int fec_mdio_read(struct mii_bus staticintfec_mdio_write(structmii_bus*bus,intphy_id,intreg,u16data){structfec_mdio_priv*priv=bus->priv;+structmpc52xx_fec__iomem*fec;u32value=data;inttries=100;+fec=priv->regs;+out_be32(&fec->ievent,FEC_IEVENT_MII);+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;
@@ -60,38 +63,15 @@ static int fec_mdio_write(struct mii_busout_be32(&priv->regs->mii_data,value);/* wait for request to finish */-while(priv->completed==0&&tries--)+while(!(in_be32(&fec->ievent)&FEC_IEVENT_MII)&&--tries)udelay(5);-priv->completed=0;-if(tries==0)return-ETIMEDOUT;return0;}-staticirqreturn_tfec_mdio_interrupt(intirq,void*dev_id)-{-structfec_mdio_priv*priv=dev_id;-structmpc52xx_fec__iomem*fec;-intievent;--fec=priv->regs;-ievent=in_be32(&fec->ievent);--ievent&=FEC_IEVENT_MII;-if(!ievent)-returnIRQ_NONE;--out_be32(&fec->ievent,ievent);--priv->completed=1;-wake_up(&priv->wq);--returnIRQ_HANDLED;-}-staticintfec_mdio_probe(structof_device*of,conststructof_device_id*match){structdevice*dev=&of->dev;
@@ -143,22 +123,12 @@ static int fec_mdio_probe(struct of_devigotoout_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);-gotoout_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);
@@ -167,13 +137,10 @@ static int fec_mdio_probe(struct of_devierr=mdiobus_register(bus);if(err)-gotoout_free_irq;+gotoout_unmap;return0;-out_free_irq:-free_irq(priv->irq,dev);-irq_dispose_mapping(priv->irq);out_unmap:iounmap(priv->regs);out_free:
@@ -197,8 +164,6 @@ static int fec_mdio_remove(struct of_devmdiobus_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])--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de
+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;
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().
Oh, double bug made it work! ;-)
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.
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(-)
From: Robert Schwebel <hidden> Date: 2007-10-02 15:46:21
On Tue, Oct 02, 2007 at 04:32:02PM +0200, Domen Puncer wrote:
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
--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de
Hi,
On Fri, Sep 28, 2007 at 11:12:17AM +0200, Juergen Beisert wrote:
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
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.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/net/fec_mpc52xx/fec.c | 3 +++
1 file changed, 3 insertions(+)
Index: linux-2.6/drivers/net/fec_mpc52xx/fec.c
===================================================================
On Fri, Sep 28, 2007 at 11:12:17AM +0200, Juergen Beisert wrote:
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
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)
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/net/fec_mpc52xx/fec.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-2.6/drivers/net/fec_mpc52xx/fec.h
===================================================================
From: Jon Smirl <hidden> Date: 2007-10-08 16:46:04
On 10/8/07, Sascha Hauer [off-list ref] wrote:
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.
--
Jon Smirl
jonsmirl@gmail.com