diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec.c')
-rw-r--r-- | drivers/net/ethernet/freescale/fec.c | 171 |
1 files changed, 92 insertions, 79 deletions
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index fffd20528b5..0704bcab178 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -140,21 +140,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #endif #endif /* CONFIG_M5272 */ -/* The number of Tx and Rx buffers. These are allocated from the page - * pool. The code may assume these are power of two, so it it best - * to keep them that size. - * We don't need to allocate pages for the transmitter. We just use - * the skbuffer directly. - */ -#define FEC_ENET_RX_PAGES 8 -#define FEC_ENET_RX_FRSIZE 2048 -#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) -#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) -#define FEC_ENET_TX_FRSIZE 2048 -#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE) -#define TX_RING_SIZE 16 /* Must be power of two */ -#define TX_RING_MOD_MASK 15 /* for this to work */ - #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) #error "FEC: descriptor ring size constants too large" #endif @@ -179,9 +164,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define PKT_MINBUF_SIZE 64 #define PKT_MAXBLR_SIZE 1520 -/* This device has up to three irqs on some platforms */ -#define FEC_IRQ_NUM 3 - /* * The 5270/5271/5280/5282/532x RX control register also contains maximum frame * size bits. Other FEC hardware does not, so we need to take that into @@ -194,61 +176,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define OPT_FRAME_SIZE 0 #endif -/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and - * tx_bd_base always point to the base of the buffer descriptors. The - * cur_rx and cur_tx point to the currently available buffer. - * The dirty_tx tracks the current buffer that is being sent by the - * controller. The cur_tx and dirty_tx are equal under both completely - * empty and completely full conditions. The empty/ready indicator in - * the buffer descriptor determines the actual condition. - */ -struct fec_enet_private { - /* Hardware registers of the FEC device */ - void __iomem *hwp; - - struct net_device *netdev; - - struct clk *clk_ipg; - struct clk *clk_ahb; - - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - unsigned char *tx_bounce[TX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - ushort skb_cur; - ushort skb_dirty; - - /* CPM dual port RAM relative addresses */ - dma_addr_t bd_dma; - /* Address of Rx and Tx buffers */ - struct bufdesc *rx_bd_base; - struct bufdesc *tx_bd_base; - /* The next free ring entry */ - struct bufdesc *cur_rx, *cur_tx; - /* The ring entries to be free()ed */ - struct bufdesc *dirty_tx; - - uint tx_full; - /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ - spinlock_t hw_lock; - - struct platform_device *pdev; - - int opened; - int dev_id; - - /* Phylib and MDIO interface */ - struct mii_bus *mii_bus; - struct phy_device *phy_dev; - int mii_timeout; - uint phy_speed; - phy_interface_t phy_interface; - int link; - int full_duplex; - struct completion mdio_done; - int irq[FEC_IRQ_NUM]; -}; - /* FEC MII MMFR bits definition */ #define FEC_MMFR_ST (1 << 30) #define FEC_MMFR_OP_READ (2 << 28) @@ -353,6 +280,17 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | BD_ENET_TX_LAST | BD_ENET_TX_TC); bdp->cbd_sc = status; +#ifdef CONFIG_FEC_PTP + bdp->cbd_bdu = 0; + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && + fep->hwts_tx_en)) { + bdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT); + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + } else { + + bdp->cbd_esc = BD_ENET_TX_INT; + } +#endif /* Trigger transmission start */ writel(0, fep->hwp + FEC_X_DES_ACTIVE); @@ -510,10 +448,17 @@ fec_restart(struct net_device *ndev, int duplex) writel(1 << 8, fep->hwp + FEC_X_WMRK); } +#ifdef CONFIG_FEC_PTP + ecntl |= (1 << 4); +#endif + /* And last, enable the transmit and receive processing */ writel(ecntl, fep->hwp + FEC_ECNTRL); writel(0, fep->hwp + FEC_R_DES_ACTIVE); +#ifdef CONFIG_FEC_PTP + fec_ptp_start_cyclecounter(ndev); +#endif /* Enable interrupts we wish to service */ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); } @@ -599,6 +544,19 @@ fec_enet_tx(struct net_device *ndev) ndev->stats.tx_packets++; } +#ifdef CONFIG_FEC_PTP + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { + struct skb_shared_hwtstamps shhwtstamps; + unsigned long flags; + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + spin_lock_irqsave(&fep->tmreg_lock, flags); + shhwtstamps.hwtstamp = ns_to_ktime( + timecounter_cyc2time(&fep->tc, bdp->ts)); + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + skb_tstamp_tx(skb, &shhwtstamps); + } +#endif if (status & BD_ENET_TX_READY) printk("HEY! Enet xmit interrupt and TX_READY.\n"); @@ -725,6 +683,21 @@ fec_enet_rx(struct net_device *ndev) skb_put(skb, pkt_len - 4); /* Make room */ skb_copy_to_linear_data(skb, data, pkt_len - 4); skb->protocol = eth_type_trans(skb, ndev); +#ifdef CONFIG_FEC_PTP + /* Get receive timestamp from the skb */ + if (fep->hwts_rx_en) { + struct skb_shared_hwtstamps *shhwtstamps = + skb_hwtstamps(skb); + unsigned long flags; + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + + spin_lock_irqsave(&fep->tmreg_lock, flags); + shhwtstamps->hwtstamp = ns_to_ktime( + timecounter_cyc2time(&fep->tc, bdp->ts)); + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + } +#endif if (!skb_defer_rx_timestamp(skb)) netif_rx(skb); } @@ -739,6 +712,12 @@ rx_processing_done: status |= BD_ENET_RX_EMPTY; bdp->cbd_sc = status; +#ifdef CONFIG_FEC_PTP + bdp->cbd_esc = BD_ENET_RX_INT; + bdp->cbd_prot = 0; + bdp->cbd_bdu = 0; +#endif + /* Update BD pointer to next entry */ if (status & BD_ENET_RX_WRAP) bdp = fep->rx_bd_base; @@ -1178,6 +1157,10 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) if (!phydev) return -ENODEV; +#ifdef CONFIG_FEC_PTP + if (cmd == SIOCSHWTSTAMP) + return fec_ptp_ioctl(ndev, rq, cmd); +#endif return phy_mii_ioctl(phydev, rq, cmd); } @@ -1224,6 +1207,9 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); bdp->cbd_sc = BD_ENET_RX_EMPTY; +#ifdef CONFIG_FEC_PTP + bdp->cbd_esc = BD_ENET_RX_INT; +#endif bdp++; } @@ -1237,6 +1223,10 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; + +#ifdef CONFIG_FEC_PTP + bdp->cbd_esc = BD_ENET_RX_INT; +#endif bdp++; } @@ -1494,7 +1484,7 @@ static int fec_enet_init(struct net_device *ndev) } #ifdef CONFIG_OF -static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev) +static int fec_get_phy_mode_dt(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1504,7 +1494,7 @@ static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev) return -ENODEV; } -static void __devinit fec_reset_phy(struct platform_device *pdev) +static void fec_reset_phy(struct platform_device *pdev) { int err, phy_reset; int msec = 1; @@ -1543,7 +1533,7 @@ static inline void fec_reset_phy(struct platform_device *pdev) } #endif /* CONFIG_OF */ -static int __devinit +static int fec_probe(struct platform_device *pdev) { struct fec_enet_private *fep; @@ -1638,9 +1628,19 @@ fec_probe(struct platform_device *pdev) goto failed_clk; } +#ifdef CONFIG_FEC_PTP + fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); + if (IS_ERR(fep->clk_ptp)) { + ret = PTR_ERR(fep->clk_ptp); + goto failed_clk; + } +#endif + clk_prepare_enable(fep->clk_ahb); clk_prepare_enable(fep->clk_ipg); - +#ifdef CONFIG_FEC_PTP + clk_prepare_enable(fep->clk_ptp); +#endif reg_phy = devm_regulator_get(&pdev->dev, "phy"); if (!IS_ERR(reg_phy)) { ret = regulator_enable(reg_phy); @@ -1668,6 +1668,10 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_register; +#ifdef CONFIG_FEC_PTP + fec_ptp_init(ndev, pdev); +#endif + return 0; failed_register: @@ -1677,6 +1681,9 @@ failed_init: failed_regulator: clk_disable_unprepare(fep->clk_ahb); clk_disable_unprepare(fep->clk_ipg); +#ifdef CONFIG_FEC_PTP + clk_disable_unprepare(fep->clk_ptp); +#endif failed_pin: failed_clk: for (i = 0; i < FEC_IRQ_NUM; i++) { @@ -1694,7 +1701,7 @@ failed_alloc_etherdev: return ret; } -static int __devexit +static int fec_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); @@ -1709,6 +1716,12 @@ fec_drv_remove(struct platform_device *pdev) if (irq > 0) free_irq(irq, ndev); } +#ifdef CONFIG_FEC_PTP + del_timer_sync(&fep->time_keep); + clk_disable_unprepare(fep->clk_ptp); + if (fep->ptp_clock) + ptp_clock_unregister(fep->ptp_clock); +#endif clk_disable_unprepare(fep->clk_ahb); clk_disable_unprepare(fep->clk_ipg); iounmap(fep->hwp); @@ -1777,7 +1790,7 @@ static struct platform_driver fec_driver = { }, .id_table = fec_devtype, .probe = fec_probe, - .remove = __devexit_p(fec_drv_remove), + .remove = fec_drv_remove, }; module_platform_driver(fec_driver); |