diff options
Diffstat (limited to 'drivers/net/ethernet/freescale')
23 files changed, 2305 insertions, 1628 deletions
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 6048dc8604e..270308315d4 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -67,6 +67,7 @@ config FSL_XGMAC_MDIO tristate "Freescale XGMAC MDIO" depends on FSL_SOC select PHYLIB + select OF_MDIO ---help--- This driver supports the MDIO bus on the Fman 10G Ethernet MACs. diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index 549ce13b92a..71debd1c18c 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_FSL_XGMAC_MDIO) += xgmac_mdio.o obj-$(CONFIG_GIANFAR) += gianfar_driver.o obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o gianfar_driver-objs := gianfar.o \ - gianfar_ethtool.o \ - gianfar_sysfs.o + gianfar_ethtool.o obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 9ce5b7185fd..671d080105a 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -60,6 +60,61 @@ #define BM_MIIGSK_CFGR_RMII 0x01 #define BM_MIIGSK_CFGR_FRCONT_10M 0x40 +#define RMON_T_DROP 0x200 /* Count of frames not cntd correctly */ +#define RMON_T_PACKETS 0x204 /* RMON TX packet count */ +#define RMON_T_BC_PKT 0x208 /* RMON TX broadcast pkts */ +#define RMON_T_MC_PKT 0x20C /* RMON TX multicast pkts */ +#define RMON_T_CRC_ALIGN 0x210 /* RMON TX pkts with CRC align err */ +#define RMON_T_UNDERSIZE 0x214 /* RMON TX pkts < 64 bytes, good CRC */ +#define RMON_T_OVERSIZE 0x218 /* RMON TX pkts > MAX_FL bytes good CRC */ +#define RMON_T_FRAG 0x21C /* RMON TX pkts < 64 bytes, bad CRC */ +#define RMON_T_JAB 0x220 /* RMON TX pkts > MAX_FL bytes, bad CRC */ +#define RMON_T_COL 0x224 /* RMON TX collision count */ +#define RMON_T_P64 0x228 /* RMON TX 64 byte pkts */ +#define RMON_T_P65TO127 0x22C /* RMON TX 65 to 127 byte pkts */ +#define RMON_T_P128TO255 0x230 /* RMON TX 128 to 255 byte pkts */ +#define RMON_T_P256TO511 0x234 /* RMON TX 256 to 511 byte pkts */ +#define RMON_T_P512TO1023 0x238 /* RMON TX 512 to 1023 byte pkts */ +#define RMON_T_P1024TO2047 0x23C /* RMON TX 1024 to 2047 byte pkts */ +#define RMON_T_P_GTE2048 0x240 /* RMON TX pkts > 2048 bytes */ +#define RMON_T_OCTETS 0x244 /* RMON TX octets */ +#define IEEE_T_DROP 0x248 /* Count of frames not counted crtly */ +#define IEEE_T_FRAME_OK 0x24C /* Frames tx'd OK */ +#define IEEE_T_1COL 0x250 /* Frames tx'd with single collision */ +#define IEEE_T_MCOL 0x254 /* Frames tx'd with multiple collision */ +#define IEEE_T_DEF 0x258 /* Frames tx'd after deferral delay */ +#define IEEE_T_LCOL 0x25C /* Frames tx'd with late collision */ +#define IEEE_T_EXCOL 0x260 /* Frames tx'd with excesv collisions */ +#define IEEE_T_MACERR 0x264 /* Frames tx'd with TX FIFO underrun */ +#define IEEE_T_CSERR 0x268 /* Frames tx'd with carrier sense err */ +#define IEEE_T_SQE 0x26C /* Frames tx'd with SQE err */ +#define IEEE_T_FDXFC 0x270 /* Flow control pause frames tx'd */ +#define IEEE_T_OCTETS_OK 0x274 /* Octet count for frames tx'd w/o err */ +#define RMON_R_PACKETS 0x284 /* RMON RX packet count */ +#define RMON_R_BC_PKT 0x288 /* RMON RX broadcast pkts */ +#define RMON_R_MC_PKT 0x28C /* RMON RX multicast pkts */ +#define RMON_R_CRC_ALIGN 0x290 /* RMON RX pkts with CRC alignment err */ +#define RMON_R_UNDERSIZE 0x294 /* RMON RX pkts < 64 bytes, good CRC */ +#define RMON_R_OVERSIZE 0x298 /* RMON RX pkts > MAX_FL bytes good CRC */ +#define RMON_R_FRAG 0x29C /* RMON RX pkts < 64 bytes, bad CRC */ +#define RMON_R_JAB 0x2A0 /* RMON RX pkts > MAX_FL bytes, bad CRC */ +#define RMON_R_RESVD_O 0x2A4 /* Reserved */ +#define RMON_R_P64 0x2A8 /* RMON RX 64 byte pkts */ +#define RMON_R_P65TO127 0x2AC /* RMON RX 65 to 127 byte pkts */ +#define RMON_R_P128TO255 0x2B0 /* RMON RX 128 to 255 byte pkts */ +#define RMON_R_P256TO511 0x2B4 /* RMON RX 256 to 511 byte pkts */ +#define RMON_R_P512TO1023 0x2B8 /* RMON RX 512 to 1023 byte pkts */ +#define RMON_R_P1024TO2047 0x2BC /* RMON RX 1024 to 2047 byte pkts */ +#define RMON_R_P_GTE2048 0x2C0 /* RMON RX pkts > 2048 bytes */ +#define RMON_R_OCTETS 0x2C4 /* RMON RX octets */ +#define IEEE_R_DROP 0x2C8 /* Count frames not counted correctly */ +#define IEEE_R_FRAME_OK 0x2CC /* Frames rx'd OK */ +#define IEEE_R_CRC 0x2D0 /* Frames rx'd with CRC err */ +#define IEEE_R_ALIGN 0x2D4 /* Frames rx'd with alignment err */ +#define IEEE_R_MACERR 0x2D8 /* Receive FIFO overflow count */ +#define IEEE_R_FDXFC 0x2DC /* Flow control pause frames rx'd */ +#define IEEE_R_OCTETS_OK 0x2E0 /* Octet cnt for frames rx'd w/o err */ + #else #define FEC_ECNTRL 0x000 /* Ethernet control reg */ @@ -148,6 +203,9 @@ struct bufdesc_ex { #define BD_ENET_RX_CL ((ushort)0x0001) #define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ +/* Enhanced buffer descriptor control/status used by Ethernet receive */ +#define BD_ENET_RX_VLAN 0x00000004 + /* Buffer descriptor control/status used by Ethernet transmit. */ #define BD_ENET_TX_READY ((ushort)0x8000) @@ -163,7 +221,7 @@ struct bufdesc_ex { #define BD_ENET_TX_RCMASK ((ushort)0x003c) #define BD_ENET_TX_UN ((ushort)0x0002) #define BD_ENET_TX_CSL ((ushort)0x0001) -#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ +#define BD_ENET_TX_STATS ((ushort)0x0fff) /* All status bits */ /*enhanced buffer descriptor control/status used by Ethernet transmit*/ #define BD_ENET_TX_INT 0x40000000 @@ -188,8 +246,8 @@ struct bufdesc_ex { #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 */ +#define TX_RING_SIZE 512 /* Must be power of two */ +#define TX_RING_MOD_MASK 511 /* for this to work */ #define BD_ENET_RX_INT 0x00800000 #define BD_ENET_RX_PTP ((ushort)0x0400) @@ -201,6 +259,7 @@ struct bufdesc_ex { struct fec_enet_delayed_work { struct delayed_work delay_work; bool timeout; + bool trig_tx; }; /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and @@ -237,6 +296,16 @@ struct fec_enet_private { /* The ring entries to be free()ed */ struct bufdesc *dirty_tx; + unsigned short bufdesc_size; + unsigned short tx_ring_size; + unsigned short rx_ring_size; + unsigned short tx_stop_threshold; + unsigned short tx_wake_threshold; + + /* Software TSO */ + char *tso_hdrs; + dma_addr_t tso_hdrs_dma; + struct platform_device *pdev; int opened; @@ -272,11 +341,13 @@ struct fec_enet_private { int hwts_tx_en; struct timer_list time_keep; struct fec_enet_delayed_work delay_work; + struct regulator *reg_phy; }; -void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev); +void fec_ptp_init(struct platform_device *pdev); void fec_ptp_start_cyclecounter(struct net_device *ndev); -int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd); +int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); +int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); /****************************************************************************/ #endif /* FEC_H */ diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index a667015be22..77037fd377b 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -29,7 +29,6 @@ #include <linux/ioport.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -37,6 +36,7 @@ #include <linux/in.h> #include <linux/ip.h> #include <net/ip.h> +#include <net/tso.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/icmp.h> @@ -53,13 +53,16 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/of_net.h> -#include <linux/pinctrl/consumer.h> #include <linux/regulator/consumer.h> +#include <linux/if_vlan.h> +#include <linux/pinctrl/consumer.h> #include <asm/cacheflush.h> #include "fec.h" +static void set_multicast_list(struct net_device *ndev); + #if defined(CONFIG_ARM) #define FEC_ALIGNMENT 0xf #else @@ -67,7 +70,6 @@ #endif #define DRIVER_NAME "fec" -#define FEC_NAPI_WEIGHT 64 /* Pause frame feild and FIFO threshold */ #define FEC_ENET_FCE (1 << 5) @@ -89,6 +91,18 @@ #define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4) /* Controller has hardware checksum support */ #define FEC_QUIRK_HAS_CSUM (1 << 5) +/* Controller has hardware vlan support */ +#define FEC_QUIRK_HAS_VLAN (1 << 6) +/* ENET IP errata ERR006358 + * + * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously + * detected as not set during a prior frame transmission, then the + * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs + * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in + * frames not being transmitted until there is a 0-to-1 transition on + * ENET_TDAR[TDAR]. + */ +#define FEC_QUIRK_ERR006358 (1 << 7) static struct platform_device_id fec_devtype[] = { { @@ -107,7 +121,8 @@ static struct platform_device_id fec_devtype[] = { }, { .name = "imx6q-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | - FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM, + FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | + FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358, }, { .name = "mvf600-fec", .driver_data = FEC_QUIRK_ENET_MAC, @@ -159,10 +174,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #endif #endif /* CONFIG_M5272 */ -#if (((RX_RING_SIZE + TX_RING_SIZE) * 32) > PAGE_SIZE) -#error "FEC: descriptor ring size constants too large" -#endif - /* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ #define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ @@ -178,11 +189,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF)) -/* The FEC stores dest/src/type, data, and checksum for receive packets. +/* The FEC stores dest/src/type/vlan, data, and checksum for receive packets. */ -#define PKT_MAXBUF_SIZE 1518 +#define PKT_MAXBUF_SIZE 1522 #define PKT_MINBUF_SIZE 64 -#define PKT_MAXBLR_SIZE 1520 +#define PKT_MAXBLR_SIZE 1536 /* FEC receive acceleration */ #define FEC_RACC_IPDIS (1 << 1) @@ -218,24 +229,84 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_PAUSE_FLAG_AUTONEG 0x1 #define FEC_PAUSE_FLAG_ENABLE 0x2 +#define TSO_HEADER_SIZE 128 +/* Max number of allowed TCP segments for software TSO */ +#define FEC_MAX_TSO_SEGS 100 +#define FEC_MAX_SKB_DESCS (FEC_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS) + +#define IS_TSO_HEADER(txq, addr) \ + ((addr >= txq->tso_hdrs_dma) && \ + (addr < txq->tso_hdrs_dma + txq->tx_ring_size * TSO_HEADER_SIZE)) + static int mii_cnt; -static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, int is_ex) +static inline +struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_private *fep) { - struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp; - if (is_ex) - return (struct bufdesc *)(ex + 1); + struct bufdesc *new_bd = bdp + 1; + struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1; + struct bufdesc_ex *ex_base; + struct bufdesc *base; + int ring_size; + + if (bdp >= fep->tx_bd_base) { + base = fep->tx_bd_base; + ring_size = fep->tx_ring_size; + ex_base = (struct bufdesc_ex *)fep->tx_bd_base; + } else { + base = fep->rx_bd_base; + ring_size = fep->rx_ring_size; + ex_base = (struct bufdesc_ex *)fep->rx_bd_base; + } + + if (fep->bufdesc_ex) + return (struct bufdesc *)((ex_new_bd >= (ex_base + ring_size)) ? + ex_base : ex_new_bd); else - return bdp + 1; + return (new_bd >= (base + ring_size)) ? + base : new_bd; } -static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, int is_ex) +static inline +struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, struct fec_enet_private *fep) { - struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp; - if (is_ex) - return (struct bufdesc *)(ex - 1); + struct bufdesc *new_bd = bdp - 1; + struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1; + struct bufdesc_ex *ex_base; + struct bufdesc *base; + int ring_size; + + if (bdp >= fep->tx_bd_base) { + base = fep->tx_bd_base; + ring_size = fep->tx_ring_size; + ex_base = (struct bufdesc_ex *)fep->tx_bd_base; + } else { + base = fep->rx_bd_base; + ring_size = fep->rx_ring_size; + ex_base = (struct bufdesc_ex *)fep->rx_bd_base; + } + + if (fep->bufdesc_ex) + return (struct bufdesc *)((ex_new_bd < ex_base) ? + (ex_new_bd + ring_size) : ex_new_bd); else - return bdp - 1; + return (new_bd < base) ? (new_bd + ring_size) : new_bd; +} + +static int fec_enet_get_bd_index(struct bufdesc *base, struct bufdesc *bdp, + struct fec_enet_private *fep) +{ + return ((const char *)bdp - (const char *)base) / fep->bufdesc_size; +} + +static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep) +{ + int entries; + + entries = ((const char *)fep->dirty_tx - + (const char *)fep->cur_tx) / fep->bufdesc_size - 1; + + return entries > 0 ? entries : entries + fep->tx_ring_size; } static void *swap_buffer(void *bufaddr, int len) @@ -243,12 +314,17 @@ static void *swap_buffer(void *bufaddr, int len) int i; unsigned int *buf = bufaddr; - for (i = 0; i < (len + 3) / 4; i++, buf++) + for (i = 0; i < DIV_ROUND_UP(len, 4); i++, buf++) *buf = cpu_to_be32(*buf); return bufaddr; } +static inline bool is_ipv4_pkt(struct sk_buff *skb) +{ + return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4; +} + static int fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev) { @@ -259,127 +335,435 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev) if (unlikely(skb_cow_head(skb, 0))) return -1; + if (is_ipv4_pkt(skb)) + ip_hdr(skb)->check = 0; *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) = 0; return 0; } -static netdev_tx_t -fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static void +fec_enet_submit_work(struct bufdesc *bdp, struct fec_enet_private *fep) +{ + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + struct bufdesc *bdp_pre; + + bdp_pre = fec_enet_get_prevdesc(bdp, fep); + if ((id_entry->driver_data & FEC_QUIRK_ERR006358) && + !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) { + fep->delay_work.trig_tx = true; + schedule_delayed_work(&(fep->delay_work.delay_work), + msecs_to_jiffies(1)); + } +} + +static int +fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); - struct bufdesc *bdp; - void *bufaddr; - unsigned short status; + struct bufdesc *bdp = fep->cur_tx; + struct bufdesc_ex *ebdp; + int nr_frags = skb_shinfo(skb)->nr_frags; + int frag, frag_len; + unsigned short status; + unsigned int estatus = 0; + skb_frag_t *this_frag; unsigned int index; + void *bufaddr; + int i; - if (!fep->link) { - /* Link is down or auto-negotiation is in progress. */ - return NETDEV_TX_BUSY; + for (frag = 0; frag < nr_frags; frag++) { + this_frag = &skb_shinfo(skb)->frags[frag]; + bdp = fec_enet_get_nextdesc(bdp, fep); + ebdp = (struct bufdesc_ex *)bdp; + + status = bdp->cbd_sc; + status &= ~BD_ENET_TX_STATS; + status |= (BD_ENET_TX_TC | BD_ENET_TX_READY); + frag_len = skb_shinfo(skb)->frags[frag].size; + + /* Handle the last BD specially */ + if (frag == nr_frags - 1) { + status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST); + if (fep->bufdesc_ex) { + estatus |= BD_ENET_TX_INT; + if (unlikely(skb_shinfo(skb)->tx_flags & + SKBTX_HW_TSTAMP && fep->hwts_tx_en)) + estatus |= BD_ENET_TX_TS; + } + } + + if (fep->bufdesc_ex) { + if (skb->ip_summed == CHECKSUM_PARTIAL) + estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS; + ebdp->cbd_bdu = 0; + ebdp->cbd_esc = estatus; + } + + bufaddr = page_address(this_frag->page.p) + this_frag->page_offset; + + index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep); + if (((unsigned long) bufaddr) & FEC_ALIGNMENT || + id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) { + memcpy(fep->tx_bounce[index], bufaddr, frag_len); + bufaddr = fep->tx_bounce[index]; + + if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) + swap_buffer(bufaddr, frag_len); + } + + bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, + frag_len, DMA_TO_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + dev_kfree_skb_any(skb); + if (net_ratelimit()) + netdev_err(ndev, "Tx DMA memory map failed\n"); + goto dma_mapping_error; + } + + bdp->cbd_datlen = frag_len; + bdp->cbd_sc = status; } - /* Fill in a Tx ring entry */ + fep->cur_tx = bdp; + + return 0; + +dma_mapping_error: bdp = fep->cur_tx; + for (i = 0; i < frag; i++) { + bdp = fec_enet_get_nextdesc(bdp, fep); + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, + bdp->cbd_datlen, DMA_TO_DEVICE); + } + return NETDEV_TX_OK; +} - status = bdp->cbd_sc; +static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + int nr_frags = skb_shinfo(skb)->nr_frags; + struct bufdesc *bdp, *last_bdp; + void *bufaddr; + unsigned short status; + unsigned short buflen; + unsigned int estatus = 0; + unsigned int index; + int entries_free; + int ret; - if (status & BD_ENET_TX_READY) { - /* Ooops. All transmit buffers are full. Bail out. - * This should not happen, since ndev->tbusy should be set. - */ - netdev_err(ndev, "tx queue full!\n"); - return NETDEV_TX_BUSY; + entries_free = fec_enet_get_free_txdesc_num(fep); + if (entries_free < MAX_SKB_FRAGS + 1) { + dev_kfree_skb_any(skb); + if (net_ratelimit()) + netdev_err(ndev, "NOT enough BD for SG!\n"); + return NETDEV_TX_OK; } /* Protocol checksum off-load for TCP and UDP. */ if (fec_enet_clear_csum(skb, ndev)) { - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } - /* Clear all of the status flags */ + /* Fill in a Tx ring entry */ + bdp = fep->cur_tx; + status = bdp->cbd_sc; status &= ~BD_ENET_TX_STATS; /* Set buffer length and buffer pointer */ bufaddr = skb->data; - bdp->cbd_datlen = skb->len; - - /* - * On some FEC implementations data must be aligned on - * 4-byte boundaries. Use bounce buffers to copy data - * and get it aligned. Ugh. - */ - if (fep->bufdesc_ex) - index = (struct bufdesc_ex *)bdp - - (struct bufdesc_ex *)fep->tx_bd_base; - else - index = bdp - fep->tx_bd_base; + buflen = skb_headlen(skb); - if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { - memcpy(fep->tx_bounce[index], skb->data, skb->len); + index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep); + if (((unsigned long) bufaddr) & FEC_ALIGNMENT || + id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) { + memcpy(fep->tx_bounce[index], skb->data, buflen); bufaddr = fep->tx_bounce[index]; + + if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) + swap_buffer(bufaddr, buflen); } - /* - * Some design made an incorrect assumption on endian mode of - * the system that it's running on. As the result, driver has to - * swap every frame going to and coming from the controller. + /* Push the data cache so the CPM does not get stale memory + * data. */ - if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) - swap_buffer(bufaddr, skb->len); + bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, + buflen, DMA_TO_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + dev_kfree_skb_any(skb); + if (net_ratelimit()) + netdev_err(ndev, "Tx DMA memory map failed\n"); + return NETDEV_TX_OK; + } + if (nr_frags) { + ret = fec_enet_txq_submit_frag_skb(skb, ndev); + if (ret) + return ret; + } else { + status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST); + if (fep->bufdesc_ex) { + estatus = BD_ENET_TX_INT; + if (unlikely(skb_shinfo(skb)->tx_flags & + SKBTX_HW_TSTAMP && fep->hwts_tx_en)) + estatus |= BD_ENET_TX_TS; + } + } + + if (fep->bufdesc_ex) { + + struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; + + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && + fep->hwts_tx_en)) + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS; + + ebdp->cbd_bdu = 0; + ebdp->cbd_esc = estatus; + } + + last_bdp = fep->cur_tx; + index = fec_enet_get_bd_index(fep->tx_bd_base, last_bdp, fep); /* Save skb pointer */ fep->tx_skbuff[index] = skb; - /* Push the data cache so the CPM does not get stale memory - * data. - */ - bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, - FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); + bdp->cbd_datlen = buflen; /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. */ - status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR - | BD_ENET_TX_LAST | BD_ENET_TX_TC); + status |= (BD_ENET_TX_READY | BD_ENET_TX_TC); bdp->cbd_sc = status; + fec_enet_submit_work(bdp, fep); + + /* If this was the last BD in the ring, start at the beginning again. */ + bdp = fec_enet_get_nextdesc(last_bdp, fep); + + skb_tx_timestamp(skb); + + fep->cur_tx = bdp; + + /* Trigger transmission start */ + writel(0, fep->hwp + FEC_X_DES_ACTIVE); + + return 0; +} + +static int +fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev, + struct bufdesc *bdp, int index, char *data, + int size, bool last_tcp, bool is_last) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; + unsigned short status; + unsigned int estatus = 0; + + status = bdp->cbd_sc; + status &= ~BD_ENET_TX_STATS; + + status |= (BD_ENET_TX_TC | BD_ENET_TX_READY); + bdp->cbd_datlen = size; + + if (((unsigned long) data) & FEC_ALIGNMENT || + id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) { + memcpy(fep->tx_bounce[index], data, size); + data = fep->tx_bounce[index]; + + if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) + swap_buffer(data, size); + } + + bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, + size, DMA_TO_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + dev_kfree_skb_any(skb); + if (net_ratelimit()) + netdev_err(ndev, "Tx DMA memory map failed\n"); + return NETDEV_TX_BUSY; + } + if (fep->bufdesc_ex) { + if (skb->ip_summed == CHECKSUM_PARTIAL) + estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS; + ebdp->cbd_bdu = 0; + ebdp->cbd_esc = estatus; + } - struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; + /* Handle the last BD specially */ + if (last_tcp) + status |= (BD_ENET_TX_LAST | BD_ENET_TX_TC); + if (is_last) { + status |= BD_ENET_TX_INTR; + if (fep->bufdesc_ex) + ebdp->cbd_esc |= BD_ENET_TX_INT; + } + + bdp->cbd_sc = status; + + return 0; +} + +static int +fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev, + struct bufdesc *bdp, int index) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; + void *bufaddr; + unsigned long dmabuf; + unsigned short status; + unsigned int estatus = 0; + + status = bdp->cbd_sc; + status &= ~BD_ENET_TX_STATS; + status |= (BD_ENET_TX_TC | BD_ENET_TX_READY); + + bufaddr = fep->tso_hdrs + index * TSO_HEADER_SIZE; + dmabuf = fep->tso_hdrs_dma + index * TSO_HEADER_SIZE; + if (((unsigned long) bufaddr) & FEC_ALIGNMENT || + id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) { + memcpy(fep->tx_bounce[index], skb->data, hdr_len); + bufaddr = fep->tx_bounce[index]; + + if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) + swap_buffer(bufaddr, hdr_len); + + dmabuf = dma_map_single(&fep->pdev->dev, bufaddr, + hdr_len, DMA_TO_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, dmabuf)) { + dev_kfree_skb_any(skb); + if (net_ratelimit()) + netdev_err(ndev, "Tx DMA memory map failed\n"); + return NETDEV_TX_BUSY; + } + } + + bdp->cbd_bufaddr = dmabuf; + bdp->cbd_datlen = hdr_len; + + if (fep->bufdesc_ex) { + if (skb->ip_summed == CHECKSUM_PARTIAL) + estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS; ebdp->cbd_bdu = 0; - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && - fep->hwts_tx_en)) { - ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT); - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - } else { - ebdp->cbd_esc = BD_ENET_TX_INT; + ebdp->cbd_esc = estatus; + } - /* Enable protocol checksum flags - * We do not bother with the IP Checksum bits as they - * are done by the kernel - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) - ebdp->cbd_esc |= BD_ENET_TX_PINS; + bdp->cbd_sc = status; + + return 0; +} + +static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + int total_len, data_left; + struct bufdesc *bdp = fep->cur_tx; + struct tso_t tso; + unsigned int index = 0; + int ret; + + if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep)) { + dev_kfree_skb_any(skb); + if (net_ratelimit()) + netdev_err(ndev, "NOT enough BD for TSO!\n"); + return NETDEV_TX_OK; + } + + /* Protocol checksum off-load for TCP and UDP. */ + if (fec_enet_clear_csum(skb, ndev)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* Initialize the TSO handler, and prepare the first payload */ + tso_start(skb, &tso); + + total_len = skb->len - hdr_len; + while (total_len > 0) { + char *hdr; + + index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep); + data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len); + total_len -= data_left; + + /* prepare packet headers: MAC + IP + TCP */ + hdr = fep->tso_hdrs + index * TSO_HEADER_SIZE; + tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0); + ret = fec_enet_txq_put_hdr_tso(skb, ndev, bdp, index); + if (ret) + goto err_release; + + while (data_left > 0) { + int size; + + size = min_t(int, tso.size, data_left); + bdp = fec_enet_get_nextdesc(bdp, fep); + index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep); + ret = fec_enet_txq_put_data_tso(skb, ndev, bdp, index, tso.data, + size, size == data_left, + total_len == 0); + if (ret) + goto err_release; + + data_left -= size; + tso_build_data(skb, &tso, size); } + + bdp = fec_enet_get_nextdesc(bdp, fep); } - /* If this was the last BD in the ring, start at the beginning again. */ - if (status & BD_ENET_TX_WRAP) - bdp = fep->tx_bd_base; - else - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); - fep->cur_tx = bdp; + /* Save skb pointer */ + fep->tx_skbuff[index] = skb; - if (fep->cur_tx == fep->dirty_tx) - netif_stop_queue(ndev); + fec_enet_submit_work(bdp, fep); + + skb_tx_timestamp(skb); + fep->cur_tx = bdp; /* Trigger transmission start */ writel(0, fep->hwp + FEC_X_DES_ACTIVE); - skb_tx_timestamp(skb); + return 0; + +err_release: + /* TODO: Release all used data descriptors for TSO */ + return ret; +} + +static netdev_tx_t +fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + int entries_free; + int ret; + + if (skb_is_gso(skb)) + ret = fec_enet_txq_submit_tso(skb, ndev); + else + ret = fec_enet_txq_submit_skb(skb, ndev); + if (ret) + return ret; + + entries_free = fec_enet_get_free_txdesc_num(fep); + if (entries_free <= fep->tx_stop_threshold) + netif_stop_queue(ndev); return NETDEV_TX_OK; } @@ -394,18 +778,18 @@ static void fec_enet_bd_init(struct net_device *dev) /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < fep->rx_ring_size; i++) { /* Initialize the BD for every fragment in the page. */ if (bdp->cbd_bufaddr) bdp->cbd_sc = BD_ENET_RX_EMPTY; else bdp->cbd_sc = 0; - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); } /* Set the last buffer to wrap */ - bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_prevdesc(bdp, fep); bdp->cbd_sc |= BD_SC_WRAP; fep->cur_rx = fep->rx_bd_base; @@ -413,7 +797,7 @@ static void fec_enet_bd_init(struct net_device *dev) /* ...and the same for transmit */ bdp = fep->tx_bd_base; fep->cur_tx = bdp; - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < fep->tx_ring_size; i++) { /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = 0; @@ -422,11 +806,11 @@ static void fec_enet_bd_init(struct net_device *dev) fep->tx_skbuff[i] = NULL; } bdp->cbd_bufaddr = 0; - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); } /* Set the last buffer to wrap */ - bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_prevdesc(bdp, fep); bdp->cbd_sc |= BD_SC_WRAP; fep->dirty_tx = bdp; } @@ -471,14 +855,6 @@ fec_restart(struct net_device *ndev, int duplex) /* Clear any outstanding interrupt. */ writel(0xffc00000, fep->hwp + FEC_IEVENT); - /* Reset all multicast. */ - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); -#ifndef CONFIG_M5272 - writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_HASH_TABLE_LOW); -#endif - /* Set maximum receive buffer size. */ writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); @@ -488,10 +864,10 @@ fec_restart(struct net_device *ndev, int duplex) writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); if (fep->bufdesc_ex) writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex) - * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); + * fep->rx_ring_size, fep->hwp + FEC_X_DES_START); else writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) - * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); + * fep->rx_ring_size, fep->hwp + FEC_X_DES_START); for (i = 0; i <= TX_RING_MOD_MASK; i++) { @@ -516,6 +892,7 @@ fec_restart(struct net_device *ndev, int duplex) /* Set MII speed */ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); +#if !defined(CONFIG_M5272) /* set RX checksum */ val = readl(fep->hwp + FEC_RACC); if (fep->csum_flags & FLAG_RX_CSUM_ENABLED) @@ -523,6 +900,7 @@ fec_restart(struct net_device *ndev, int duplex) else val &= ~FEC_RACC_OPTIONS; writel(val, fep->hwp + FEC_RACC); +#endif /* * The phy interface and speed need to get configured @@ -575,6 +953,7 @@ fec_restart(struct net_device *ndev, int duplex) #endif } +#if !defined(CONFIG_M5272) /* enable pause frame*/ if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) || ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) && @@ -592,9 +971,17 @@ fec_restart(struct net_device *ndev, int duplex) } else { rcntl &= ~FEC_ENET_FCE; } +#endif /* !defined(CONFIG_M5272) */ writel(rcntl, fep->hwp + FEC_R_CNTRL); + /* Setup multicast filter. */ + set_multicast_list(ndev); +#ifndef CONFIG_M5272 + writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_HASH_TABLE_LOW); +#endif + if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { /* enable ENET endian swap */ ecntl |= (1 << 8); @@ -605,6 +992,11 @@ fec_restart(struct net_device *ndev, int duplex) if (fep->bufdesc_ex) ecntl |= (1 << 4); +#ifndef CONFIG_M5272 + /* Enable the MIB statistic event counters */ + writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT); +#endif + /* And last, enable the transmit and receive processing */ writel(ecntl, fep->hwp + FEC_ECNTRL); writel(0, fep->hwp + FEC_R_DES_ACTIVE); @@ -676,6 +1068,11 @@ static void fec_enet_work(struct work_struct *work) fec_restart(fep->netdev, fep->full_duplex); netif_wake_queue(fep->netdev); } + + if (fep->delay_work.trig_tx) { + fep->delay_work.trig_tx = false; + writel(0, fep->hwp + FEC_X_DES_ACTIVE); + } } static void @@ -686,15 +1083,13 @@ fec_enet_tx(struct net_device *ndev) unsigned short status; struct sk_buff *skb; int index = 0; + int entries_free; fep = netdev_priv(ndev); bdp = fep->dirty_tx; /* get next bdp of dirty_tx */ - if (bdp->cbd_sc & BD_ENET_TX_WRAP) - bdp = fep->tx_bd_base; - else - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { @@ -702,17 +1097,17 @@ fec_enet_tx(struct net_device *ndev) if (bdp == fep->cur_tx) break; - if (fep->bufdesc_ex) - index = (struct bufdesc_ex *)bdp - - (struct bufdesc_ex *)fep->tx_bd_base; - else - index = bdp - fep->tx_bd_base; - - dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, - FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); - bdp->cbd_bufaddr = 0; + index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep); skb = fep->tx_skbuff[index]; + if (!IS_TSO_HEADER(fep, bdp->cbd_bufaddr)) + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, + bdp->cbd_datlen, DMA_TO_DEVICE); + bdp->cbd_bufaddr = 0; + if (!skb) { + bdp = fec_enet_get_nextdesc(bdp, fep); + continue; + } /* Check for errors. */ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | @@ -731,6 +1126,7 @@ fec_enet_tx(struct net_device *ndev) ndev->stats.tx_carrier_errors++; } else { ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; } if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) && @@ -763,22 +1159,19 @@ fec_enet_tx(struct net_device *ndev) fep->dirty_tx = bdp; /* Update pointer to next buffer descriptor to be transmitted */ - if (status & BD_ENET_TX_WRAP) - bdp = fep->tx_bd_base; - else - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); /* Since we have freed up a buffer, the ring is no longer full */ - if (fep->dirty_tx != fep->cur_tx) { - if (netif_queue_stopped(ndev)) + if (netif_queue_stopped(ndev)) { + entries_free = fec_enet_get_free_txdesc_num(fep); + if (entries_free >= fep->tx_wake_threshold) netif_wake_queue(ndev); } } return; } - /* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, @@ -796,6 +1189,10 @@ fec_enet_rx(struct net_device *ndev, int budget) ushort pkt_len; __u8 *data; int pkt_received = 0; + struct bufdesc_ex *ebdp = NULL; + bool vlan_packet_rcvd = false; + u16 vlan_tag; + int index = 0; #ifdef CONFIG_M532x flush_cache_all(); @@ -851,14 +1248,33 @@ fec_enet_rx(struct net_device *ndev, int budget) ndev->stats.rx_packets++; pkt_len = bdp->cbd_datlen; ndev->stats.rx_bytes += pkt_len; - data = (__u8*)__va(bdp->cbd_bufaddr); - dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, - FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); + index = fec_enet_get_bd_index(fep->rx_bd_base, bdp, fep); + data = fep->rx_skbuff[index]->data; + dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) swap_buffer(data, pkt_len); + /* Extract the enhanced buffer descriptor */ + ebdp = NULL; + if (fep->bufdesc_ex) + ebdp = (struct bufdesc_ex *)bdp; + + /* If this is a VLAN packet remove the VLAN Tag */ + vlan_packet_rcvd = false; + if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) && + fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) { + /* Push and remove the vlan tag */ + struct vlan_hdr *vlan_header = + (struct vlan_hdr *) (data + ETH_HLEN); + vlan_tag = ntohs(vlan_header->h_vlan_TCI); + pkt_len -= VLAN_HLEN; + + vlan_packet_rcvd = true; + } + /* This does 16 byte alignment, exactly what we need. * The packet length includes FCS, but we don't want to * include that when passing upstream as it messes up @@ -869,9 +1285,18 @@ fec_enet_rx(struct net_device *ndev, int budget) if (unlikely(!skb)) { ndev->stats.rx_dropped++; } else { + int payload_offset = (2 * ETH_ALEN); skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pkt_len - 4); /* Make room */ - skb_copy_to_linear_data(skb, data, pkt_len - 4); + + /* Extract the frame data without the VLAN header. */ + skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN)); + if (vlan_packet_rcvd) + payload_offset = (2 * ETH_ALEN) + VLAN_HLEN; + skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN), + data + payload_offset, + pkt_len - 4 - (2 * ETH_ALEN)); + skb->protocol = eth_type_trans(skb, ndev); /* Get receive timestamp from the skb */ @@ -879,8 +1304,6 @@ fec_enet_rx(struct net_device *ndev, int budget) struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); unsigned long flags; - struct bufdesc_ex *ebdp = - (struct bufdesc_ex *)bdp; memset(shhwtstamps, 0, sizeof(*shhwtstamps)); @@ -891,9 +1314,7 @@ fec_enet_rx(struct net_device *ndev, int budget) } if (fep->bufdesc_ex && - (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { - struct bufdesc_ex *ebdp = - (struct bufdesc_ex *)bdp; + (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { /* don't check it */ skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -902,12 +1323,17 @@ fec_enet_rx(struct net_device *ndev, int budget) } } - if (!skb_defer_rx_timestamp(skb)) - napi_gro_receive(&fep->napi, skb); + /* Handle received VLAN packets */ + if (vlan_packet_rcvd) + __vlan_hwaccel_put_tag(skb, + htons(ETH_P_8021Q), + vlan_tag); + + napi_gro_receive(&fep->napi, skb); } - bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, - FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); + dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); rx_processing_done: /* Clear the status flags for this buffer */ status &= ~BD_ENET_RX_STATS; @@ -925,10 +1351,8 @@ rx_processing_done: } /* Update BD pointer to next entry */ - if (status & BD_ENET_RX_WRAP) - bdp = fep->rx_bd_base; - else - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); + /* Doing this here will keep the FEC running while we process * incoming frames. On a heavily loaded network, we should be * able to keep up at the expense of system resources. @@ -991,7 +1415,7 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget) static void fec_get_mac(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - struct fec_platform_data *pdata = fep->pdev->dev.platform_data; + struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev); unsigned char *iap, tmpaddr[ETH_ALEN]; /* @@ -1031,10 +1455,10 @@ static void fec_get_mac(struct net_device *ndev) * 4) FEC mac registers set by bootloader */ if (!is_valid_ether_addr(iap)) { - *((unsigned long *) &tmpaddr[0]) = - be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW)); - *((unsigned short *) &tmpaddr[4]) = - be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16); + *((__be32 *) &tmpaddr[0]) = + cpu_to_be32(readl(fep->hwp + FEC_ADDR_LOW)); + *((__be16 *) &tmpaddr[4]) = + cpu_to_be16(readl(fep->hwp + FEC_ADDR_HIGH) >> 16); iap = &tmpaddr[0]; } @@ -1156,9 +1580,47 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, return 0; } -static int fec_enet_mdio_reset(struct mii_bus *bus) +static int fec_enet_clk_enable(struct net_device *ndev, bool enable) { + struct fec_enet_private *fep = netdev_priv(ndev); + int ret; + + if (enable) { + ret = clk_prepare_enable(fep->clk_ahb); + if (ret) + return ret; + ret = clk_prepare_enable(fep->clk_ipg); + if (ret) + goto failed_clk_ipg; + if (fep->clk_enet_out) { + ret = clk_prepare_enable(fep->clk_enet_out); + if (ret) + goto failed_clk_enet_out; + } + if (fep->clk_ptp) { + ret = clk_prepare_enable(fep->clk_ptp); + if (ret) + goto failed_clk_ptp; + } + } else { + clk_disable_unprepare(fep->clk_ahb); + clk_disable_unprepare(fep->clk_ipg); + if (fep->clk_enet_out) + clk_disable_unprepare(fep->clk_enet_out); + if (fep->clk_ptp) + clk_disable_unprepare(fep->clk_ptp); + } + return 0; +failed_clk_ptp: + if (fep->clk_enet_out) + clk_disable_unprepare(fep->clk_enet_out); +failed_clk_enet_out: + clk_disable_unprepare(fep->clk_ipg); +failed_clk_ipg: + clk_disable_unprepare(fep->clk_ahb); + + return ret; } static int fec_enet_mii_probe(struct net_device *ndev) @@ -1205,7 +1667,9 @@ static int fec_enet_mii_probe(struct net_device *ndev) /* mask with MAC supported features */ if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) { phy_dev->supported &= PHY_GBIT_FEATURES; +#if !defined(CONFIG_M5272) phy_dev->supported |= SUPPORTED_Pause; +#endif } else phy_dev->supported &= PHY_BASIC_FEATURES; @@ -1268,7 +1732,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) * Reference Manual has an error on this, and gets fixed on i.MX6Q * document. */ - fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ahb), 5000000); + fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000); if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) fep->phy_speed--; fep->phy_speed <<= 1; @@ -1283,7 +1747,6 @@ static int fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->name = "fec_enet_mii_bus"; fep->mii_bus->read = fec_enet_mdio_read; fep->mii_bus->write = fec_enet_mdio_write; - fep->mii_bus->reset = fec_enet_mdio_reset; snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, fep->dev_id + 1); fep->mii_bus->priv = fep; @@ -1390,6 +1853,8 @@ static int fec_enet_get_ts_info(struct net_device *ndev, } } +#if !defined(CONFIG_M5272) + static void fec_enet_get_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause) { @@ -1436,14 +1901,133 @@ static int fec_enet_set_pauseparam(struct net_device *ndev, return 0; } +static const struct fec_stat { + char name[ETH_GSTRING_LEN]; + u16 offset; +} fec_stats[] = { + /* RMON TX */ + { "tx_dropped", RMON_T_DROP }, + { "tx_packets", RMON_T_PACKETS }, + { "tx_broadcast", RMON_T_BC_PKT }, + { "tx_multicast", RMON_T_MC_PKT }, + { "tx_crc_errors", RMON_T_CRC_ALIGN }, + { "tx_undersize", RMON_T_UNDERSIZE }, + { "tx_oversize", RMON_T_OVERSIZE }, + { "tx_fragment", RMON_T_FRAG }, + { "tx_jabber", RMON_T_JAB }, + { "tx_collision", RMON_T_COL }, + { "tx_64byte", RMON_T_P64 }, + { "tx_65to127byte", RMON_T_P65TO127 }, + { "tx_128to255byte", RMON_T_P128TO255 }, + { "tx_256to511byte", RMON_T_P256TO511 }, + { "tx_512to1023byte", RMON_T_P512TO1023 }, + { "tx_1024to2047byte", RMON_T_P1024TO2047 }, + { "tx_GTE2048byte", RMON_T_P_GTE2048 }, + { "tx_octets", RMON_T_OCTETS }, + + /* IEEE TX */ + { "IEEE_tx_drop", IEEE_T_DROP }, + { "IEEE_tx_frame_ok", IEEE_T_FRAME_OK }, + { "IEEE_tx_1col", IEEE_T_1COL }, + { "IEEE_tx_mcol", IEEE_T_MCOL }, + { "IEEE_tx_def", IEEE_T_DEF }, + { "IEEE_tx_lcol", IEEE_T_LCOL }, + { "IEEE_tx_excol", IEEE_T_EXCOL }, + { "IEEE_tx_macerr", IEEE_T_MACERR }, + { "IEEE_tx_cserr", IEEE_T_CSERR }, + { "IEEE_tx_sqe", IEEE_T_SQE }, + { "IEEE_tx_fdxfc", IEEE_T_FDXFC }, + { "IEEE_tx_octets_ok", IEEE_T_OCTETS_OK }, + + /* RMON RX */ + { "rx_packets", RMON_R_PACKETS }, + { "rx_broadcast", RMON_R_BC_PKT }, + { "rx_multicast", RMON_R_MC_PKT }, + { "rx_crc_errors", RMON_R_CRC_ALIGN }, + { "rx_undersize", RMON_R_UNDERSIZE }, + { "rx_oversize", RMON_R_OVERSIZE }, + { "rx_fragment", RMON_R_FRAG }, + { "rx_jabber", RMON_R_JAB }, + { "rx_64byte", RMON_R_P64 }, + { "rx_65to127byte", RMON_R_P65TO127 }, + { "rx_128to255byte", RMON_R_P128TO255 }, + { "rx_256to511byte", RMON_R_P256TO511 }, + { "rx_512to1023byte", RMON_R_P512TO1023 }, + { "rx_1024to2047byte", RMON_R_P1024TO2047 }, + { "rx_GTE2048byte", RMON_R_P_GTE2048 }, + { "rx_octets", RMON_R_OCTETS }, + + /* IEEE RX */ + { "IEEE_rx_drop", IEEE_R_DROP }, + { "IEEE_rx_frame_ok", IEEE_R_FRAME_OK }, + { "IEEE_rx_crc", IEEE_R_CRC }, + { "IEEE_rx_align", IEEE_R_ALIGN }, + { "IEEE_rx_macerr", IEEE_R_MACERR }, + { "IEEE_rx_fdxfc", IEEE_R_FDXFC }, + { "IEEE_rx_octets_ok", IEEE_R_OCTETS_OK }, +}; + +static void fec_enet_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct fec_enet_private *fep = netdev_priv(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(fec_stats); i++) + data[i] = readl(fep->hwp + fec_stats[i].offset); +} + +static void fec_enet_get_strings(struct net_device *netdev, + u32 stringset, u8 *data) +{ + int i; + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(fec_stats); i++) + memcpy(data + i * ETH_GSTRING_LEN, + fec_stats[i].name, ETH_GSTRING_LEN); + break; + } +} + +static int fec_enet_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(fec_stats); + default: + return -EOPNOTSUPP; + } +} +#endif /* !defined(CONFIG_M5272) */ + +static int fec_enet_nway_reset(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev = fep->phy_dev; + + if (!phydev) + return -ENODEV; + + return genphy_restart_aneg(phydev); +} + static const struct ethtool_ops fec_enet_ethtool_ops = { +#if !defined(CONFIG_M5272) .get_pauseparam = fec_enet_get_pauseparam, .set_pauseparam = fec_enet_set_pauseparam, +#endif .get_settings = fec_enet_get_settings, .set_settings = fec_enet_set_settings, .get_drvinfo = fec_enet_get_drvinfo, .get_link = ethtool_op_get_link, .get_ts_info = fec_enet_get_ts_info, + .nway_reset = fec_enet_nway_reset, +#ifndef CONFIG_M5272 + .get_ethtool_stats = fec_enet_get_ethtool_stats, + .get_strings = fec_enet_get_strings, + .get_sset_count = fec_enet_get_sset_count, +#endif }; static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -1457,8 +2041,12 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) if (!phydev) return -ENODEV; - if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex) - return fec_ptp_ioctl(ndev, rq, cmd); + if (fep->bufdesc_ex) { + if (cmd == SIOCSHWTSTAMP) + return fec_ptp_set(ndev, rq); + if (cmd == SIOCGHWTSTAMP) + return fec_ptp_get(ndev, rq); + } return phy_mii_ioctl(phydev, rq, cmd); } @@ -1471,7 +2059,7 @@ static void fec_enet_free_buffers(struct net_device *ndev) struct bufdesc *bdp; bdp = fep->rx_bd_base; - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < fep->rx_ring_size; i++) { skb = fep->rx_skbuff[i]; if (bdp->cbd_bufaddr) @@ -1479,11 +2067,11 @@ static void fec_enet_free_buffers(struct net_device *ndev) FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); if (skb) dev_kfree_skb(skb); - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); } bdp = fep->tx_bd_base; - for (i = 0; i < TX_RING_SIZE; i++) + for (i = 0; i < fep->tx_ring_size; i++) kfree(fep->tx_bounce[i]); } @@ -1495,7 +2083,7 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) struct bufdesc *bdp; bdp = fep->rx_bd_base; - for (i = 0; i < RX_RING_SIZE; i++) { + for (i = 0; i < fep->rx_ring_size; i++) { skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); if (!skb) { fec_enet_free_buffers(ndev); @@ -1505,6 +2093,12 @@ 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); + if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + fec_enet_free_buffers(ndev); + if (net_ratelimit()) + netdev_err(ndev, "Rx DMA memory map failed\n"); + return -ENOMEM; + } bdp->cbd_sc = BD_ENET_RX_EMPTY; if (fep->bufdesc_ex) { @@ -1512,15 +2106,15 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) ebdp->cbd_esc = BD_ENET_RX_INT; } - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); } /* Set the last buffer to wrap. */ - bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_prevdesc(bdp, fep); bdp->cbd_sc |= BD_SC_WRAP; bdp = fep->tx_bd_base; - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < fep->tx_ring_size; i++) { fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); bdp->cbd_sc = 0; @@ -1531,11 +2125,11 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) ebdp->cbd_esc = BD_ENET_TX_INT; } - bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_nextdesc(bdp, fep); } /* Set the last buffer to wrap. */ - bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + bdp = fec_enet_get_prevdesc(bdp, fep); bdp->cbd_sc |= BD_SC_WRAP; return 0; @@ -1547,7 +2141,10 @@ fec_enet_open(struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); int ret; - napi_enable(&fep->napi); + pinctrl_pm_select_default_state(&fep->pdev->dev); + ret = fec_enet_clk_enable(ndev, true); + if (ret) + return ret; /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. @@ -1563,6 +2160,8 @@ fec_enet_open(struct net_device *ndev) fec_enet_free_buffers(ndev); return ret; } + + napi_enable(&fep->napi); phy_start(fep->phy_dev); netif_start_queue(ndev); fep->opened = 1; @@ -1585,6 +2184,8 @@ fec_enet_close(struct net_device *ndev) phy_disconnect(fep->phy_dev); } + fec_enet_clk_enable(ndev, false); + pinctrl_pm_select_sleep_state(&fep->pdev->dev); fec_enet_free_buffers(ndev); return 0; @@ -1672,10 +2273,11 @@ fec_set_mac_address(struct net_device *ndev, void *p) struct fec_enet_private *fep = netdev_priv(ndev); struct sockaddr *addr = p; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + if (addr) { + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + } writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) | (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24), @@ -1761,27 +2363,51 @@ static int fec_enet_init(struct net_device *ndev) const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); struct bufdesc *cbd_base; + int bd_size; + + /* init the tx & rx ring size */ + fep->tx_ring_size = TX_RING_SIZE; + fep->rx_ring_size = RX_RING_SIZE; + + fep->tx_stop_threshold = FEC_MAX_SKB_DESCS; + fep->tx_wake_threshold = (fep->tx_ring_size - fep->tx_stop_threshold) / 2; + + if (fep->bufdesc_ex) + fep->bufdesc_size = sizeof(struct bufdesc_ex); + else + fep->bufdesc_size = sizeof(struct bufdesc); + bd_size = (fep->tx_ring_size + fep->rx_ring_size) * + fep->bufdesc_size; /* Allocate memory for buffer descriptors. */ - cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, + cbd_base = dma_alloc_coherent(NULL, bd_size, &fep->bd_dma, GFP_KERNEL); if (!cbd_base) return -ENOMEM; + fep->tso_hdrs = dma_alloc_coherent(NULL, fep->tx_ring_size * TSO_HEADER_SIZE, + &fep->tso_hdrs_dma, GFP_KERNEL); + if (!fep->tso_hdrs) { + dma_free_coherent(NULL, bd_size, cbd_base, fep->bd_dma); + return -ENOMEM; + } + memset(cbd_base, 0, PAGE_SIZE); fep->netdev = ndev; /* Get the Ethernet address */ fec_get_mac(ndev); + /* make sure MAC we just acquired is programmed into the hw */ + fec_set_mac_address(ndev, NULL); /* Set receive and transmit descriptor base. */ fep->rx_bd_base = cbd_base; if (fep->bufdesc_ex) fep->tx_bd_base = (struct bufdesc *) - (((struct bufdesc_ex *)cbd_base) + RX_RING_SIZE); + (((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size); else - fep->tx_bd_base = cbd_base + RX_RING_SIZE; + fep->tx_bd_base = cbd_base + fep->rx_ring_size; /* The FEC Ethernet specific entries in the device structure */ ndev->watchdog_timeo = TX_TIMEOUT; @@ -1789,17 +2415,23 @@ static int fec_enet_init(struct net_device *ndev) ndev->ethtool_ops = &fec_enet_ethtool_ops; writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK); - netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT); + netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT); + + if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN) + /* enable hw VLAN support */ + ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) { + ndev->gso_max_segs = FEC_MAX_TSO_SEGS; + /* enable hw accelerator */ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM - | NETIF_F_RXCSUM); - ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM - | NETIF_F_RXCSUM); + | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO); fep->csum_flags |= FLAG_RX_CSUM_ENABLED; } + ndev->hw_features = ndev->features; + fec_restart(ndev, 0); return 0; @@ -1853,17 +2485,11 @@ fec_probe(struct platform_device *pdev) struct resource *r; const struct of_device_id *of_id; static int dev_id; - struct pinctrl *pinctrl; - struct regulator *reg_phy; of_id = of_match_device(fec_dt_ids, &pdev->dev); if (of_id) pdev->id_entry = of_id->data; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; - /* Init network device */ ndev = alloc_etherdev(sizeof(struct fec_enet_private)); if (!ndev) @@ -1874,27 +2500,33 @@ fec_probe(struct platform_device *pdev) /* setup board info structure */ fep = netdev_priv(ndev); +#if !defined(CONFIG_M5272) /* default enable pause frame auto negotiation */ if (pdev->id_entry && (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT)) fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG; +#endif + + /* Select default pin state */ + pinctrl_pm_select_default_state(&pdev->dev); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fep->hwp = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(fep->hwp)) { + ret = PTR_ERR(fep->hwp); + goto failed_ioremap; + } - fep->hwp = devm_request_and_ioremap(&pdev->dev, r); fep->pdev = pdev; fep->dev_id = dev_id++; fep->bufdesc_ex = 0; - if (!fep->hwp) { - ret = -ENOMEM; - goto failed_ioremap; - } - platform_set_drvdata(pdev, ndev); ret = of_get_phy_mode(pdev->dev.of_node); if (ret < 0) { - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (pdata) fep->phy_interface = pdata->phy; else @@ -1903,12 +2535,6 @@ fec_probe(struct platform_device *pdev) fep->phy_interface = ret; } - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - ret = PTR_ERR(pinctrl); - goto failed_pin; - } - fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(fep->clk_ipg)) { ret = PTR_ERR(fep->clk_ipg); @@ -1934,25 +2560,26 @@ fec_probe(struct platform_device *pdev) fep->bufdesc_ex = 0; } - clk_prepare_enable(fep->clk_ahb); - clk_prepare_enable(fep->clk_ipg); - clk_prepare_enable(fep->clk_enet_out); - clk_prepare_enable(fep->clk_ptp); + ret = fec_enet_clk_enable(ndev, true); + if (ret) + goto failed_clk; - reg_phy = devm_regulator_get(&pdev->dev, "phy"); - if (!IS_ERR(reg_phy)) { - ret = regulator_enable(reg_phy); + fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); + if (!IS_ERR(fep->reg_phy)) { + ret = regulator_enable(fep->reg_phy); if (ret) { dev_err(&pdev->dev, "Failed to enable phy regulator: %d\n", ret); goto failed_regulator; } + } else { + fep->reg_phy = NULL; } fec_reset_phy(pdev); if (fep->bufdesc_ex) - fec_ptp_init(ndev, pdev); + fec_ptp_init(pdev); ret = fec_enet_init(ndev); if (ret) @@ -1966,14 +2593,10 @@ fec_probe(struct platform_device *pdev) ret = irq; goto failed_irq; } - ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); - if (ret) { - while (--i >= 0) { - irq = platform_get_irq(pdev, i); - free_irq(irq, ndev); - } + ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt, + 0, pdev->name, ndev); + if (ret) goto failed_irq; - } } ret = fec_enet_mii_init(pdev); @@ -1982,6 +2605,8 @@ fec_probe(struct platform_device *pdev) /* Carrier starts down, phylib will bring it up */ netif_carrier_off(ndev); + fec_enet_clk_enable(ndev, false); + pinctrl_pm_select_sleep_state(&pdev->dev); ret = register_netdev(ndev); if (ret) @@ -1996,19 +2621,12 @@ fec_probe(struct platform_device *pdev) failed_register: fec_enet_mii_remove(fep); failed_mii_init: -failed_init: - for (i = 0; i < FEC_IRQ_NUM; i++) { - irq = platform_get_irq(pdev, i); - if (irq > 0) - free_irq(irq, ndev); - } failed_irq: +failed_init: + if (fep->reg_phy) + regulator_disable(fep->reg_phy); failed_regulator: - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); - clk_disable_unprepare(fep->clk_enet_out); - clk_disable_unprepare(fep->clk_ptp); -failed_pin: + fec_enet_clk_enable(ndev, false); failed_clk: failed_ioremap: free_netdev(ndev); @@ -2021,27 +2639,18 @@ fec_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); - int i; cancel_delayed_work_sync(&(fep->delay_work.delay_work)); unregister_netdev(ndev); fec_enet_mii_remove(fep); del_timer_sync(&fep->time_keep); - clk_disable_unprepare(fep->clk_ptp); + if (fep->reg_phy) + regulator_disable(fep->reg_phy); if (fep->ptp_clock) ptp_clock_unregister(fep->ptp_clock); - clk_disable_unprepare(fep->clk_enet_out); - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); - for (i = 0; i < FEC_IRQ_NUM; i++) { - int irq = platform_get_irq(pdev, i); - if (irq > 0) - free_irq(irq, ndev); - } + fec_enet_clk_enable(ndev, false); free_netdev(ndev); - platform_set_drvdata(pdev, NULL); - return 0; } @@ -2056,9 +2665,11 @@ fec_suspend(struct device *dev) fec_stop(ndev); netif_device_detach(ndev); } - clk_disable_unprepare(fep->clk_enet_out); - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); + fec_enet_clk_enable(ndev, false); + pinctrl_pm_select_sleep_state(&fep->pdev->dev); + + if (fep->reg_phy) + regulator_disable(fep->reg_phy); return 0; } @@ -2068,16 +2679,30 @@ fec_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); + int ret; + + if (fep->reg_phy) { + ret = regulator_enable(fep->reg_phy); + if (ret) + return ret; + } + + pinctrl_pm_select_default_state(&fep->pdev->dev); + ret = fec_enet_clk_enable(ndev, true); + if (ret) + goto failed_clk; - clk_prepare_enable(fep->clk_enet_out); - clk_prepare_enable(fep->clk_ahb); - clk_prepare_enable(fep->clk_ipg); if (netif_running(ndev)) { fec_restart(ndev, fep->full_duplex); netif_device_attach(ndev); } return 0; + +failed_clk: + if (fep->reg_phy) + regulator_disable(fep->reg_phy); + return ret; } #endif /* CONFIG_PM_SLEEP */ @@ -2097,4 +2722,5 @@ static struct platform_driver fec_driver = { module_platform_driver(fec_driver); +MODULE_ALIAS("platform:"DRIVER_NAME); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c index 9bc15e2365b..9947765e90c 100644 --- a/drivers/net/ethernet/freescale/fec_mpc52xx.c +++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c @@ -981,7 +981,7 @@ static int mpc52xx_fec_probe(struct platform_device *op) goto err_node; /* We're done ! */ - dev_set_drvdata(&op->dev, ndev); + platform_set_drvdata(op, ndev); netdev_info(ndev, "%s MAC %pM\n", op->dev.of_node->full_name, ndev->dev_addr); @@ -1010,7 +1010,7 @@ mpc52xx_fec_remove(struct platform_device *op) struct net_device *ndev; struct mpc52xx_fec_priv *priv; - ndev = dev_get_drvdata(&op->dev); + ndev = platform_get_drvdata(op); priv = netdev_priv(ndev); unregister_netdev(ndev); @@ -1030,14 +1030,13 @@ mpc52xx_fec_remove(struct platform_device *op) free_netdev(ndev); - dev_set_drvdata(&op->dev, NULL); return 0; } #ifdef CONFIG_PM static int mpc52xx_fec_of_suspend(struct platform_device *op, pm_message_t state) { - struct net_device *dev = dev_get_drvdata(&op->dev); + struct net_device *dev = platform_get_drvdata(op); if (netif_running(dev)) mpc52xx_fec_close(dev); @@ -1047,7 +1046,7 @@ static int mpc52xx_fec_of_suspend(struct platform_device *op, pm_message_t state static int mpc52xx_fec_of_resume(struct platform_device *op) { - struct net_device *dev = dev_get_drvdata(&op->dev); + struct net_device *dev = platform_get_drvdata(op); mpc52xx_fec_hw_init(dev); mpc52xx_fec_reset_stats(dev); diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c index 360a578c2bb..e0528900db0 100644 --- a/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c +++ b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c @@ -123,12 +123,10 @@ static int mpc52xx_fec_mdio_probe(struct platform_device *of) static int mpc52xx_fec_mdio_remove(struct platform_device *of) { - struct device *dev = &of->dev; - struct mii_bus *bus = dev_get_drvdata(dev); + struct mii_bus *bus = platform_get_drvdata(of); struct mpc52xx_fec_mdio_priv *priv = bus->priv; mdiobus_unregister(bus); - dev_set_drvdata(dev, NULL); iounmap(priv->regs); kfree(priv); mdiobus_free(bus); diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 25fc960cbf0..82386b29914 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -28,7 +28,6 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -274,7 +273,7 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, * @ifreq: ioctl data * @cmd: particular ioctl requested */ -int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr) { struct fec_enet_private *fep = netdev_priv(ndev); @@ -321,6 +320,20 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) -EFAULT : 0; } +int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + struct hwtstamp_config config; + + config.flags = 0; + config.tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + config.rx_filter = (fep->hwts_rx_en ? + HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE); + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + /** * fec_time_keep - call timecounter_read every second to avoid timer overrun * because ENET just support 32bit counter, will timeout in 4s @@ -347,8 +360,9 @@ static void fec_time_keep(unsigned long _data) * cyclecounter init routine and exits. */ -void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev) +void fec_ptp_init(struct platform_device *pdev) { + struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); fep->ptp_caps.owner = THIS_MODULE; @@ -358,6 +372,7 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev) fep->ptp_caps.n_alarm = 0; fep->ptp_caps.n_ext_ts = 0; fep->ptp_caps.n_per_out = 0; + fep->ptp_caps.n_pins = 0; fep->ptp_caps.pps = 0; fep->ptp_caps.adjfreq = fec_ptp_adjfreq; fep->ptp_caps.adjtime = fec_ptp_adjtime; diff --git a/drivers/net/ethernet/freescale/fs_enet/Kconfig b/drivers/net/ethernet/freescale/fs_enet/Kconfig index 268414d9f2c..be92229f2c2 100644 --- a/drivers/net/ethernet/freescale/fs_enet/Kconfig +++ b/drivers/net/ethernet/freescale/fs_enet/Kconfig @@ -1,7 +1,6 @@ config FS_ENET tristate "Freescale Ethernet Driver" depends on NET_VENDOR_FREESCALE && (CPM1 || CPM2 || PPC_MPC512x) - select NET_CORE select MII select PHYLIB diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index edc120094c3..cfaf17b70f3 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -24,7 +24,6 @@ #include <linux/ioport.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -92,6 +91,9 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) u16 pkt_len, sc; int curidx; + if (budget <= 0) + return received; + /* * First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. @@ -583,7 +585,6 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev, struct sk_buff *skb) { struct sk_buff *new_skb; - struct fs_enet_private *fep = netdev_priv(dev); /* Alloc new skb */ new_skb = netdev_alloc_skb(dev, skb->len + 4); @@ -791,10 +792,6 @@ static int fs_init_phy(struct net_device *dev) phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0, iface); if (!phydev) { - phydev = of_phy_connect_fixed_link(dev, &fs_adjust_link, - iface); - } - if (!phydev) { dev_err(&dev->dev, "Could not attach to PHY\n"); return -ENODEV; } @@ -1000,6 +997,8 @@ static int fs_enet_probe(struct platform_device *ofdev) struct fs_enet_private *fep; struct fs_platform_info *fpi; const u32 *data; + struct clk *clk; + int err; const u8 *mac_addr; const char *phy_connection_type; int privsize, len, ret = -ENODEV; @@ -1026,9 +1025,16 @@ static int fs_enet_probe(struct platform_device *ofdev) fpi->use_napi = 1; fpi->napi_weight = 17; fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); - if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link", - NULL))) - goto out_free_fpi; + if (!fpi->phy_node && of_phy_is_fixed_link(ofdev->dev.of_node)) { + err = of_phy_register_fixed_link(ofdev->dev.of_node); + if (err) + goto out_free_fpi; + + /* In the case of a fixed PHY, the DT node associated + * to the PHY is the Ethernet MAC DT node. + */ + fpi->phy_node = ofdev->dev.of_node; + } if (of_device_is_compatible(ofdev->dev.of_node, "fsl,mpc5125-fec")) { phy_connection_type = of_get_property(ofdev->dev.of_node, @@ -1037,6 +1043,20 @@ static int fs_enet_probe(struct platform_device *ofdev) fpi->use_rmii = 1; } + /* make clock lookup non-fatal (the driver is shared among platforms), + * but require enable to succeed when a clock was specified/found, + * keep a reference to the clock upon successful acquisition + */ + clk = devm_clk_get(&ofdev->dev, "per"); + if (!IS_ERR(clk)) { + err = clk_prepare_enable(clk); + if (err) { + ret = err; + goto out_free_fpi; + } + fpi->clk_per = clk; + } + privsize = sizeof(*fep) + sizeof(struct sk_buff **) * (fpi->rx_ring + fpi->tx_ring); @@ -1048,7 +1068,7 @@ static int fs_enet_probe(struct platform_device *ofdev) } SET_NETDEV_DEV(ndev, &ofdev->dev); - dev_set_drvdata(&ofdev->dev, ndev); + platform_set_drvdata(ofdev, ndev); fep = netdev_priv(ndev); fep->dev = &ofdev->dev; @@ -1068,7 +1088,7 @@ static int fs_enet_probe(struct platform_device *ofdev) mac_addr = of_get_mac_address(ofdev->dev.of_node); if (mac_addr) - memcpy(ndev->dev_addr, mac_addr, 6); + memcpy(ndev->dev_addr, mac_addr, ETH_ALEN); ret = fep->ops->allocate_bd(ndev); if (ret) @@ -1106,9 +1126,10 @@ out_cleanup_data: fep->ops->cleanup_data(ndev); out_free_dev: free_netdev(ndev); - dev_set_drvdata(&ofdev->dev, NULL); out_put: of_node_put(fpi->phy_node); + if (fpi->clk_per) + clk_disable_unprepare(fpi->clk_per); out_free_fpi: kfree(fpi); return ret; @@ -1116,7 +1137,7 @@ out_free_fpi: static int fs_enet_remove(struct platform_device *ofdev) { - struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct net_device *ndev = platform_get_drvdata(ofdev); struct fs_enet_private *fep = netdev_priv(ndev); unregister_netdev(ndev); @@ -1125,6 +1146,8 @@ static int fs_enet_remove(struct platform_device *ofdev) fep->ops->cleanup_data(ndev); dev_set_drvdata(fep->dev, NULL); of_node_put(fep->fpi->phy_node); + if (fep->fpi->clk_per) + clk_disable_unprepare(fep->fpi->clk_per); free_netdev(ndev); return 0; } diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c index 7583a9572bc..f5383abbf39 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c @@ -20,7 +20,6 @@ #include <linux/errno.h> #include <linux/ioport.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -32,7 +31,9 @@ #include <linux/fs.h> #include <linux/platform_device.h> #include <linux/phy.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/gfp.h> #include <asm/immap_cpm2.h> @@ -88,7 +89,7 @@ static int do_pd_setup(struct fs_enet_private *fep) struct fs_platform_info *fpi = fep->fpi; int ret = -EINVAL; - fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); + fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (fep->interrupt == NO_IRQ) goto out; diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c index 9ae6cdbcac2..fc541348849 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c @@ -20,7 +20,6 @@ #include <linux/errno.h> #include <linux/ioport.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -31,7 +30,9 @@ #include <linux/bitops.h> #include <linux/fs.h> #include <linux/platform_device.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/gfp.h> #include <asm/irq.h> @@ -98,7 +99,7 @@ static int do_pd_setup(struct fs_enet_private *fep) { struct platform_device *ofdev = to_platform_device(fep->dev); - fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); + fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (fep->interrupt == NO_IRQ) return -EINVAL; diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c index 22a02a76706..b4bf02f57d4 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c @@ -20,7 +20,6 @@ #include <linux/errno.h> #include <linux/ioport.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -31,6 +30,8 @@ #include <linux/bitops.h> #include <linux/fs.h> #include <linux/platform_device.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/irq.h> @@ -98,7 +99,7 @@ static int do_pd_setup(struct fs_enet_private *fep) { struct platform_device *ofdev = to_platform_device(fep->dev); - fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); + fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (fep->interrupt == NO_IRQ) return -EINVAL; diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c index 2bafbd37c24..3d3fde66c2c 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c @@ -15,13 +15,13 @@ #include <linux/module.h> #include <linux/ioport.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/mii.h> #include <linux/platform_device.h> #include <linux/mdio-bitbang.h> +#include <linux/of_address.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> @@ -179,7 +179,7 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev) } new_bus->parent = &ofdev->dev; - dev_set_drvdata(&ofdev->dev, new_bus); + platform_set_drvdata(ofdev, new_bus); ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); if (ret) @@ -188,7 +188,6 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev) return 0; out_free_irqs: - dev_set_drvdata(&ofdev->dev, NULL); kfree(new_bus->irq); out_unmap_regs: iounmap(bitbang->dir); @@ -202,11 +201,10 @@ out: static int fs_enet_mdio_remove(struct platform_device *ofdev) { - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct mii_bus *bus = platform_get_drvdata(ofdev); struct bb_info *bitbang = bus->priv; mdiobus_unregister(bus); - dev_set_drvdata(&ofdev->dev, NULL); kfree(bus->irq); free_mdio_bitbang(bus); iounmap(bitbang->dir); diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c index 18e8ef20373..ebf5d6429a8 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c @@ -21,7 +21,6 @@ #include <linux/ioport.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -31,6 +30,7 @@ #include <linux/ethtool.h> #include <linux/bitops.h> #include <linux/platform_device.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/pgtable.h> @@ -95,12 +95,6 @@ static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, } -static int fs_enet_fec_mii_reset(struct mii_bus *bus) -{ - /* nothing here - for now */ - return 0; -} - static struct of_device_id fs_enet_mdio_fec_match[]; static int fs_enet_mdio_probe(struct platform_device *ofdev) { @@ -128,7 +122,6 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev) new_bus->name = "FEC MII Bus"; new_bus->read = &fs_enet_fec_mii_read; new_bus->write = &fs_enet_fec_mii_write; - new_bus->reset = &fs_enet_fec_mii_reset; ret = of_address_to_resource(ofdev->dev.of_node, 0, &res); if (ret) @@ -180,7 +173,7 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev) } new_bus->parent = &ofdev->dev; - dev_set_drvdata(&ofdev->dev, new_bus); + platform_set_drvdata(ofdev, new_bus); ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); if (ret) @@ -189,7 +182,6 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev) return 0; out_free_irqs: - dev_set_drvdata(&ofdev->dev, NULL); kfree(new_bus->irq); out_unmap_regs: iounmap(fec->fecp); @@ -204,11 +196,10 @@ out: static int fs_enet_mdio_remove(struct platform_device *ofdev) { - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct mii_bus *bus = platform_get_drvdata(ofdev); struct fec_info *fec = bus->priv; mdiobus_unregister(bus); - dev_set_drvdata(&ofdev->dev, NULL); kfree(bus->irq); iounmap(fec->fecp); kfree(fec); diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index c93a05654b4..583e71ab7f5 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -20,7 +20,6 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/mii.h> @@ -409,7 +408,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) priv->regs = priv->map + data->mii_offset; new_bus->parent = &pdev->dev; - dev_set_drvdata(&pdev->dev, new_bus); + platform_set_drvdata(pdev, new_bus); if (data->get_tbipa) { for_each_child_of_node(np, tbi) { @@ -468,8 +467,6 @@ static int fsl_pq_mdio_remove(struct platform_device *pdev) mdiobus_unregister(bus); - dev_set_drvdata(device, NULL); - iounmap(priv->map); mdiobus_free(bus); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 2375a01715a..a6cf40e62f3 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -9,7 +9,7 @@ * Maintainer: Kumar Gala * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> * - * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc. + * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc. * Copyright 2007 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it @@ -70,7 +70,6 @@ #include <linux/unistd.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -78,6 +77,8 @@ #include <linux/if_vlan.h> #include <linux/spinlock.h> #include <linux/mm.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> #include <linux/ip.h> @@ -88,6 +89,7 @@ #include <asm/io.h> #include <asm/reg.h> +#include <asm/mpc85xx.h> #include <asm/irq.h> #include <asm/uaccess.h> #include <linux/module.h> @@ -119,7 +121,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id); static irqreturn_t gfar_transmit(int irq, void *dev_id); static irqreturn_t gfar_interrupt(int irq, void *dev_id); static void adjust_link(struct net_device *dev); -static void init_registers(struct net_device *dev); +static noinline void gfar_update_link_state(struct gfar_private *priv); static int init_phy(struct net_device *dev); static int gfar_probe(struct platform_device *ofdev); static int gfar_remove(struct platform_device *ofdev); @@ -127,7 +129,10 @@ static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); static void gfar_configure_serdes(struct net_device *dev); -static int gfar_poll(struct napi_struct *napi, int budget); +static int gfar_poll_rx(struct napi_struct *napi, int budget); +static int gfar_poll_tx(struct napi_struct *napi, int budget); +static int gfar_poll_rx_sq(struct napi_struct *napi, int budget); +static int gfar_poll_tx_sq(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void gfar_netpoll(struct net_device *dev); #endif @@ -135,9 +140,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int amount_pull, struct napi_struct *napi); -void gfar_halt(struct net_device *dev); -static void gfar_halt_nodisable(struct net_device *dev); -void gfar_start(struct net_device *dev); +static void gfar_halt_nodisable(struct gfar_private *priv); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, const u8 *addr); @@ -329,72 +332,76 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv) } } -static void gfar_init_mac(struct net_device *ndev) +static void gfar_rx_buff_size_config(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 rctrl = 0; - u32 tctrl = 0; - u32 attrs = 0; - - /* write the tx/rx base registers */ - gfar_init_tx_rx_base(priv); - - /* Configure the coalescing support */ - gfar_configure_coalescing_all(priv); + int frame_size = priv->ndev->mtu + ETH_HLEN; /* set this when rx hw offload (TOE) functions are being used */ priv->uses_rxfcb = 0; + if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX)) + priv->uses_rxfcb = 1; + + if (priv->hwts_rx_en) + priv->uses_rxfcb = 1; + + if (priv->uses_rxfcb) + frame_size += GMAC_FCB_LEN; + + frame_size += priv->padding; + + frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + + INCREMENTAL_BUFFER_SIZE; + + priv->rx_buffer_size = frame_size; +} + +static void gfar_mac_rx_config(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 rctrl = 0; + if (priv->rx_filer_enable) { rctrl |= RCTRL_FILREN; /* Program the RIR0 reg with the required distribution */ - gfar_write(®s->rir0, DEFAULT_RIR0); + if (priv->poll_mode == GFAR_SQ_POLLING) + gfar_write(®s->rir0, DEFAULT_2RXQ_RIR0); + else /* GFAR_MQ_POLLING */ + gfar_write(®s->rir0, DEFAULT_8RXQ_RIR0); } /* Restore PROMISC mode */ - if (ndev->flags & IFF_PROMISC) + if (priv->ndev->flags & IFF_PROMISC) rctrl |= RCTRL_PROM; - if (ndev->features & NETIF_F_RXCSUM) { + if (priv->ndev->features & NETIF_F_RXCSUM) rctrl |= RCTRL_CHECKSUMMING; - priv->uses_rxfcb = 1; - } - if (priv->extended_hash) { - rctrl |= RCTRL_EXTHASH; - - gfar_clear_exact_match(ndev); - rctrl |= RCTRL_EMEN; - } + if (priv->extended_hash) + rctrl |= RCTRL_EXTHASH | RCTRL_EMEN; if (priv->padding) { rctrl &= ~RCTRL_PAL_MASK; rctrl |= RCTRL_PADDING(priv->padding); } - /* Insert receive time stamps into padding alignment bytes */ - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) { - rctrl &= ~RCTRL_PAL_MASK; - rctrl |= RCTRL_PADDING(8); - priv->padding = 8; - } - /* Enable HW time stamping if requested from user space */ - if (priv->hwts_rx_en) { + if (priv->hwts_rx_en) rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; - priv->uses_rxfcb = 1; - } - if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; - priv->uses_rxfcb = 1; - } /* Init rctrl based on our settings */ gfar_write(®s->rctrl, rctrl); +} - if (ndev->features & NETIF_F_IP_CSUM) +static void gfar_mac_tx_config(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 tctrl = 0; + + if (priv->ndev->features & NETIF_F_IP_CSUM) tctrl |= TCTRL_INIT_CSUM; if (priv->prio_sched_en) @@ -405,30 +412,51 @@ static void gfar_init_mac(struct net_device *ndev) gfar_write(®s->tr47wt, DEFAULT_WRRS_WEIGHT); } - gfar_write(®s->tctrl, tctrl); + if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_TX) + tctrl |= TCTRL_VLINS; - /* Set the extraction length and index */ - attrs = ATTRELI_EL(priv->rx_stash_size) | - ATTRELI_EI(priv->rx_stash_index); + gfar_write(®s->tctrl, tctrl); +} - gfar_write(®s->attreli, attrs); +static void gfar_configure_coalescing(struct gfar_private *priv, + unsigned long tx_mask, unsigned long rx_mask) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 __iomem *baddr; - /* Start with defaults, and add stashing or locking - * depending on the approprate variables - */ - attrs = ATTR_INIT_SETTINGS; + if (priv->mode == MQ_MG_MODE) { + int i = 0; - if (priv->bd_stash_en) - attrs |= ATTR_BDSTASH; + baddr = ®s->txic0; + for_each_set_bit(i, &tx_mask, priv->num_tx_queues) { + gfar_write(baddr + i, 0); + if (likely(priv->tx_queue[i]->txcoalescing)) + gfar_write(baddr + i, priv->tx_queue[i]->txic); + } - if (priv->rx_stash_size != 0) - attrs |= ATTR_BUFSTASH; + baddr = ®s->rxic0; + for_each_set_bit(i, &rx_mask, priv->num_rx_queues) { + gfar_write(baddr + i, 0); + if (likely(priv->rx_queue[i]->rxcoalescing)) + gfar_write(baddr + i, priv->rx_queue[i]->rxic); + } + } else { + /* Backward compatible case -- even if we enable + * multiple queues, there's only single reg to program + */ + gfar_write(®s->txic, 0); + if (likely(priv->tx_queue[0]->txcoalescing)) + gfar_write(®s->txic, priv->tx_queue[0]->txic); - gfar_write(®s->attr, attrs); + gfar_write(®s->rxic, 0); + if (unlikely(priv->rx_queue[0]->rxcoalescing)) + gfar_write(®s->rxic, priv->rx_queue[0]->rxic); + } +} - gfar_write(®s->fifo_tx_thr, priv->fifo_threshold); - gfar_write(®s->fifo_tx_starve, priv->fifo_starve); - gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off); +void gfar_configure_coalescing_all(struct gfar_private *priv) +{ + gfar_configure_coalescing(priv, 0xFF, 0xFF); } static struct net_device_stats *gfar_get_stats(struct net_device *dev) @@ -476,12 +504,27 @@ static const struct net_device_ops gfar_netdev_ops = { #endif }; -void lock_rx_qs(struct gfar_private *priv) +static void gfar_ints_disable(struct gfar_private *priv) { int i; + for (i = 0; i < priv->num_grps; i++) { + struct gfar __iomem *regs = priv->gfargrp[i].regs; + /* Clear IEVENT */ + gfar_write(®s->ievent, IEVENT_INIT_CLEAR); - for (i = 0; i < priv->num_rx_queues; i++) - spin_lock(&priv->rx_queue[i]->rxlock); + /* Initialize IMASK */ + gfar_write(®s->imask, IMASK_INIT_CLEAR); + } +} + +static void gfar_ints_enable(struct gfar_private *priv) +{ + int i; + for (i = 0; i < priv->num_grps; i++) { + struct gfar __iomem *regs = priv->gfargrp[i].regs; + /* Unmask the interrupts we look for */ + gfar_write(®s->imask, IMASK_DEFAULT); + } } void lock_tx_qs(struct gfar_private *priv) @@ -492,23 +535,50 @@ void lock_tx_qs(struct gfar_private *priv) spin_lock(&priv->tx_queue[i]->txlock); } -void unlock_rx_qs(struct gfar_private *priv) +void unlock_tx_qs(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_rx_queues; i++) - spin_unlock(&priv->rx_queue[i]->rxlock); + for (i = 0; i < priv->num_tx_queues; i++) + spin_unlock(&priv->tx_queue[i]->txlock); } -void unlock_tx_qs(struct gfar_private *priv) +static int gfar_alloc_tx_queues(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_tx_queues; i++) - spin_unlock(&priv->tx_queue[i]->txlock); + for (i = 0; i < priv->num_tx_queues; i++) { + priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q), + GFP_KERNEL); + if (!priv->tx_queue[i]) + return -ENOMEM; + + priv->tx_queue[i]->tx_skbuff = NULL; + priv->tx_queue[i]->qindex = i; + priv->tx_queue[i]->dev = priv->ndev; + spin_lock_init(&(priv->tx_queue[i]->txlock)); + } + return 0; +} + +static int gfar_alloc_rx_queues(struct gfar_private *priv) +{ + int i; + + for (i = 0; i < priv->num_rx_queues; i++) { + priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q), + GFP_KERNEL); + if (!priv->rx_queue[i]) + return -ENOMEM; + + priv->rx_queue[i]->rx_skbuff = NULL; + priv->rx_queue[i]->qindex = i; + priv->rx_queue[i]->dev = priv->ndev; + } + return 0; } -static void free_tx_pointers(struct gfar_private *priv) +static void gfar_free_tx_queues(struct gfar_private *priv) { int i; @@ -516,7 +586,7 @@ static void free_tx_pointers(struct gfar_private *priv) kfree(priv->tx_queue[i]); } -static void free_rx_pointers(struct gfar_private *priv) +static void gfar_free_rx_queues(struct gfar_private *priv) { int i; @@ -550,23 +620,26 @@ static void disable_napi(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_grps; i++) - napi_disable(&priv->gfargrp[i].napi); + for (i = 0; i < priv->num_grps; i++) { + napi_disable(&priv->gfargrp[i].napi_rx); + napi_disable(&priv->gfargrp[i].napi_tx); + } } static void enable_napi(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_grps; i++) - napi_enable(&priv->gfargrp[i].napi); + for (i = 0; i < priv->num_grps; i++) { + napi_enable(&priv->gfargrp[i].napi_rx); + napi_enable(&priv->gfargrp[i].napi_tx); + } } static int gfar_parse_group(struct device_node *np, struct gfar_private *priv, const char *model) { struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps]; - u32 *queue_mask; int i; for (i = 0; i < GFAR_NUM_IRQS; i++) { @@ -592,20 +665,55 @@ static int gfar_parse_group(struct device_node *np, return -EINVAL; } - grp->grp_id = priv->num_grps; grp->priv = priv; spin_lock_init(&grp->grplock); if (priv->mode == MQ_MG_MODE) { - queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL); - grp->rx_bit_map = queue_mask ? - *queue_mask : (DEFAULT_MAPPING >> priv->num_grps); - queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL); - grp->tx_bit_map = queue_mask ? - *queue_mask : (DEFAULT_MAPPING >> priv->num_grps); + u32 *rxq_mask, *txq_mask; + rxq_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL); + txq_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL); + + if (priv->poll_mode == GFAR_SQ_POLLING) { + /* One Q per interrupt group: Q0 to G0, Q1 to G1 */ + grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps); + grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps); + } else { /* GFAR_MQ_POLLING */ + grp->rx_bit_map = rxq_mask ? + *rxq_mask : (DEFAULT_MAPPING >> priv->num_grps); + grp->tx_bit_map = txq_mask ? + *txq_mask : (DEFAULT_MAPPING >> priv->num_grps); + } } else { grp->rx_bit_map = 0xFF; grp->tx_bit_map = 0xFF; } + + /* bit_map's MSB is q0 (from q0 to q7) but, for_each_set_bit parses + * right to left, so we need to revert the 8 bits to get the q index + */ + grp->rx_bit_map = bitrev8(grp->rx_bit_map); + grp->tx_bit_map = bitrev8(grp->tx_bit_map); + + /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values, + * also assign queues to groups + */ + for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) { + if (!grp->rx_queue) + grp->rx_queue = priv->rx_queue[i]; + grp->num_rx_queues++; + grp->rstat |= (RSTAT_CLEAR_RHALT >> i); + priv->rqueue |= ((RQUEUE_EN0 | RQUEUE_EX0) >> i); + priv->rx_queue[i]->grp = grp; + } + + for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) { + if (!grp->tx_queue) + grp->tx_queue = priv->tx_queue[i]; + grp->num_tx_queues++; + grp->tstat |= (TSTAT_CLEAR_THALT >> i); + priv->tqueue |= (TQUEUE_EN0 >> i); + priv->tx_queue[i]->grp = grp; + } + priv->num_grps++; return 0; @@ -626,13 +734,45 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) const u32 *stash_idx; unsigned int num_tx_qs, num_rx_qs; u32 *tx_queues, *rx_queues; + unsigned short mode, poll_mode; if (!np || !of_device_is_available(np)) return -ENODEV; - /* parse the num of tx and rx queues */ + if (of_device_is_compatible(np, "fsl,etsec2")) { + mode = MQ_MG_MODE; + poll_mode = GFAR_SQ_POLLING; + } else { + mode = SQ_SG_MODE; + poll_mode = GFAR_SQ_POLLING; + } + + /* parse the num of HW tx and rx queues */ tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL); - num_tx_qs = tx_queues ? *tx_queues : 1; + rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); + + if (mode == SQ_SG_MODE) { + num_tx_qs = 1; + num_rx_qs = 1; + } else { /* MQ_MG_MODE */ + /* get the actual number of supported groups */ + unsigned int num_grps = of_get_available_child_count(np); + + if (num_grps == 0 || num_grps > MAXGROUPS) { + dev_err(&ofdev->dev, "Invalid # of int groups(%d)\n", + num_grps); + pr_err("Cannot do alloc_etherdev, aborting\n"); + return -EINVAL; + } + + if (poll_mode == GFAR_SQ_POLLING) { + num_tx_qs = num_grps; /* one txq per int group */ + num_rx_qs = num_grps; /* one rxq per int group */ + } else { /* GFAR_MQ_POLLING */ + num_tx_qs = tx_queues ? *tx_queues : 1; + num_rx_qs = rx_queues ? *rx_queues : 1; + } + } if (num_tx_qs > MAX_TX_QS) { pr_err("num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n", @@ -641,9 +781,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) return -EINVAL; } - rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); - num_rx_qs = rx_queues ? *rx_queues : 1; - if (num_rx_qs > MAX_RX_QS) { pr_err("num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n", num_rx_qs, MAX_RX_QS); @@ -659,10 +796,20 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv = netdev_priv(dev); priv->ndev = dev; + priv->mode = mode; + priv->poll_mode = poll_mode; + priv->num_tx_queues = num_tx_qs; netif_set_real_num_rx_queues(dev, num_rx_qs); priv->num_rx_queues = num_rx_qs; - priv->num_grps = 0x0; + + err = gfar_alloc_tx_queues(priv); + if (err) + goto tx_alloc_failed; + + err = gfar_alloc_rx_queues(priv); + if (err) + goto rx_alloc_failed; /* Init Rx queue filer rule set linked list */ INIT_LIST_HEAD(&priv->rx_list.list); @@ -675,52 +822,18 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv->gfargrp[i].regs = NULL; /* Parse and initialize group specific information */ - if (of_device_is_compatible(np, "fsl,etsec2")) { - priv->mode = MQ_MG_MODE; + if (priv->mode == MQ_MG_MODE) { for_each_child_of_node(np, child) { err = gfar_parse_group(child, priv, model); if (err) goto err_grp_init; } - } else { - priv->mode = SQ_SG_MODE; + } else { /* SQ_SG_MODE */ err = gfar_parse_group(np, priv, model); if (err) goto err_grp_init; } - for (i = 0; i < priv->num_tx_queues; i++) - priv->tx_queue[i] = NULL; - for (i = 0; i < priv->num_rx_queues; i++) - priv->rx_queue[i] = NULL; - - for (i = 0; i < priv->num_tx_queues; i++) { - priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q), - GFP_KERNEL); - if (!priv->tx_queue[i]) { - err = -ENOMEM; - goto tx_alloc_failed; - } - priv->tx_queue[i]->tx_skbuff = NULL; - priv->tx_queue[i]->qindex = i; - priv->tx_queue[i]->dev = dev; - spin_lock_init(&(priv->tx_queue[i]->txlock)); - } - - for (i = 0; i < priv->num_rx_queues; i++) { - priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q), - GFP_KERNEL); - if (!priv->rx_queue[i]) { - err = -ENOMEM; - goto rx_alloc_failed; - } - priv->rx_queue[i]->rx_skbuff = NULL; - priv->rx_queue[i]->qindex = i; - priv->rx_queue[i]->dev = dev; - spin_lock_init(&(priv->rx_queue[i]->rxlock)); - } - - stash = of_get_property(np, "bd-stash", NULL); if (stash) { @@ -747,17 +860,16 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) memcpy(dev->dev_addr, mac_addr, ETH_ALEN); if (model && !strcasecmp(model, "TSEC")) - priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR; if (model && !strcasecmp(model, "eTSEC")) - priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR | - FSL_GIANFAR_DEV_HAS_PADDING | FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | @@ -777,23 +889,33 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv->phy_node = of_parse_phandle(np, "phy-handle", 0); + /* In the case of a fixed PHY, the DT node associated + * to the PHY is the Ethernet MAC DT node. + */ + if (of_phy_is_fixed_link(np)) { + err = of_phy_register_fixed_link(np); + if (err) + goto err_grp_init; + + priv->phy_node = np; + } + /* Find the TBI PHY. If it's not there, we don't support SGMII */ priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0); return 0; -rx_alloc_failed: - free_rx_pointers(priv); -tx_alloc_failed: - free_tx_pointers(priv); err_grp_init: unmap_group_regs(priv); +rx_alloc_failed: + gfar_free_rx_queues(priv); +tx_alloc_failed: + gfar_free_tx_queues(priv); free_gfar_dev(priv); return err; } -static int gfar_hwtstamp_ioctl(struct net_device *netdev, - struct ifreq *ifr, int cmd) +static int gfar_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr) { struct hwtstamp_config config; struct gfar_private *priv = netdev_priv(netdev); @@ -821,18 +943,16 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: if (priv->hwts_rx_en) { - stop_gfar(netdev); priv->hwts_rx_en = 0; - startup_gfar(netdev); + reset_gfar(netdev); } break; default: if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)) return -ERANGE; if (!priv->hwts_rx_en) { - stop_gfar(netdev); priv->hwts_rx_en = 1; - startup_gfar(netdev); + reset_gfar(netdev); } config.rx_filter = HWTSTAMP_FILTER_ALL; break; @@ -842,7 +962,20 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, -EFAULT : 0; } -/* Ioctl MII Interface */ +static int gfar_hwtstamp_get(struct net_device *netdev, struct ifreq *ifr) +{ + struct hwtstamp_config config; + struct gfar_private *priv = netdev_priv(netdev); + + config.flags = 0; + config.tx_type = priv->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + config.rx_filter = (priv->hwts_rx_en ? + HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE); + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct gfar_private *priv = netdev_priv(dev); @@ -851,7 +984,9 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EINVAL; if (cmd == SIOCSHWTSTAMP) - return gfar_hwtstamp_ioctl(dev, rq, cmd); + return gfar_hwtstamp_set(dev, rq); + if (cmd == SIOCGHWTSTAMP) + return gfar_hwtstamp_get(dev, rq); if (!priv->phydev) return -ENODEV; @@ -859,19 +994,6 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(priv->phydev, rq, cmd); } -static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs) -{ - unsigned int new_bit_map = 0x0; - int mask = 0x1 << (max_qs - 1), i; - - for (i = 0; i < max_qs; i++) { - if (bit_map & mask) - new_bit_map = new_bit_map + (1 << i); - mask = mask >> 0x1; - } - return new_bit_map; -} - static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class) { @@ -939,9 +1061,8 @@ static void gfar_init_filer_table(struct gfar_private *priv) } } -static void gfar_detect_errata(struct gfar_private *priv) +static void __gfar_detect_errata_83xx(struct gfar_private *priv) { - struct device *dev = &priv->ofdev->dev; unsigned int pvr = mfspr(SPRN_PVR); unsigned int svr = mfspr(SPRN_SVR); unsigned int mod = (svr >> 16) & 0xfff6; /* w/o E suffix */ @@ -957,103 +1078,173 @@ static void gfar_detect_errata(struct gfar_private *priv) (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0)) priv->errata |= GFAR_ERRATA_76; - /* MPC8313 and MPC837x all rev */ - if ((pvr == 0x80850010 && mod == 0x80b0) || - (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0)) - priv->errata |= GFAR_ERRATA_A002; + /* MPC8313 Rev < 2.0 */ + if (pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020) + priv->errata |= GFAR_ERRATA_12; +} + +static void __gfar_detect_errata_85xx(struct gfar_private *priv) +{ + unsigned int svr = mfspr(SPRN_SVR); - /* MPC8313 Rev < 2.0, MPC8548 rev 2.0 */ - if ((pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020) || - (pvr == 0x80210020 && mod == 0x8030 && rev == 0x0020)) + if ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) == 0x20)) priv->errata |= GFAR_ERRATA_12; + if (((SVR_SOC_VER(svr) == SVR_P2020) && (SVR_REV(svr) < 0x20)) || + ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20))) + priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */ +} + +static void gfar_detect_errata(struct gfar_private *priv) +{ + struct device *dev = &priv->ofdev->dev; + + /* no plans to fix */ + priv->errata |= GFAR_ERRATA_A002; + + if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2)) + __gfar_detect_errata_85xx(priv); + else /* non-mpc85xx parts, i.e. e300 core based */ + __gfar_detect_errata_83xx(priv); if (priv->errata) dev_info(dev, "enabled errata workarounds, flags: 0x%x\n", priv->errata); } -/* Set up the ethernet device structure, private data, - * and anything else we need before we start - */ -static int gfar_probe(struct platform_device *ofdev) +void gfar_mac_reset(struct gfar_private *priv) { + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - struct net_device *dev = NULL; - struct gfar_private *priv = NULL; - struct gfar __iomem *regs = NULL; - int err = 0, i, grp_idx = 0; - u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0; - u32 isrg = 0; - u32 __iomem *baddr; - err = gfar_of_init(ofdev, &dev); + /* Reset MAC layer */ + gfar_write(®s->maccfg1, MACCFG1_SOFT_RESET); - if (err) - return err; + /* We need to delay at least 3 TX clocks */ + udelay(3); - priv = netdev_priv(dev); - priv->ndev = dev; - priv->ofdev = ofdev; - priv->dev = &ofdev->dev; - SET_NETDEV_DEV(dev, &ofdev->dev); + /* the soft reset bit is not self-resetting, so we need to + * clear it before resuming normal operation + */ + gfar_write(®s->maccfg1, 0); - spin_lock_init(&priv->bflock); - INIT_WORK(&priv->reset_task, gfar_reset_task); + udelay(3); - dev_set_drvdata(&ofdev->dev, priv); - regs = priv->gfargrp[0].regs; + /* Compute rx_buff_size based on config flags */ + gfar_rx_buff_size_config(priv); - gfar_detect_errata(priv); + /* Initialize the max receive frame/buffer lengths */ + gfar_write(®s->maxfrm, priv->rx_buffer_size); + gfar_write(®s->mrblr, priv->rx_buffer_size); + + /* Initialize the Minimum Frame Length Register */ + gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); + + /* Initialize MACCFG2. */ + tempval = MACCFG2_INIT_SETTINGS; + + /* If the mtu is larger than the max size for standard + * ethernet frames (ie, a jumbo frame), then set maccfg2 + * to allow huge frames, and to check the length + */ + if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE || + gfar_has_errata(priv, GFAR_ERRATA_74)) + tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK; + + gfar_write(®s->maccfg2, tempval); + + /* Clear mac addr hash registers */ + gfar_write(®s->igaddr0, 0); + gfar_write(®s->igaddr1, 0); + gfar_write(®s->igaddr2, 0); + gfar_write(®s->igaddr3, 0); + gfar_write(®s->igaddr4, 0); + gfar_write(®s->igaddr5, 0); + gfar_write(®s->igaddr6, 0); + gfar_write(®s->igaddr7, 0); + + gfar_write(®s->gaddr0, 0); + gfar_write(®s->gaddr1, 0); + gfar_write(®s->gaddr2, 0); + gfar_write(®s->gaddr3, 0); + gfar_write(®s->gaddr4, 0); + gfar_write(®s->gaddr5, 0); + gfar_write(®s->gaddr6, 0); + gfar_write(®s->gaddr7, 0); + + if (priv->extended_hash) + gfar_clear_exact_match(priv->ndev); + + gfar_mac_rx_config(priv); + + gfar_mac_tx_config(priv); + + gfar_set_mac_address(priv->ndev); + + gfar_set_multi(priv->ndev); + + /* clear ievent and imask before configuring coalescing */ + gfar_ints_disable(priv); + + /* Configure the coalescing support */ + gfar_configure_coalescing_all(priv); +} + +static void gfar_hw_init(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 attrs; /* Stop the DMA engine now, in case it was running before * (The firmware could have used it, and left it running). */ - gfar_halt(dev); + gfar_halt(priv); - /* Reset MAC layer */ - gfar_write(®s->maccfg1, MACCFG1_SOFT_RESET); + gfar_mac_reset(priv); - /* We need to delay at least 3 TX clocks */ - udelay(2); - - tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); - gfar_write(®s->maccfg1, tempval); + /* Zero out the rmon mib registers if it has them */ + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { + memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib)); - /* Initialize MACCFG2. */ - tempval = MACCFG2_INIT_SETTINGS; - if (gfar_has_errata(priv, GFAR_ERRATA_74)) - tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK; - gfar_write(®s->maccfg2, tempval); + /* Mask off the CAM interrupts */ + gfar_write(®s->rmon.cam1, 0xffffffff); + gfar_write(®s->rmon.cam2, 0xffffffff); + } /* Initialize ECNTRL */ gfar_write(®s->ecntrl, ECNTRL_INIT_SETTINGS); - /* Set the dev->base_addr to the gfar reg region */ - dev->base_addr = (unsigned long) regs; + /* Set the extraction length and index */ + attrs = ATTRELI_EL(priv->rx_stash_size) | + ATTRELI_EI(priv->rx_stash_index); - /* Fill in the dev structure */ - dev->watchdog_timeo = TX_TIMEOUT; - dev->mtu = 1500; - dev->netdev_ops = &gfar_netdev_ops; - dev->ethtool_ops = &gfar_ethtool_ops; + gfar_write(®s->attreli, attrs); - /* Register for napi ...We are registering NAPI for each grp */ - for (i = 0; i < priv->num_grps; i++) - netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, - GFAR_DEV_WEIGHT); + /* Start with defaults, and add stashing + * depending on driver parameters + */ + attrs = ATTR_INIT_SETTINGS; - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { - dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_RXCSUM; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_RXCSUM | NETIF_F_HIGHDMA; - } + if (priv->bd_stash_en) + attrs |= ATTR_BDSTASH; - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { - dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_CTAG_RX; - dev->features |= NETIF_F_HW_VLAN_CTAG_RX; - } + if (priv->rx_stash_size != 0) + attrs |= ATTR_BUFSTASH; + + gfar_write(®s->attr, attrs); + + /* FIFO configs */ + gfar_write(®s->fifo_tx_thr, DEFAULT_FIFO_TX_THR); + gfar_write(®s->fifo_tx_starve, DEFAULT_FIFO_TX_STARVE); + gfar_write(®s->fifo_tx_starve_shutoff, DEFAULT_FIFO_TX_STARVE_OFF); + + /* Program the interrupt steering regs, only for MG devices */ + if (priv->num_grps > 1) + gfar_write_isrg(priv); +} + +static void gfar_init_addr_hash_table(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { priv->extended_hash = 1; @@ -1089,68 +1280,81 @@ static int gfar_probe(struct platform_device *ofdev) priv->hash_regs[6] = ®s->gaddr6; priv->hash_regs[7] = ®s->gaddr7; } +} - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING) - priv->padding = DEFAULT_PADDING; - else - priv->padding = 0; +/* Set up the ethernet device structure, private data, + * and anything else we need before we start + */ +static int gfar_probe(struct platform_device *ofdev) +{ + struct net_device *dev = NULL; + struct gfar_private *priv = NULL; + int err = 0, i; - if (dev->features & NETIF_F_IP_CSUM || - priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) - dev->needed_headroom = GMAC_FCB_LEN; + err = gfar_of_init(ofdev, &dev); - /* Program the isrg regs only if number of grps > 1 */ - if (priv->num_grps > 1) { - baddr = ®s->isrg0; - for (i = 0; i < priv->num_grps; i++) { - isrg |= (priv->gfargrp[i].rx_bit_map << ISRG_SHIFT_RX); - isrg |= (priv->gfargrp[i].tx_bit_map << ISRG_SHIFT_TX); - gfar_write(baddr, isrg); - baddr++; - isrg = 0x0; + if (err) + return err; + + priv = netdev_priv(dev); + priv->ndev = dev; + priv->ofdev = ofdev; + priv->dev = &ofdev->dev; + SET_NETDEV_DEV(dev, &ofdev->dev); + + spin_lock_init(&priv->bflock); + INIT_WORK(&priv->reset_task, gfar_reset_task); + + platform_set_drvdata(ofdev, priv); + + gfar_detect_errata(priv); + + /* Set the dev->base_addr to the gfar reg region */ + dev->base_addr = (unsigned long) priv->gfargrp[0].regs; + + /* Fill in the dev structure */ + dev->watchdog_timeo = TX_TIMEOUT; + dev->mtu = 1500; + dev->netdev_ops = &gfar_netdev_ops; + dev->ethtool_ops = &gfar_ethtool_ops; + + /* Register for napi ...We are registering NAPI for each grp */ + for (i = 0; i < priv->num_grps; i++) { + if (priv->poll_mode == GFAR_SQ_POLLING) { + netif_napi_add(dev, &priv->gfargrp[i].napi_rx, + gfar_poll_rx_sq, GFAR_DEV_WEIGHT); + netif_napi_add(dev, &priv->gfargrp[i].napi_tx, + gfar_poll_tx_sq, 2); + } else { + netif_napi_add(dev, &priv->gfargrp[i].napi_rx, + gfar_poll_rx, GFAR_DEV_WEIGHT); + netif_napi_add(dev, &priv->gfargrp[i].napi_tx, + gfar_poll_tx, 2); } } - /* Need to reverse the bit maps as bit_map's MSB is q0 - * but, for_each_set_bit parses from right to left, which - * basically reverses the queue numbers - */ - for (i = 0; i< priv->num_grps; i++) { - priv->gfargrp[i].tx_bit_map = - reverse_bitmap(priv->gfargrp[i].tx_bit_map, MAX_TX_QS); - priv->gfargrp[i].rx_bit_map = - reverse_bitmap(priv->gfargrp[i].rx_bit_map, MAX_RX_QS); + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM | NETIF_F_HIGHDMA; } - /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values, - * also assign queues to groups - */ - for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) { - priv->gfargrp[grp_idx].num_rx_queues = 0x0; - - for_each_set_bit(i, &priv->gfargrp[grp_idx].rx_bit_map, - priv->num_rx_queues) { - priv->gfargrp[grp_idx].num_rx_queues++; - priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx]; - rstat = rstat | (RSTAT_CLEAR_RHALT >> i); - rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i); - } - priv->gfargrp[grp_idx].num_tx_queues = 0x0; - - for_each_set_bit(i, &priv->gfargrp[grp_idx].tx_bit_map, - priv->num_tx_queues) { - priv->gfargrp[grp_idx].num_tx_queues++; - priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx]; - tstat = tstat | (TSTAT_CLEAR_THALT >> i); - tqueue = tqueue | (TQUEUE_EN0 >> i); - } - priv->gfargrp[grp_idx].rstat = rstat; - priv->gfargrp[grp_idx].tstat = tstat; - rstat = tstat =0; + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { + dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX; + dev->features |= NETIF_F_HW_VLAN_CTAG_RX; } - gfar_write(®s->rqueue, rqueue); - gfar_write(®s->tqueue, tqueue); + gfar_init_addr_hash_table(priv); + + /* Insert receive time stamps into padding alignment bytes */ + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) + priv->padding = 8; + + if (dev->features & NETIF_F_IP_CSUM || + priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) + dev->needed_headroom = GMAC_FCB_LEN; priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; @@ -1176,6 +1380,10 @@ static int gfar_probe(struct platform_device *ofdev) if (priv->num_tx_queues == 1) priv->prio_sched_en = 1; + set_bit(GFAR_DOWN, &priv->state); + + gfar_hw_init(priv); + /* Carrier starts down, phylib will bring it up */ netif_carrier_off(dev); @@ -1207,9 +1415,6 @@ static int gfar_probe(struct platform_device *ofdev) /* Initialize the filer table */ gfar_init_filer_table(priv); - /* Create all the sysfs files */ - gfar_init_sysfs(dev); - /* Print out the device info */ netdev_info(dev, "mac: %pM\n", dev->dev_addr); @@ -1228,8 +1433,8 @@ static int gfar_probe(struct platform_device *ofdev) register_fail: unmap_group_regs(priv); - free_tx_pointers(priv); - free_rx_pointers(priv); + gfar_free_rx_queues(priv); + gfar_free_tx_queues(priv); if (priv->phy_node) of_node_put(priv->phy_node); if (priv->tbi_node) @@ -1240,17 +1445,17 @@ register_fail: static int gfar_remove(struct platform_device *ofdev) { - struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); + struct gfar_private *priv = platform_get_drvdata(ofdev); if (priv->phy_node) of_node_put(priv->phy_node); if (priv->tbi_node) of_node_put(priv->tbi_node); - dev_set_drvdata(&ofdev->dev, NULL); - unregister_netdev(priv->ndev); unmap_group_regs(priv); + gfar_free_rx_queues(priv); + gfar_free_tx_queues(priv); free_gfar_dev(priv); return 0; @@ -1276,9 +1481,8 @@ static int gfar_suspend(struct device *dev) local_irq_save(flags); lock_tx_qs(priv); - lock_rx_qs(priv); - gfar_halt_nodisable(ndev); + gfar_halt_nodisable(priv); /* Disable Tx, and Rx if wake-on-LAN is disabled. */ tempval = gfar_read(®s->maccfg1); @@ -1290,7 +1494,6 @@ static int gfar_suspend(struct device *dev) gfar_write(®s->maccfg1, tempval); - unlock_rx_qs(priv); unlock_tx_qs(priv); local_irq_restore(flags); @@ -1336,15 +1539,13 @@ static int gfar_resume(struct device *dev) */ local_irq_save(flags); lock_tx_qs(priv); - lock_rx_qs(priv); tempval = gfar_read(®s->maccfg2); tempval &= ~MACCFG2_MPEN; gfar_write(®s->maccfg2, tempval); - gfar_start(ndev); + gfar_start(priv); - unlock_rx_qs(priv); unlock_tx_qs(priv); local_irq_restore(flags); @@ -1371,10 +1572,11 @@ static int gfar_restore(struct device *dev) return -ENOMEM; } - init_registers(ndev); - gfar_set_mac_address(ndev); - gfar_init_mac(ndev); - gfar_start(ndev); + gfar_mac_reset(priv); + + gfar_init_tx_rx_base(priv); + + gfar_start(priv); priv->oldlink = 0; priv->oldspeed = 0; @@ -1458,7 +1660,7 @@ static int init_phy(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); uint gigabit_support = priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? - SUPPORTED_1000baseT_Full : 0; + GFAR_SUPPORTED_GBIT : 0; phy_interface_t interface; priv->oldlink = 0; @@ -1469,9 +1671,6 @@ static int init_phy(struct net_device *dev) priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link, 0, interface); - if (!priv->phydev) - priv->phydev = of_phy_connect_fixed_link(dev, &adjust_link, - interface); if (!priv->phydev) { dev_err(&dev->dev, "could not attach to PHY\n"); return -ENODEV; @@ -1532,57 +1731,6 @@ static void gfar_configure_serdes(struct net_device *dev) BMCR_SPEED1000); } -static void init_registers(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = NULL; - int i; - - for (i = 0; i < priv->num_grps; i++) { - regs = priv->gfargrp[i].regs; - /* Clear IEVENT */ - gfar_write(®s->ievent, IEVENT_INIT_CLEAR); - - /* Initialize IMASK */ - gfar_write(®s->imask, IMASK_INIT_CLEAR); - } - - regs = priv->gfargrp[0].regs; - /* Init hash registers to zero */ - gfar_write(®s->igaddr0, 0); - gfar_write(®s->igaddr1, 0); - gfar_write(®s->igaddr2, 0); - gfar_write(®s->igaddr3, 0); - gfar_write(®s->igaddr4, 0); - gfar_write(®s->igaddr5, 0); - gfar_write(®s->igaddr6, 0); - gfar_write(®s->igaddr7, 0); - - gfar_write(®s->gaddr0, 0); - gfar_write(®s->gaddr1, 0); - gfar_write(®s->gaddr2, 0); - gfar_write(®s->gaddr3, 0); - gfar_write(®s->gaddr4, 0); - gfar_write(®s->gaddr5, 0); - gfar_write(®s->gaddr6, 0); - gfar_write(®s->gaddr7, 0); - - /* Zero out the rmon mib registers if it has them */ - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { - memset_io(&(regs->rmon), 0, sizeof (struct rmon_mib)); - - /* Mask off the CAM interrupts */ - gfar_write(®s->rmon.cam1, 0xffffffff); - gfar_write(®s->rmon.cam2, 0xffffffff); - } - - /* Initialize the max receive buffer length */ - gfar_write(®s->mrblr, priv->rx_buffer_size); - - /* Initialize the Minimum Frame Length Register */ - gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); -} - static int __gfar_is_rx_idle(struct gfar_private *priv) { u32 res; @@ -1590,7 +1738,7 @@ static int __gfar_is_rx_idle(struct gfar_private *priv) /* Normaly TSEC should not hang on GRS commands, so we should * actually wait for IEVENT_GRSC flag. */ - if (likely(!gfar_has_errata(priv, GFAR_ERRATA_A002))) + if (!gfar_has_errata(priv, GFAR_ERRATA_A002)) return 0; /* Read the eTSEC register at offset 0xD1C. If bits 7-14 are @@ -1606,23 +1754,13 @@ static int __gfar_is_rx_idle(struct gfar_private *priv) } /* Halt the receive and transmit queues */ -static void gfar_halt_nodisable(struct net_device *dev) +static void gfar_halt_nodisable(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = NULL; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - int i; - - for (i = 0; i < priv->num_grps; i++) { - regs = priv->gfargrp[i].regs; - /* Mask all interrupts */ - gfar_write(®s->imask, IMASK_INIT_CLEAR); - /* Clear all interrupts */ - gfar_write(®s->ievent, IEVENT_INIT_CLEAR); - } + gfar_ints_disable(priv); - regs = priv->gfargrp[0].regs; /* Stop the DMA, and wait for it to stop */ tempval = gfar_read(®s->dmactrl); if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) != @@ -1643,56 +1781,41 @@ static void gfar_halt_nodisable(struct net_device *dev) } /* Halt the receive and transmit queues */ -void gfar_halt(struct net_device *dev) +void gfar_halt(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - gfar_halt_nodisable(dev); + /* Dissable the Rx/Tx hw queues */ + gfar_write(®s->rqueue, 0); + gfar_write(®s->tqueue, 0); + + mdelay(10); - /* Disable Rx and Tx */ + gfar_halt_nodisable(priv); + + /* Disable Rx/Tx DMA */ tempval = gfar_read(®s->maccfg1); tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN); gfar_write(®s->maccfg1, tempval); } -static void free_grp_irqs(struct gfar_priv_grp *grp) -{ - free_irq(gfar_irq(grp, TX)->irq, grp); - free_irq(gfar_irq(grp, RX)->irq, grp); - free_irq(gfar_irq(grp, ER)->irq, grp); -} - void stop_gfar(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - unsigned long flags; - int i; - phy_stop(priv->phydev); + netif_tx_stop_all_queues(dev); + smp_mb__before_atomic(); + set_bit(GFAR_DOWN, &priv->state); + smp_mb__after_atomic(); - /* Lock it down */ - local_irq_save(flags); - lock_tx_qs(priv); - lock_rx_qs(priv); - - gfar_halt(dev); + disable_napi(priv); - unlock_rx_qs(priv); - unlock_tx_qs(priv); - local_irq_restore(flags); + /* disable ints and gracefully shut down Rx/Tx DMA */ + gfar_halt(priv); - /* Free the IRQs */ - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - for (i = 0; i < priv->num_grps; i++) - free_grp_irqs(&priv->gfargrp[i]); - } else { - for (i = 0; i < priv->num_grps; i++) - free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq, - &priv->gfargrp[i]); - } + phy_stop(priv->phydev); free_skb_resources(priv); } @@ -1783,17 +1906,15 @@ static void free_skb_resources(struct gfar_private *priv) priv->tx_queue[0]->tx_bd_dma_base); } -void gfar_start(struct net_device *dev) +void gfar_start(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; int i = 0; - /* Enable Rx and Tx in MACCFG1 */ - tempval = gfar_read(®s->maccfg1); - tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN); - gfar_write(®s->maccfg1, tempval); + /* Enable Rx/Tx hw queues */ + gfar_write(®s->rqueue, priv->rqueue); + gfar_write(®s->tqueue, priv->tqueue); /* Initialize DMACTRL to have WWR and WOP */ tempval = gfar_read(®s->dmactrl); @@ -1810,52 +1931,23 @@ void gfar_start(struct net_device *dev) /* Clear THLT/RHLT, so that the DMA starts polling now */ gfar_write(®s->tstat, priv->gfargrp[i].tstat); gfar_write(®s->rstat, priv->gfargrp[i].rstat); - /* Unmask the interrupts we look for */ - gfar_write(®s->imask, IMASK_DEFAULT); } - dev->trans_start = jiffies; /* prevent tx timeout */ -} - -static void gfar_configure_coalescing(struct gfar_private *priv, - unsigned long tx_mask, unsigned long rx_mask) -{ - struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 __iomem *baddr; - - if (priv->mode == MQ_MG_MODE) { - int i = 0; - - baddr = ®s->txic0; - for_each_set_bit(i, &tx_mask, priv->num_tx_queues) { - gfar_write(baddr + i, 0); - if (likely(priv->tx_queue[i]->txcoalescing)) - gfar_write(baddr + i, priv->tx_queue[i]->txic); - } + /* Enable Rx/Tx DMA */ + tempval = gfar_read(®s->maccfg1); + tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + gfar_write(®s->maccfg1, tempval); - baddr = ®s->rxic0; - for_each_set_bit(i, &rx_mask, priv->num_rx_queues) { - gfar_write(baddr + i, 0); - if (likely(priv->rx_queue[i]->rxcoalescing)) - gfar_write(baddr + i, priv->rx_queue[i]->rxic); - } - } else { - /* Backward compatible case -- even if we enable - * multiple queues, there's only single reg to program - */ - gfar_write(®s->txic, 0); - if (likely(priv->tx_queue[0]->txcoalescing)) - gfar_write(®s->txic, priv->tx_queue[0]->txic); + gfar_ints_enable(priv); - gfar_write(®s->rxic, 0); - if (unlikely(priv->rx_queue[0]->rxcoalescing)) - gfar_write(®s->rxic, priv->rx_queue[0]->rxic); - } + priv->ndev->trans_start = jiffies; /* prevent tx timeout */ } -void gfar_configure_coalescing_all(struct gfar_private *priv) +static void free_grp_irqs(struct gfar_priv_grp *grp) { - gfar_configure_coalescing(priv, 0xFF, 0xFF); + free_irq(gfar_irq(grp, TX)->irq, grp); + free_irq(gfar_irq(grp, RX)->irq, grp); + free_irq(gfar_irq(grp, ER)->irq, grp); } static int register_grp_irqs(struct gfar_priv_grp *grp) @@ -1914,46 +2006,65 @@ err_irq_fail: } -/* Bring the controller up and running */ -int startup_gfar(struct net_device *ndev) +static void gfar_free_irq(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = NULL; - int err, i, j; + int i; - for (i = 0; i < priv->num_grps; i++) { - regs= priv->gfargrp[i].regs; - gfar_write(®s->imask, IMASK_INIT_CLEAR); + /* Free the IRQs */ + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + for (i = 0; i < priv->num_grps; i++) + free_grp_irqs(&priv->gfargrp[i]); + } else { + for (i = 0; i < priv->num_grps; i++) + free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq, + &priv->gfargrp[i]); } +} - regs= priv->gfargrp[0].regs; - err = gfar_alloc_skb_resources(ndev); - if (err) - return err; - - gfar_init_mac(ndev); +static int gfar_request_irq(struct gfar_private *priv) +{ + int err, i, j; for (i = 0; i < priv->num_grps; i++) { err = register_grp_irqs(&priv->gfargrp[i]); if (err) { for (j = 0; j < i; j++) free_grp_irqs(&priv->gfargrp[j]); - goto irq_fail; + return err; } } - /* Start the controller */ - gfar_start(ndev); + return 0; +} + +/* Bring the controller up and running */ +int startup_gfar(struct net_device *ndev) +{ + struct gfar_private *priv = netdev_priv(ndev); + int err; + + gfar_mac_reset(priv); + + err = gfar_alloc_skb_resources(ndev); + if (err) + return err; + + gfar_init_tx_rx_base(priv); + + smp_mb__before_atomic(); + clear_bit(GFAR_DOWN, &priv->state); + smp_mb__after_atomic(); + + /* Start Rx/Tx DMA and enable the interrupts */ + gfar_start(priv); phy_start(priv->phydev); - gfar_configure_coalescing_all(priv); + enable_napi(priv); - return 0; + netif_tx_wake_all_queues(ndev); -irq_fail: - free_skb_resources(priv); - return err; + return 0; } /* Called when something needs to use the ethernet device @@ -1964,27 +2075,17 @@ static int gfar_enet_open(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); int err; - enable_napi(priv); - - /* Initialize a bunch of registers */ - init_registers(dev); - - gfar_set_mac_address(dev); - err = init_phy(dev); + if (err) + return err; - if (err) { - disable_napi(priv); + err = gfar_request_irq(priv); + if (err) return err; - } err = startup_gfar(dev); - if (err) { - disable_napi(priv); + if (err) return err; - } - - netif_tx_start_all_queues(dev); device_set_wakeup_enable(&dev->dev, priv->wol_en); @@ -2049,6 +2150,24 @@ static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base, return skip_txbd(bdp, 1, base, ring_size); } +/* eTSEC12: csum generation not supported for some fcb offsets */ +static inline bool gfar_csum_errata_12(struct gfar_private *priv, + unsigned long fcb_addr) +{ + return (gfar_has_errata(priv, GFAR_ERRATA_12) && + (fcb_addr % 0x20) > 0x18); +} + +/* eTSEC76: csum generation for frames larger than 2500 may + * cause excess delays before start of transmission + */ +static inline bool gfar_csum_errata_76(struct gfar_private *priv, + unsigned int len) +{ + return (gfar_has_errata(priv, GFAR_ERRATA_76) && + (len > 2500)); +} + /* This is called by the kernel when a frame is ready for transmission. * It is pointed to by the dev->hard_start_xmit function pointer */ @@ -2061,23 +2180,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) struct txfcb *fcb = NULL; struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL; u32 lstatus; - int i, rq = 0, do_tstamp = 0; + int i, rq = 0; + int do_tstamp, do_csum, do_vlan; u32 bufaddr; unsigned long flags; - unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN; - - /* TOE=1 frames larger than 2500 bytes may see excess delays - * before start of transmission. - */ - if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_76) && - skb->ip_summed == CHECKSUM_PARTIAL && - skb->len > 2500)) { - int ret; - - ret = skb_checksum_help(skb); - if (ret) - return ret; - } + unsigned int nr_frags, nr_txbds, bytes_sent, fcb_len = 0; rq = skb->queue_mapping; tx_queue = priv->tx_queue[rq]; @@ -2085,30 +2192,32 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) base = tx_queue->tx_bd_base; regs = tx_queue->grp->regs; + do_csum = (CHECKSUM_PARTIAL == skb->ip_summed); + do_vlan = vlan_tx_tag_present(skb); + do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + priv->hwts_tx_en; + + if (do_csum || do_vlan) + fcb_len = GMAC_FCB_LEN; + /* check if time stamp should be generated */ - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && - priv->hwts_tx_en)) { - do_tstamp = 1; - fcb_length = GMAC_FCB_LEN + GMAC_TXPAL_LEN; - } + if (unlikely(do_tstamp)) + fcb_len = GMAC_FCB_LEN + GMAC_TXPAL_LEN; /* make space for additional header when fcb is needed */ - if (((skb->ip_summed == CHECKSUM_PARTIAL) || - vlan_tx_tag_present(skb) || - unlikely(do_tstamp)) && - (skb_headroom(skb) < fcb_length)) { + if (fcb_len && unlikely(skb_headroom(skb) < fcb_len)) { struct sk_buff *skb_new; - skb_new = skb_realloc_headroom(skb, fcb_length); + skb_new = skb_realloc_headroom(skb, fcb_len); if (!skb_new) { dev->stats.tx_errors++; - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } if (skb->sk) skb_set_owner_w(skb_new, skb->sk); - consume_skb(skb); + dev_consume_skb_any(skb); skb = skb_new; } @@ -2130,7 +2239,10 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Update transmit stats */ - tx_queue->stats.tx_bytes += skb->len; + bytes_sent = skb->len; + tx_queue->stats.tx_bytes += bytes_sent; + /* keep Tx bytes on wire for BQL accounting */ + GFAR_CB(skb)->bytes_sent = bytes_sent; tx_queue->stats.tx_packets++; txbdp = txbdp_start = tx_queue->cur_tx; @@ -2150,12 +2262,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) } else { /* Place the fragment addresses and lengths into the TxBDs */ for (i = 0; i < nr_frags; i++) { + unsigned int frag_len; /* Point at the next BD, wrapping as needed */ txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size); - length = skb_shinfo(skb)->frags[i].size; + frag_len = skb_shinfo(skb)->frags[i].size; - lstatus = txbdp->lstatus | length | + lstatus = txbdp->lstatus | frag_len | BD_LFLAG(TXBD_READY); /* Handle the last BD specially */ @@ -2165,7 +2278,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) bufaddr = skb_frag_dma_map(priv->dev, &skb_shinfo(skb)->frags[i], 0, - length, + frag_len, DMA_TO_DEVICE); /* set the TxBD length and buffer pointer */ @@ -2182,36 +2295,38 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) memset(skb->data, 0, GMAC_TXPAL_LEN); } - /* Set up checksumming */ - if (CHECKSUM_PARTIAL == skb->ip_summed) { + /* Add TxFCB if required */ + if (fcb_len) { fcb = gfar_add_fcb(skb); - /* as specified by errata */ - if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12) && - ((unsigned long)fcb % 0x20) > 0x18)) { + lstatus |= BD_LFLAG(TXBD_TOE); + } + + /* Set up checksumming */ + if (do_csum) { + gfar_tx_checksum(skb, fcb, fcb_len); + + if (unlikely(gfar_csum_errata_12(priv, (unsigned long)fcb)) || + unlikely(gfar_csum_errata_76(priv, skb->len))) { __skb_pull(skb, GMAC_FCB_LEN); skb_checksum_help(skb); - } else { - lstatus |= BD_LFLAG(TXBD_TOE); - gfar_tx_checksum(skb, fcb, fcb_length); + if (do_vlan || do_tstamp) { + /* put back a new fcb for vlan/tstamp TOE */ + fcb = gfar_add_fcb(skb); + } else { + /* Tx TOE not used */ + lstatus &= ~(BD_LFLAG(TXBD_TOE)); + fcb = NULL; + } } } - if (vlan_tx_tag_present(skb)) { - if (unlikely(NULL == fcb)) { - fcb = gfar_add_fcb(skb); - lstatus |= BD_LFLAG(TXBD_TOE); - } - + if (do_vlan) gfar_tx_vlan(skb, fcb); - } /* Setup tx hardware time stamping if requested */ if (unlikely(do_tstamp)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - if (fcb == NULL) - fcb = gfar_add_fcb(skb); fcb->ptp = 1; - lstatus |= BD_LFLAG(TXBD_TOE); } txbdp_start->bufPtr = dma_map_single(priv->dev, skb->data, @@ -2223,15 +2338,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) * the full frame length. */ if (unlikely(do_tstamp)) { - txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_length; + txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_len; txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) | - (skb_headlen(skb) - fcb_length); + (skb_headlen(skb) - fcb_len); lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN; } else { lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); } - netdev_tx_sent_queue(txq, skb->len); + netdev_tx_sent_queue(txq, bytes_sent); /* We can work in parallel with gfar_clean_tx_ring(), except * when modifying num_txbdfree. Note that we didn't grab the lock @@ -2295,8 +2410,6 @@ static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - disable_napi(priv); - cancel_work_sync(&priv->reset_task); stop_gfar(dev); @@ -2304,7 +2417,7 @@ static int gfar_close(struct net_device *dev) phy_disconnect(priv->phydev); priv->phydev = NULL; - netif_tx_stop_all_queues(dev); + gfar_free_irq(priv); return 0; } @@ -2317,77 +2430,9 @@ static int gfar_set_mac_address(struct net_device *dev) return 0; } -/* Check if rx parser should be activated */ -void gfar_check_rx_parser_mode(struct gfar_private *priv) -{ - struct gfar __iomem *regs; - u32 tempval; - - regs = priv->gfargrp[0].regs; - - tempval = gfar_read(®s->rctrl); - /* If parse is no longer required, then disable parser */ - if (tempval & RCTRL_REQ_PARSER) { - tempval |= RCTRL_PRSDEP_INIT; - priv->uses_rxfcb = 1; - } else { - tempval &= ~RCTRL_PRSDEP_INIT; - priv->uses_rxfcb = 0; - } - gfar_write(®s->rctrl, tempval); -} - -/* Enables and disables VLAN insertion/extraction */ -void gfar_vlan_mode(struct net_device *dev, netdev_features_t features) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = NULL; - unsigned long flags; - u32 tempval; - - regs = priv->gfargrp[0].regs; - local_irq_save(flags); - lock_rx_qs(priv); - - if (features & NETIF_F_HW_VLAN_CTAG_TX) { - /* Enable VLAN tag insertion */ - tempval = gfar_read(®s->tctrl); - tempval |= TCTRL_VLINS; - gfar_write(®s->tctrl, tempval); - } else { - /* Disable VLAN tag insertion */ - tempval = gfar_read(®s->tctrl); - tempval &= ~TCTRL_VLINS; - gfar_write(®s->tctrl, tempval); - } - - if (features & NETIF_F_HW_VLAN_CTAG_RX) { - /* Enable VLAN tag extraction */ - tempval = gfar_read(®s->rctrl); - tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); - gfar_write(®s->rctrl, tempval); - priv->uses_rxfcb = 1; - } else { - /* Disable VLAN tag extraction */ - tempval = gfar_read(®s->rctrl); - tempval &= ~RCTRL_VLEX; - gfar_write(®s->rctrl, tempval); - - gfar_check_rx_parser_mode(priv); - } - - gfar_change_mtu(dev, dev->mtu); - - unlock_rx_qs(priv); - local_irq_restore(flags); -} - static int gfar_change_mtu(struct net_device *dev, int new_mtu) { - int tempsize, tempval; struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - int oldsize = priv->rx_buffer_size; int frame_size = new_mtu + ETH_HLEN; if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { @@ -2395,45 +2440,33 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } - if (priv->uses_rxfcb) - frame_size += GMAC_FCB_LEN; - - frame_size += priv->padding; - - tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + - INCREMENTAL_BUFFER_SIZE; + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); - /* Only stop and start the controller if it isn't already - * stopped, and we changed something - */ - if ((oldsize != tempsize) && (dev->flags & IFF_UP)) + if (dev->flags & IFF_UP) stop_gfar(dev); - priv->rx_buffer_size = tempsize; - dev->mtu = new_mtu; - gfar_write(®s->mrblr, priv->rx_buffer_size); - gfar_write(®s->maxfrm, priv->rx_buffer_size); + if (dev->flags & IFF_UP) + startup_gfar(dev); - /* If the mtu is larger than the max size for standard - * ethernet frames (ie, a jumbo frame), then set maccfg2 - * to allow huge frames, and to check the length - */ - tempval = gfar_read(®s->maccfg2); + clear_bit_unlock(GFAR_RESETTING, &priv->state); - if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE || - gfar_has_errata(priv, GFAR_ERRATA_74)) - tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); - else - tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); + return 0; +} - gfar_write(®s->maccfg2, tempval); +void reset_gfar(struct net_device *ndev) +{ + struct gfar_private *priv = netdev_priv(ndev); - if ((oldsize != tempsize) && (dev->flags & IFF_UP)) - startup_gfar(dev); + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); - return 0; + stop_gfar(ndev); + startup_gfar(ndev); + + clear_bit_unlock(GFAR_RESETTING, &priv->state); } /* gfar_reset_task gets scheduled when a packet has not been @@ -2445,16 +2478,7 @@ static void gfar_reset_task(struct work_struct *work) { struct gfar_private *priv = container_of(work, struct gfar_private, reset_task); - struct net_device *dev = priv->ndev; - - if (dev->flags & IFF_UP) { - netif_tx_stop_all_queues(dev); - stop_gfar(dev); - startup_gfar(dev); - netif_tx_start_all_queues(dev); - } - - netif_tx_schedule_all(dev); + reset_gfar(priv->ndev); } static void gfar_timeout(struct net_device *dev) @@ -2551,7 +2575,7 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) bdp = next_txbd(bdp, base, tx_ring_size); } - bytes_sent += skb->len; + bytes_sent += GFAR_CB(skb)->bytes_sent; dev_kfree_skb_any(skb); @@ -2567,8 +2591,10 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) } /* If we freed a buffer, we can restart transmission, if necessary */ - if (netif_tx_queue_stopped(txq) && tx_queue->num_txbdfree) - netif_wake_subqueue(dev, tqi); + if (tx_queue->num_txbdfree && + netif_tx_queue_stopped(txq) && + !(test_bit(GFAR_DOWN, &priv->state))) + netif_wake_subqueue(priv->ndev, tqi); /* Update dirty indicators */ tx_queue->skb_dirtytx = skb_dirtytx; @@ -2577,31 +2603,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) netdev_tx_completed_queue(txq, howmany, bytes_sent); } -static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) -{ - unsigned long flags; - - spin_lock_irqsave(&gfargrp->grplock, flags); - if (napi_schedule_prep(&gfargrp->napi)) { - gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED); - __napi_schedule(&gfargrp->napi); - } else { - /* Clear IEVENT, so interrupts aren't called again - * because of the packets that have already arrived. - */ - gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK); - } - spin_unlock_irqrestore(&gfargrp->grplock, flags); - -} - -/* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *grp_id) -{ - gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); - return IRQ_HANDLED; -} - static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, struct sk_buff *skb) { @@ -2672,7 +2673,48 @@ static inline void count_errors(unsigned short status, struct net_device *dev) irqreturn_t gfar_receive(int irq, void *grp_id) { - gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); + struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id; + unsigned long flags; + u32 imask; + + if (likely(napi_schedule_prep(&grp->napi_rx))) { + spin_lock_irqsave(&grp->grplock, flags); + imask = gfar_read(&grp->regs->imask); + imask &= IMASK_RX_DISABLED; + gfar_write(&grp->regs->imask, imask); + spin_unlock_irqrestore(&grp->grplock, flags); + __napi_schedule(&grp->napi_rx); + } else { + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived. + */ + gfar_write(&grp->regs->ievent, IEVENT_RX_MASK); + } + + return IRQ_HANDLED; +} + +/* Interrupt Handler for Transmit complete */ +static irqreturn_t gfar_transmit(int irq, void *grp_id) +{ + struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id; + unsigned long flags; + u32 imask; + + if (likely(napi_schedule_prep(&grp->napi_tx))) { + spin_lock_irqsave(&grp->grplock, flags); + imask = gfar_read(&grp->regs->imask); + imask &= IMASK_TX_DISABLED; + gfar_write(&grp->regs->imask, imask); + spin_unlock_irqrestore(&grp->grplock, flags); + __napi_schedule(&grp->napi_tx); + } else { + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived. + */ + gfar_write(&grp->regs->ievent, IEVENT_TX_MASK); + } + return IRQ_HANDLED; } @@ -2796,7 +2838,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) rx_queue->stats.rx_bytes += pkt_len; skb_record_rx_queue(skb, rx_queue->qindex); gfar_process_frame(dev, skb, amount_pull, - &rx_queue->grp->napi); + &rx_queue->grp->napi_rx); } else { netif_warn(priv, rx_err, dev, "Missing skb!\n"); @@ -2825,24 +2867,81 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) return howmany; } -static int gfar_poll(struct napi_struct *napi, int budget) +static int gfar_poll_rx_sq(struct napi_struct *napi, int budget) +{ + struct gfar_priv_grp *gfargrp = + container_of(napi, struct gfar_priv_grp, napi_rx); + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_priv_rx_q *rx_queue = gfargrp->rx_queue; + int work_done = 0; + + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived + */ + gfar_write(®s->ievent, IEVENT_RX_MASK); + + work_done = gfar_clean_rx_ring(rx_queue, budget); + + if (work_done < budget) { + u32 imask; + napi_complete(napi); + /* Clear the halt bit in RSTAT */ + gfar_write(®s->rstat, gfargrp->rstat); + + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_RX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + } + + return work_done; +} + +static int gfar_poll_tx_sq(struct napi_struct *napi, int budget) +{ + struct gfar_priv_grp *gfargrp = + container_of(napi, struct gfar_priv_grp, napi_tx); + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_priv_tx_q *tx_queue = gfargrp->tx_queue; + u32 imask; + + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived + */ + gfar_write(®s->ievent, IEVENT_TX_MASK); + + /* run Tx cleanup to completion */ + if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) + gfar_clean_tx_ring(tx_queue); + + napi_complete(napi); + + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_TX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + + return 0; +} + +static int gfar_poll_rx(struct napi_struct *napi, int budget) { struct gfar_priv_grp *gfargrp = - container_of(napi, struct gfar_priv_grp, napi); + container_of(napi, struct gfar_priv_grp, napi_rx); struct gfar_private *priv = gfargrp->priv; struct gfar __iomem *regs = gfargrp->regs; - struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; int work_done = 0, work_done_per_q = 0; int i, budget_per_q = 0; - int has_tx_work; unsigned long rstat_rxf; int num_act_queues; /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ - gfar_write(®s->ievent, IEVENT_RTX_MASK); + gfar_write(®s->ievent, IEVENT_RX_MASK); rstat_rxf = gfar_read(®s->rstat) & RSTAT_RXF_MASK; @@ -2850,67 +2949,84 @@ static int gfar_poll(struct napi_struct *napi, int budget) if (num_act_queues) budget_per_q = budget/num_act_queues; - while (1) { - has_tx_work = 0; - for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) { - tx_queue = priv->tx_queue[i]; - /* run Tx cleanup to completion */ - if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) { - gfar_clean_tx_ring(tx_queue); - has_tx_work = 1; - } - } + for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) { + /* skip queue if not active */ + if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i))) + continue; - for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) { - /* skip queue if not active */ - if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i))) - continue; - - rx_queue = priv->rx_queue[i]; - work_done_per_q = - gfar_clean_rx_ring(rx_queue, budget_per_q); - work_done += work_done_per_q; - - /* finished processing this queue */ - if (work_done_per_q < budget_per_q) { - /* clear active queue hw indication */ - gfar_write(®s->rstat, - RSTAT_CLEAR_RXF0 >> i); - rstat_rxf &= ~(RSTAT_CLEAR_RXF0 >> i); - num_act_queues--; - - if (!num_act_queues) - break; - /* recompute budget per Rx queue */ - budget_per_q = - (budget - work_done) / num_act_queues; - } + rx_queue = priv->rx_queue[i]; + work_done_per_q = + gfar_clean_rx_ring(rx_queue, budget_per_q); + work_done += work_done_per_q; + + /* finished processing this queue */ + if (work_done_per_q < budget_per_q) { + /* clear active queue hw indication */ + gfar_write(®s->rstat, + RSTAT_CLEAR_RXF0 >> i); + num_act_queues--; + + if (!num_act_queues) + break; } + } - if (work_done >= budget) - break; + if (!num_act_queues) { + u32 imask; + napi_complete(napi); - if (!num_act_queues && !has_tx_work) { + /* Clear the halt bit in RSTAT */ + gfar_write(®s->rstat, gfargrp->rstat); - napi_complete(napi); + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_RX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + } - /* Clear the halt bit in RSTAT */ - gfar_write(®s->rstat, gfargrp->rstat); + return work_done; +} - gfar_write(®s->imask, IMASK_DEFAULT); +static int gfar_poll_tx(struct napi_struct *napi, int budget) +{ + struct gfar_priv_grp *gfargrp = + container_of(napi, struct gfar_priv_grp, napi_tx); + struct gfar_private *priv = gfargrp->priv; + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_priv_tx_q *tx_queue = NULL; + int has_tx_work = 0; + int i; - /* If we are coalescing interrupts, update the timer - * Otherwise, clear it - */ - gfar_configure_coalescing(priv, gfargrp->rx_bit_map, - gfargrp->tx_bit_map); - break; + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived + */ + gfar_write(®s->ievent, IEVENT_TX_MASK); + + for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) { + tx_queue = priv->tx_queue[i]; + /* run Tx cleanup to completion */ + if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) { + gfar_clean_tx_ring(tx_queue); + has_tx_work = 1; } } - return work_done; + if (!has_tx_work) { + u32 imask; + napi_complete(napi); + + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_TX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + } + + return 0; } + #ifdef CONFIG_NET_POLL_CONTROLLER /* Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while @@ -2978,81 +3094,12 @@ static irqreturn_t gfar_interrupt(int irq, void *grp_id) static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned long flags; struct phy_device *phydev = priv->phydev; - int new_state = 0; - - local_irq_save(flags); - lock_tx_qs(priv); - - if (phydev->link) { - u32 tempval = gfar_read(®s->maccfg2); - u32 ecntrl = gfar_read(®s->ecntrl); - - /* Now we make sure that we can be in full duplex mode. - * If not, we operate in half-duplex mode. - */ - if (phydev->duplex != priv->oldduplex) { - new_state = 1; - if (!(phydev->duplex)) - tempval &= ~(MACCFG2_FULL_DUPLEX); - else - tempval |= MACCFG2_FULL_DUPLEX; - - priv->oldduplex = phydev->duplex; - } - - if (phydev->speed != priv->oldspeed) { - new_state = 1; - switch (phydev->speed) { - case 1000: - tempval = - ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); - - ecntrl &= ~(ECNTRL_R100); - break; - case 100: - case 10: - tempval = - ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); - - /* Reduced mode distinguishes - * between 10 and 100 - */ - if (phydev->speed == SPEED_100) - ecntrl |= ECNTRL_R100; - else - ecntrl &= ~(ECNTRL_R100); - break; - default: - netif_warn(priv, link, dev, - "Ack! Speed (%d) is not 10/100/1000!\n", - phydev->speed); - break; - } - - priv->oldspeed = phydev->speed; - } - - gfar_write(®s->maccfg2, tempval); - gfar_write(®s->ecntrl, ecntrl); - if (!priv->oldlink) { - new_state = 1; - priv->oldlink = 1; - } - } else if (priv->oldlink) { - new_state = 1; - priv->oldlink = 0; - priv->oldspeed = 0; - priv->oldduplex = -1; - } - - if (new_state && netif_msg_link(priv)) - phy_print_status(phydev); - unlock_tx_qs(priv); - local_irq_restore(flags); + if (unlikely(phydev->link != priv->oldlink || + phydev->duplex != priv->oldduplex || + phydev->speed != priv->oldspeed)) + gfar_update_link_state(priv); } /* Update the hash table based on the current list of multicast @@ -3298,6 +3345,114 @@ static irqreturn_t gfar_error(int irq, void *grp_id) return IRQ_HANDLED; } +static u32 gfar_get_flowctrl_cfg(struct gfar_private *priv) +{ + struct phy_device *phydev = priv->phydev; + u32 val = 0; + + if (!phydev->duplex) + return val; + + if (!priv->pause_aneg_en) { + if (priv->tx_pause_en) + val |= MACCFG1_TX_FLOW; + if (priv->rx_pause_en) + val |= MACCFG1_RX_FLOW; + } else { + u16 lcl_adv, rmt_adv; + u8 flowctrl; + /* get link partner capabilities */ + rmt_adv = 0; + if (phydev->pause) + rmt_adv = LPA_PAUSE_CAP; + if (phydev->asym_pause) + rmt_adv |= LPA_PAUSE_ASYM; + + lcl_adv = mii_advertise_flowctrl(phydev->advertising); + + flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); + if (flowctrl & FLOW_CTRL_TX) + val |= MACCFG1_TX_FLOW; + if (flowctrl & FLOW_CTRL_RX) + val |= MACCFG1_RX_FLOW; + } + + return val; +} + +static noinline void gfar_update_link_state(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + struct phy_device *phydev = priv->phydev; + + if (unlikely(test_bit(GFAR_RESETTING, &priv->state))) + return; + + if (phydev->link) { + u32 tempval1 = gfar_read(®s->maccfg1); + u32 tempval = gfar_read(®s->maccfg2); + u32 ecntrl = gfar_read(®s->ecntrl); + + if (phydev->duplex != priv->oldduplex) { + if (!(phydev->duplex)) + tempval &= ~(MACCFG2_FULL_DUPLEX); + else + tempval |= MACCFG2_FULL_DUPLEX; + + priv->oldduplex = phydev->duplex; + } + + if (phydev->speed != priv->oldspeed) { + switch (phydev->speed) { + case 1000: + tempval = + ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); + + ecntrl &= ~(ECNTRL_R100); + break; + case 100: + case 10: + tempval = + ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); + + /* Reduced mode distinguishes + * between 10 and 100 + */ + if (phydev->speed == SPEED_100) + ecntrl |= ECNTRL_R100; + else + ecntrl &= ~(ECNTRL_R100); + break; + default: + netif_warn(priv, link, priv->ndev, + "Ack! Speed (%d) is not 10/100/1000!\n", + phydev->speed); + break; + } + + priv->oldspeed = phydev->speed; + } + + tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); + tempval1 |= gfar_get_flowctrl_cfg(priv); + + gfar_write(®s->maccfg1, tempval1); + gfar_write(®s->maccfg2, tempval); + gfar_write(®s->ecntrl, ecntrl); + + if (!priv->oldlink) + priv->oldlink = 1; + + } else if (priv->oldlink) { + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + } + + if (netif_msg_link(priv)) + phy_print_status(phydev); +} + static struct of_device_id gfar_match[] = { { diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 04b552cd419..84632c569f2 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -9,7 +9,7 @@ * Maintainer: Kumar Gala * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> * - * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc. + * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -29,7 +29,6 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -146,6 +145,10 @@ extern const char gfar_driver_version[]; | SUPPORTED_Autoneg \ | SUPPORTED_MII) +#define GFAR_SUPPORTED_GBIT (SUPPORTED_1000baseT_Full \ + | SUPPORTED_Pause \ + | SUPPORTED_Asym_Pause) + /* TBI register addresses */ #define MII_TBICON 0x11 @@ -374,8 +377,11 @@ extern const char gfar_driver_version[]; IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \ | IMASK_PERR) -#define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \ - & IMASK_DEFAULT) +#define IMASK_RX_DEFAULT (IMASK_RXFEN0 | IMASK_BSY) +#define IMASK_TX_DEFAULT (IMASK_TXFEN | IMASK_TXBEN) + +#define IMASK_RX_DISABLED ((~(IMASK_RX_DEFAULT)) & IMASK_DEFAULT) +#define IMASK_TX_DISABLED ((~(IMASK_TX_DEFAULT)) & IMASK_DEFAULT) /* Fifo management */ #define FIFO_TX_THR_MASK 0x01ff @@ -406,7 +412,9 @@ extern const char gfar_driver_version[]; /* This default RIR value directly corresponds * to the 3-bit hash value generated */ -#define DEFAULT_RIR0 0x05397700 +#define DEFAULT_8RXQ_RIR0 0x05397700 +/* Map even hash values to Q0, and odd ones to Q1 */ +#define DEFAULT_2RXQ_RIR0 0x04104100 /* RQFCR register bits */ #define RQFCR_GPI 0x80000000 @@ -571,7 +579,7 @@ struct rxfcb { }; struct gianfar_skb_cb { - int alignamount; + unsigned int bytes_sent; /* bytes-on-wire (i.e. no FCB) */ }; #define GFAR_CB(skb) ((struct gianfar_skb_cb *)((skb)->cb)) @@ -877,7 +885,6 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010 #define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020 #define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040 -#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080 #define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x00000100 #define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 @@ -889,8 +896,8 @@ struct gfar { #define DEFAULT_MAPPING 0xFF #endif -#define ISRG_SHIFT_TX 0x10 -#define ISRG_SHIFT_RX 0x18 +#define ISRG_RR0 0x80000000 +#define ISRG_TR0 0x00800000 /* The same driver can operate in two modes */ /* SQ_SG_MODE: Single Queue Single Group Mode @@ -902,6 +909,22 @@ enum { MQ_MG_MODE }; +/* GFAR_SQ_POLLING: Single Queue NAPI polling mode + * The driver supports a single pair of RX/Tx queues + * per interrupt group (Rx/Tx int line). MQ_MG mode + * devices have 2 interrupt groups, so the device will + * have a total of 2 Tx and 2 Rx queues in this case. + * GFAR_MQ_POLLING: Multi Queue NAPI polling mode + * The driver supports all the 8 Rx and Tx HW queues + * each queue mapped by the Device Tree to one of + * the 2 interrupt groups. This mode implies significant + * processing overhead (CPU and controller level). + */ +enum gfar_poll_mode { + GFAR_SQ_POLLING = 0, + GFAR_MQ_POLLING +}; + /* * Per TX queue stats */ @@ -963,7 +986,6 @@ struct rx_q_stats { /** * struct gfar_priv_rx_q - per rx queue structure - * @rxlock: per queue rx spin lock * @rx_skbuff: skb pointers * @skb_currx: currently use skb pointer * @rx_bd_base: First rx buffer descriptor @@ -976,8 +998,7 @@ struct rx_q_stats { */ struct gfar_priv_rx_q { - spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct sk_buff ** rx_skbuff; + struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); dma_addr_t rx_bd_dma_base; struct rxbd8 *rx_bd_base; struct rxbd8 *cur_rx; @@ -1009,23 +1030,24 @@ struct gfar_irqinfo { * @napi: the napi poll function * @priv: back pointer to the priv structure * @regs: the ioremapped register space for this group - * @grp_id: group id for this group * @irqinfo: TX/RX/ER irq data for this group */ struct gfar_priv_grp { - spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct napi_struct napi; - struct gfar_private *priv; + spinlock_t grplock __aligned(SMP_CACHE_BYTES); + struct napi_struct napi_rx; + struct napi_struct napi_tx; struct gfar __iomem *regs; - unsigned int grp_id; - unsigned long num_rx_queues; - unsigned long rx_bit_map; - /* cacheline 3 */ - unsigned int rstat; + struct gfar_priv_tx_q *tx_queue; + struct gfar_priv_rx_q *rx_queue; unsigned int tstat; + unsigned int rstat; + + struct gfar_private *priv; unsigned long num_tx_queues; unsigned long tx_bit_map; + unsigned long num_rx_queues; + unsigned long rx_bit_map; struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS]; }; @@ -1040,6 +1062,11 @@ enum gfar_errata { GFAR_ERRATA_12 = 0x08, /* a.k.a errata eTSEC49 */ }; +enum gfar_dev_state { + GFAR_DOWN = 1, + GFAR_RESETTING +}; + /* Struct stolen almost completely (and shamelessly) from the FCC enet source * (Ok, that's not so true anymore, but there is a family resemblance) * The GFAR buffer descriptors track the ring buffers. The rx_bd_base @@ -1050,8 +1077,6 @@ enum gfar_errata { * the buffer descriptor determines the actual condition. */ struct gfar_private { - unsigned int num_rx_queues; - struct device *dev; struct net_device *ndev; enum gfar_errata errata; @@ -1059,6 +1084,7 @@ struct gfar_private { u16 uses_rxfcb; u16 padding; + u32 device_flags; /* HW time stamping enabled flag */ int hwts_rx_en; @@ -1068,10 +1094,12 @@ struct gfar_private { struct gfar_priv_rx_q *rx_queue[MAX_RX_QS]; struct gfar_priv_grp gfargrp[MAXGROUPS]; - u32 device_flags; + unsigned long state; - unsigned int mode; + unsigned short mode; + unsigned short poll_mode; unsigned int num_tx_queues; + unsigned int num_rx_queues; unsigned int num_grps; /* Network Statistics */ @@ -1102,12 +1130,19 @@ struct gfar_private { /* Wake-on-LAN enabled */ wol_en:1, /* Enable priorty based Tx scheduling in Hw */ - prio_sched_en:1; + prio_sched_en:1, + /* Flow control flags */ + pause_aneg_en:1, + tx_pause_en:1, + rx_pause_en:1; /* The total tx and rx ring size for the enabled queues */ unsigned int total_tx_ring_size; unsigned int total_rx_ring_size; + u32 rqueue; + u32 tqueue; + /* RX per device parameters */ unsigned int rx_stash_size; unsigned int rx_stash_index; @@ -1122,11 +1157,6 @@ struct gfar_private { u32 __iomem *hash_regs[16]; int hash_width; - /* global parameters */ - unsigned int fifo_threshold; - unsigned int fifo_starve; - unsigned int fifo_starve_off; - /*Filer table*/ unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; @@ -1171,21 +1201,42 @@ static inline void gfar_read_filer(struct gfar_private *priv, *fpr = gfar_read(®s->rqfpr); } -extern void lock_rx_qs(struct gfar_private *priv); -extern void lock_tx_qs(struct gfar_private *priv); -extern void unlock_rx_qs(struct gfar_private *priv); -extern void unlock_tx_qs(struct gfar_private *priv); -extern irqreturn_t gfar_receive(int irq, void *dev_id); -extern int startup_gfar(struct net_device *dev); -extern void stop_gfar(struct net_device *dev); -extern void gfar_halt(struct net_device *dev); -extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, - int enable, u32 regnum, u32 read); -extern void gfar_configure_coalescing_all(struct gfar_private *priv); -void gfar_init_sysfs(struct net_device *dev); +static inline void gfar_write_isrg(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 __iomem *baddr = ®s->isrg0; + u32 isrg = 0; + int grp_idx, i; + + for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) { + struct gfar_priv_grp *grp = &priv->gfargrp[grp_idx]; + + for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) { + isrg |= (ISRG_RR0 >> i); + } + + for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) { + isrg |= (ISRG_TR0 >> i); + } + + gfar_write(baddr, isrg); + + baddr++; + isrg = 0; + } +} + +irqreturn_t gfar_receive(int irq, void *dev_id); +int startup_gfar(struct net_device *dev); +void stop_gfar(struct net_device *dev); +void reset_gfar(struct net_device *dev); +void gfar_mac_reset(struct gfar_private *priv); +void gfar_halt(struct gfar_private *priv); +void gfar_start(struct gfar_private *priv); +void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, int enable, + u32 regnum, u32 read); +void gfar_configure_coalescing_all(struct gfar_private *priv); int gfar_set_features(struct net_device *dev, netdev_features_t features); -extern void gfar_check_rx_parser_mode(struct gfar_private *priv); -extern void gfar_vlan_mode(struct net_device *dev, netdev_features_t features); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 21cd88124ca..76d70708f86 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -22,7 +22,6 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -45,10 +44,6 @@ #include "gianfar.h" -extern void gfar_start(struct net_device *dev); -extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, - int rx_work_limit); - #define GFAR_MAX_COAL_USECS 0xffff #define GFAR_MAX_COAL_FRAMES 0xff static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, @@ -365,25 +360,11 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) { struct gfar_private *priv = netdev_priv(dev); - int i = 0; + int i, err = 0; if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; - /* Set up rx coalescing */ - /* As of now, we will enable/disable coalescing for all - * queues together in case of eTSEC2, this will be modified - * along with the ethtool interface - */ - if ((cvals->rx_coalesce_usecs == 0) || - (cvals->rx_max_coalesced_frames == 0)) { - for (i = 0; i < priv->num_rx_queues; i++) - priv->rx_queue[i]->rxcoalescing = 0; - } else { - for (i = 0; i < priv->num_rx_queues; i++) - priv->rx_queue[i]->rxcoalescing = 1; - } - if (NULL == priv->phydev) return -ENODEV; @@ -400,6 +381,32 @@ static int gfar_scoalesce(struct net_device *dev, return -EINVAL; } + /* Check the bounds of the values */ + if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + netdev_info(dev, "Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + netdev_info(dev, "Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); + + /* Set up rx coalescing */ + if ((cvals->rx_coalesce_usecs == 0) || + (cvals->rx_max_coalesced_frames == 0)) { + for (i = 0; i < priv->num_rx_queues; i++) + priv->rx_queue[i]->rxcoalescing = 0; + } else { + for (i = 0; i < priv->num_rx_queues; i++) + priv->rx_queue[i]->rxcoalescing = 1; + } + for (i = 0; i < priv->num_rx_queues; i++) { priv->rx_queue[i]->rxic = mk_ic_value( cvals->rx_max_coalesced_frames, @@ -416,28 +423,22 @@ static int gfar_scoalesce(struct net_device *dev, priv->tx_queue[i]->txcoalescing = 1; } - /* Check the bounds of the values */ - if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { - netdev_info(dev, "Coalescing is limited to %d microseconds\n", - GFAR_MAX_COAL_USECS); - return -EINVAL; - } - - if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { - netdev_info(dev, "Coalescing is limited to %d frames\n", - GFAR_MAX_COAL_FRAMES); - return -EINVAL; - } - for (i = 0; i < priv->num_tx_queues; i++) { priv->tx_queue[i]->txic = mk_ic_value( cvals->tx_max_coalesced_frames, gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs)); } - gfar_configure_coalescing_all(priv); + if (dev->flags & IFF_UP) { + stop_gfar(dev); + err = startup_gfar(dev); + } else { + gfar_mac_reset(priv); + } - return 0; + clear_bit_unlock(GFAR_RESETTING, &priv->state); + + return err; } /* Fills in rvals with the current ring parameters. Currently, @@ -468,15 +469,13 @@ static void gfar_gringparam(struct net_device *dev, } /* Change the current ring parameters, stopping the controller if - * necessary so that we don't mess things up while we're in - * motion. We wait for the ring to be clean before reallocating - * the rings. + * necessary so that we don't mess things up while we're in motion. */ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) { struct gfar_private *priv = netdev_priv(dev); - int err = 0, i = 0; + int err = 0, i; if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) return -EINVAL; @@ -494,86 +493,128 @@ static int gfar_sringparam(struct net_device *dev, return -EINVAL; } + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); - if (dev->flags & IFF_UP) { - unsigned long flags; - - /* Halt TX and RX, and process the frames which - * have already been received - */ - local_irq_save(flags); - lock_tx_qs(priv); - lock_rx_qs(priv); - - gfar_halt(dev); - - unlock_rx_qs(priv); - unlock_tx_qs(priv); - local_irq_restore(flags); - - for (i = 0; i < priv->num_rx_queues; i++) - gfar_clean_rx_ring(priv->rx_queue[i], - priv->rx_queue[i]->rx_ring_size); - - /* Now we take down the rings to rebuild them */ + if (dev->flags & IFF_UP) stop_gfar(dev); - } - /* Change the size */ - for (i = 0; i < priv->num_rx_queues; i++) { + /* Change the sizes */ + for (i = 0; i < priv->num_rx_queues; i++) priv->rx_queue[i]->rx_ring_size = rvals->rx_pending; + + for (i = 0; i < priv->num_tx_queues; i++) priv->tx_queue[i]->tx_ring_size = rvals->tx_pending; - priv->tx_queue[i]->num_txbdfree = - priv->tx_queue[i]->tx_ring_size; - } /* Rebuild the rings with the new size */ - if (dev->flags & IFF_UP) { + if (dev->flags & IFF_UP) err = startup_gfar(dev); - netif_tx_wake_all_queues(dev); - } + + clear_bit_unlock(GFAR_RESETTING, &priv->state); + return err; } -int gfar_set_features(struct net_device *dev, netdev_features_t features) +static void gfar_gpauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) { struct gfar_private *priv = netdev_priv(dev); - unsigned long flags; - int err = 0, i = 0; - netdev_features_t changed = dev->features ^ features; - if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX)) - gfar_vlan_mode(dev, features); + epause->autoneg = !!priv->pause_aneg_en; + epause->rx_pause = !!priv->rx_pause_en; + epause->tx_pause = !!priv->tx_pause_en; +} - if (!(changed & NETIF_F_RXCSUM)) - return 0; +static int gfar_spauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct gfar_private *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 oldadv, newadv; - if (dev->flags & IFF_UP) { - /* Halt TX and RX, and process the frames which - * have already been received - */ - local_irq_save(flags); - lock_tx_qs(priv); - lock_rx_qs(priv); + if (!phydev) + return -ENODEV; - gfar_halt(dev); + if (!(phydev->supported & SUPPORTED_Pause) || + (!(phydev->supported & SUPPORTED_Asym_Pause) && + (epause->rx_pause != epause->tx_pause))) + return -EINVAL; - unlock_tx_qs(priv); - unlock_rx_qs(priv); - local_irq_restore(flags); + priv->rx_pause_en = priv->tx_pause_en = 0; + if (epause->rx_pause) { + priv->rx_pause_en = 1; + + if (epause->tx_pause) { + priv->tx_pause_en = 1; + /* FLOW_CTRL_RX & TX */ + newadv = ADVERTISED_Pause; + } else /* FLOW_CTLR_RX */ + newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause; + } else if (epause->tx_pause) { + priv->tx_pause_en = 1; + /* FLOW_CTLR_TX */ + newadv = ADVERTISED_Asym_Pause; + } else + newadv = 0; + + if (epause->autoneg) + priv->pause_aneg_en = 1; + else + priv->pause_aneg_en = 0; + + oldadv = phydev->advertising & + (ADVERTISED_Pause | ADVERTISED_Asym_Pause); + if (oldadv != newadv) { + phydev->advertising &= + ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); + phydev->advertising |= newadv; + if (phydev->autoneg) + /* inform link partner of our + * new flow ctrl settings + */ + return phy_start_aneg(phydev); + + if (!epause->autoneg) { + u32 tempval; + tempval = gfar_read(®s->maccfg1); + tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); + if (priv->tx_pause_en) + tempval |= MACCFG1_TX_FLOW; + if (priv->rx_pause_en) + tempval |= MACCFG1_RX_FLOW; + gfar_write(®s->maccfg1, tempval); + } + } - for (i = 0; i < priv->num_rx_queues; i++) - gfar_clean_rx_ring(priv->rx_queue[i], - priv->rx_queue[i]->rx_ring_size); + return 0; +} - /* Now we take down the rings to rebuild them */ - stop_gfar(dev); +int gfar_set_features(struct net_device *dev, netdev_features_t features) +{ + netdev_features_t changed = dev->features ^ features; + struct gfar_private *priv = netdev_priv(dev); + int err = 0; - dev->features = features; + if (!(changed & (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_RXCSUM))) + return 0; + + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); + + dev->features = features; + if (dev->flags & IFF_UP) { + /* Now we take down the rings to rebuild them */ + stop_gfar(dev); err = startup_gfar(dev); - netif_tx_wake_all_queues(dev); + } else { + gfar_mac_reset(priv); } + + clear_bit_unlock(GFAR_RESETTING, &priv->state); + return err; } @@ -817,11 +858,9 @@ static int gfar_set_hash_opts(struct gfar_private *priv, static int gfar_check_filer_hardware(struct gfar_private *priv) { - struct gfar __iomem *regs = NULL; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 i; - regs = priv->gfargrp[0].regs; - /* Check if we are in FIFO mode */ i = gfar_read(®s->ecntrl); i &= ECNTRL_FIFM; @@ -855,7 +894,7 @@ static int gfar_check_filer_hardware(struct gfar_private *priv) /* Sets the properties for arbitrary filer rule * to the first 4 Layer 4 Bytes */ - regs->rbifx = 0xC0C1C2C3; + gfar_write(®s->rbifx, 0xC0C1C2C3); return 0; } @@ -983,10 +1022,18 @@ static void gfar_set_basic_ip(struct ethtool_tcpip4_spec *value, struct ethtool_tcpip4_spec *mask, struct filer_table *tab) { - gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab); - gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab); - gfar_set_attribute(value->pdst, mask->pdst, RQFCR_PID_DPT, tab); - gfar_set_attribute(value->psrc, mask->psrc, RQFCR_PID_SPT, tab); + gfar_set_attribute(be32_to_cpu(value->ip4src), + be32_to_cpu(mask->ip4src), + RQFCR_PID_SIA, tab); + gfar_set_attribute(be32_to_cpu(value->ip4dst), + be32_to_cpu(mask->ip4dst), + RQFCR_PID_DIA, tab); + gfar_set_attribute(be16_to_cpu(value->pdst), + be16_to_cpu(mask->pdst), + RQFCR_PID_DPT, tab); + gfar_set_attribute(be16_to_cpu(value->psrc), + be16_to_cpu(mask->psrc), + RQFCR_PID_SPT, tab); gfar_set_attribute(value->tos, mask->tos, RQFCR_PID_TOS, tab); } @@ -995,12 +1042,17 @@ static void gfar_set_user_ip(struct ethtool_usrip4_spec *value, struct ethtool_usrip4_spec *mask, struct filer_table *tab) { - gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab); - gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab); + gfar_set_attribute(be32_to_cpu(value->ip4src), + be32_to_cpu(mask->ip4src), + RQFCR_PID_SIA, tab); + gfar_set_attribute(be32_to_cpu(value->ip4dst), + be32_to_cpu(mask->ip4dst), + RQFCR_PID_DIA, tab); gfar_set_attribute(value->tos, mask->tos, RQFCR_PID_TOS, tab); gfar_set_attribute(value->proto, mask->proto, RQFCR_PID_L4P, tab); - gfar_set_attribute(value->l4_4_bytes, mask->l4_4_bytes, RQFCR_PID_ARB, - tab); + gfar_set_attribute(be32_to_cpu(value->l4_4_bytes), + be32_to_cpu(mask->l4_4_bytes), + RQFCR_PID_ARB, tab); } @@ -1067,7 +1119,41 @@ static void gfar_set_ether(struct ethhdr *value, struct ethhdr *mask, } } - gfar_set_attribute(value->h_proto, mask->h_proto, RQFCR_PID_ETY, tab); + gfar_set_attribute(be16_to_cpu(value->h_proto), + be16_to_cpu(mask->h_proto), + RQFCR_PID_ETY, tab); +} + +static inline u32 vlan_tci_vid(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_VID_MASK; +} + +static inline u32 vlan_tci_vidm(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_VID_MASK; +} + +static inline u32 vlan_tci_cfi(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_CFI_MASK; +} + +static inline u32 vlan_tci_cfim(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_CFI_MASK; +} + +static inline u32 vlan_tci_prio(struct ethtool_rx_flow_spec *rule) +{ + return (be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; +} + +static inline u32 vlan_tci_priom(struct ethtool_rx_flow_spec *rule) +{ + return (be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; } /* Convert a rule to binary filter format of gianfar */ @@ -1081,22 +1167,21 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule, u32 old_index = tab->index; /* Check if vlan is wanted */ - if ((rule->flow_type & FLOW_EXT) && (rule->m_ext.vlan_tci != 0xFFFF)) { + if ((rule->flow_type & FLOW_EXT) && + (rule->m_ext.vlan_tci != cpu_to_be16(0xFFFF))) { if (!rule->m_ext.vlan_tci) - rule->m_ext.vlan_tci = 0xFFFF; + rule->m_ext.vlan_tci = cpu_to_be16(0xFFFF); vlan = RQFPR_VLN; vlan_mask = RQFPR_VLN; /* Separate the fields */ - id = rule->h_ext.vlan_tci & VLAN_VID_MASK; - id_mask = rule->m_ext.vlan_tci & VLAN_VID_MASK; - cfi = rule->h_ext.vlan_tci & VLAN_CFI_MASK; - cfi_mask = rule->m_ext.vlan_tci & VLAN_CFI_MASK; - prio = (rule->h_ext.vlan_tci & VLAN_PRIO_MASK) >> - VLAN_PRIO_SHIFT; - prio_mask = (rule->m_ext.vlan_tci & VLAN_PRIO_MASK) >> - VLAN_PRIO_SHIFT; + id = vlan_tci_vid(rule); + id_mask = vlan_tci_vidm(rule); + cfi = vlan_tci_cfi(rule); + cfi_mask = vlan_tci_cfim(rule); + prio = vlan_tci_prio(rule); + prio_mask = vlan_tci_priom(rule); if (cfi == VLAN_TAG_PRESENT && cfi_mask == VLAN_TAG_PRESENT) { vlan |= RQFPR_CFI; @@ -1495,9 +1580,6 @@ static int gfar_write_filer_table(struct gfar_private *priv, if (tab->index > MAX_FILER_IDX - 1) return -EBUSY; - /* Avoid inconsistent filer table to be processed */ - lock_rx_qs(priv); - /* Fill regular entries */ for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl); i++) @@ -1510,8 +1592,6 @@ static int gfar_write_filer_table(struct gfar_private *priv, */ gfar_write_filer(priv, i, 0x20, 0x0); - unlock_rx_qs(priv); - return 0; } @@ -1594,10 +1674,10 @@ static void gfar_invert_masks(struct ethtool_rx_flow_spec *flow) for (i = 0; i < sizeof(flow->m_u); i++) flow->m_u.hdata[i] ^= 0xFF; - flow->m_ext.vlan_etype ^= 0xFFFF; - flow->m_ext.vlan_tci ^= 0xFFFF; - flow->m_ext.data[0] ^= ~0; - flow->m_ext.data[1] ^= ~0; + flow->m_ext.vlan_etype ^= cpu_to_be16(0xFFFF); + flow->m_ext.vlan_tci ^= cpu_to_be16(0xFFFF); + flow->m_ext.data[0] ^= cpu_to_be32(~0); + flow->m_ext.data[1] ^= cpu_to_be32(~0); } static int gfar_add_cls(struct gfar_private *priv, @@ -1716,6 +1796,9 @@ static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd) struct gfar_private *priv = netdev_priv(dev); int ret = 0; + if (test_bit(GFAR_RESETTING, &priv->state)) + return -EBUSY; + mutex_lock(&priv->rx_queue_access); switch (cmd->cmd) { @@ -1806,6 +1889,8 @@ const struct ethtool_ops gfar_ethtool_ops = { .set_coalesce = gfar_scoalesce, .get_ringparam = gfar_gringparam, .set_ringparam = gfar_sringparam, + .get_pauseparam = gfar_gpauseparam, + .set_pauseparam = gfar_spauseparam, .get_strings = gfar_gstrings, .get_sset_count = gfar_sset_count, .get_ethtool_stats = gfar_fill_stats, diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 083ea2b4d20..bb568006f37 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -22,7 +22,6 @@ #include <linux/device.h> #include <linux/hrtimer.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> @@ -134,7 +133,7 @@ struct gianfar_ptp_registers { #define REG_SIZE sizeof(struct gianfar_ptp_registers) struct etsects { - struct gianfar_ptp_registers *regs; + struct gianfar_ptp_registers __iomem *regs; spinlock_t lock; /* protects regs */ struct ptp_clock *clock; struct ptp_clock_info caps; @@ -415,6 +414,7 @@ static struct ptp_clock_info ptp_gianfar_caps = { .n_alarm = 0, .n_ext_ts = N_EXT_TS, .n_per_out = 0, + .n_pins = 0, .pps = 1, .adjfreq = ptp_gianfar_adjfreq, .adjtime = ptp_gianfar_adjtime, @@ -452,7 +452,9 @@ static int gianfar_ptp_probe(struct platform_device *dev) err = -ENODEV; etsects->caps = ptp_gianfar_caps; - etsects->cksel = DEFAULT_CKSEL; + + if (get_of_u32(node, "fsl,cksel", &etsects->cksel)) + etsects->cksel = DEFAULT_CKSEL; if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) || get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) || @@ -519,7 +521,7 @@ static int gianfar_ptp_probe(struct platform_device *dev) } gfar_phc_index = ptp_clock_index(etsects->clock); - dev_set_drvdata(&dev->dev, etsects); + platform_set_drvdata(dev, etsects); return 0; @@ -537,7 +539,7 @@ no_memory: static int gianfar_ptp_remove(struct platform_device *dev) { - struct etsects *etsects = dev_get_drvdata(&dev->dev); + struct etsects *etsects = platform_get_drvdata(dev); gfar_write(&etsects->regs->tmr_temask, 0); gfar_write(&etsects->regs->tmr_ctrl, 0); diff --git a/drivers/net/ethernet/freescale/gianfar_sysfs.c b/drivers/net/ethernet/freescale/gianfar_sysfs.c deleted file mode 100644 index acb55af7e3f..00000000000 --- a/drivers/net/ethernet/freescale/gianfar_sysfs.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * drivers/net/ethernet/freescale/gianfar_sysfs.c - * - * Gianfar Ethernet Driver - * This driver is designed for the non-CPM ethernet controllers - * on the 85xx and 83xx family of integrated processors - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (galak@kernel.crashing.org) - * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> - * - * Copyright 2002-2009 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Sysfs file creation and management - */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/unistd.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/etherdevice.h> -#include <linux/spinlock.h> -#include <linux/mm.h> -#include <linux/device.h> - -#include <asm/uaccess.h> -#include <linux/module.h> - -#include "gianfar.h" - -static ssize_t gfar_show_bd_stash(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%s\n", priv->bd_stash_en ? "on" : "off"); -} - -static ssize_t gfar_set_bd_stash(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - int new_setting = 0; - u32 temp; - unsigned long flags; - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING)) - return count; - - - /* Find out the new setting */ - if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) - new_setting = 1; - else if (!strncmp("off", buf, count - 1) || - !strncmp("0", buf, count - 1)) - new_setting = 0; - else - return count; - - - local_irq_save(flags); - lock_rx_qs(priv); - - /* Set the new stashing value */ - priv->bd_stash_en = new_setting; - - temp = gfar_read(®s->attr); - - if (new_setting) - temp |= ATTR_BDSTASH; - else - temp &= ~(ATTR_BDSTASH); - - gfar_write(®s->attr, temp); - - unlock_rx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(bd_stash, 0644, gfar_show_bd_stash, gfar_set_bd_stash); - -static ssize_t gfar_show_rx_stash_size(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->rx_stash_size); -} - -static ssize_t gfar_set_rx_stash_size(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int length = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) - return count; - - local_irq_save(flags); - lock_rx_qs(priv); - - if (length > priv->rx_buffer_size) - goto out; - - if (length == priv->rx_stash_size) - goto out; - - priv->rx_stash_size = length; - - temp = gfar_read(®s->attreli); - temp &= ~ATTRELI_EL_MASK; - temp |= ATTRELI_EL(length); - gfar_write(®s->attreli, temp); - - /* Turn stashing on/off as appropriate */ - temp = gfar_read(®s->attr); - - if (length) - temp |= ATTR_BUFSTASH; - else - temp &= ~(ATTR_BUFSTASH); - - gfar_write(®s->attr, temp); - -out: - unlock_rx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(rx_stash_size, 0644, gfar_show_rx_stash_size, - gfar_set_rx_stash_size); - -/* Stashing will only be enabled when rx_stash_size != 0 */ -static ssize_t gfar_show_rx_stash_index(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->rx_stash_index); -} - -static ssize_t gfar_set_rx_stash_index(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned short index = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) - return count; - - local_irq_save(flags); - lock_rx_qs(priv); - - if (index > priv->rx_stash_size) - goto out; - - if (index == priv->rx_stash_index) - goto out; - - priv->rx_stash_index = index; - - temp = gfar_read(®s->attreli); - temp &= ~ATTRELI_EI_MASK; - temp |= ATTRELI_EI(index); - gfar_write(®s->attreli, temp); - -out: - unlock_rx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(rx_stash_index, 0644, gfar_show_rx_stash_index, - gfar_set_rx_stash_index); - -static ssize_t gfar_show_fifo_threshold(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->fifo_threshold); -} - -static ssize_t gfar_set_fifo_threshold(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int length = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (length > GFAR_MAX_FIFO_THRESHOLD) - return count; - - local_irq_save(flags); - lock_tx_qs(priv); - - priv->fifo_threshold = length; - - temp = gfar_read(®s->fifo_tx_thr); - temp &= ~FIFO_TX_THR_MASK; - temp |= length; - gfar_write(®s->fifo_tx_thr, temp); - - unlock_tx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(fifo_threshold, 0644, gfar_show_fifo_threshold, - gfar_set_fifo_threshold); - -static ssize_t gfar_show_fifo_starve(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->fifo_starve); -} - -static ssize_t gfar_set_fifo_starve(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int num = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (num > GFAR_MAX_FIFO_STARVE) - return count; - - local_irq_save(flags); - lock_tx_qs(priv); - - priv->fifo_starve = num; - - temp = gfar_read(®s->fifo_tx_starve); - temp &= ~FIFO_TX_STARVE_MASK; - temp |= num; - gfar_write(®s->fifo_tx_starve, temp); - - unlock_tx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(fifo_starve, 0644, gfar_show_fifo_starve, - gfar_set_fifo_starve); - -static ssize_t gfar_show_fifo_starve_off(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->fifo_starve_off); -} - -static ssize_t gfar_set_fifo_starve_off(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int num = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (num > GFAR_MAX_FIFO_STARVE_OFF) - return count; - - local_irq_save(flags); - lock_tx_qs(priv); - - priv->fifo_starve_off = num; - - temp = gfar_read(®s->fifo_tx_starve_shutoff); - temp &= ~FIFO_TX_STARVE_OFF_MASK; - temp |= num; - gfar_write(®s->fifo_tx_starve_shutoff, temp); - - unlock_tx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(fifo_starve_off, 0644, gfar_show_fifo_starve_off, - gfar_set_fifo_starve_off); - -void gfar_init_sysfs(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - int rc; - - /* Initialize the default values */ - priv->fifo_threshold = DEFAULT_FIFO_TX_THR; - priv->fifo_starve = DEFAULT_FIFO_TX_STARVE; - priv->fifo_starve_off = DEFAULT_FIFO_TX_STARVE_OFF; - - /* Create our sysfs files */ - rc = device_create_file(&dev->dev, &dev_attr_bd_stash); - rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_size); - rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_index); - rc |= device_create_file(&dev->dev, &dev_attr_fifo_threshold); - rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve); - rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve_off); - if (rc) - dev_err(&dev->dev, "Error creating gianfar sysfs files\n"); -} diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index e04c59818f6..36fc429298e 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -31,6 +31,8 @@ #include <linux/mii.h> #include <linux/phy.h> #include <linux/workqueue.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_mdio.h> #include <linux/of_net.h> #include <linux/of_platform.h> @@ -433,11 +435,6 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth, QE_CR_PROTOCOL_ETHERNET, 0); } -static inline int compare_addr(u8 **addr1, u8 **addr2) -{ - return memcmp(addr1, addr2, ETH_ALEN); -} - #ifdef DEBUG static void get_statistics(struct ucc_geth_private *ugeth, struct ucc_geth_tx_firmware_statistics * @@ -1731,9 +1728,6 @@ static int init_phy(struct net_device *dev) phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0, priv->phy_interface); - if (!phydev) - phydev = of_phy_connect_fixed_link(dev, &adjust_link, - priv->phy_interface); if (!phydev) { dev_err(&dev->dev, "Could not attach to PHY\n"); return -ENODEV; @@ -2996,11 +2990,11 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (ug_info->rxExtendedFiltering) { size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; if (ug_info->largestexternallookupkeysize == - QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES) + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; if (ug_info->largestexternallookupkeysize == - QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES) + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES) size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16; } @@ -3264,7 +3258,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) dev->stats.tx_packets++; - dev_kfree_skb(skb); + dev_consume_skb_any(skb); ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; ugeth->skb_dirtytx[txQ] = @@ -3564,7 +3558,7 @@ static void ucc_geth_timeout(struct net_device *dev) static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state) { - struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct net_device *ndev = platform_get_drvdata(ofdev); struct ucc_geth_private *ugeth = netdev_priv(ndev); if (!netif_running(ndev)) @@ -3592,7 +3586,7 @@ static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state) static int ucc_geth_resume(struct platform_device *ofdev) { - struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct net_device *ndev = platform_get_drvdata(ofdev); struct ucc_geth_private *ugeth = netdev_priv(ndev); int err; @@ -3793,6 +3787,17 @@ static int ucc_geth_probe(struct platform_device* ofdev) ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); ug_info->phy_node = of_parse_phandle(np, "phy-handle", 0); + if (!ug_info->phy_node) { + /* In the case of a fixed PHY, the DT node associated + * to the PHY is the Ethernet MAC DT node. + */ + if (of_phy_is_fixed_link(np)) { + err = of_phy_register_fixed_link(np); + if (err) + return err; + } + ug_info->phy_node = np; + } /* Find the TBI PHY node. If it's not there, we don't support SGMII */ ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0); @@ -3899,7 +3904,7 @@ static int ucc_geth_probe(struct platform_device* ofdev) mac_addr = of_get_mac_address(np); if (mac_addr) - memcpy(dev->dev_addr, mac_addr, 6); + memcpy(dev->dev_addr, mac_addr, ETH_ALEN); ugeth->ug_info = ug_info; ugeth->dev = device; @@ -3911,14 +3916,12 @@ static int ucc_geth_probe(struct platform_device* ofdev) static int ucc_geth_remove(struct platform_device* ofdev) { - struct device *device = &ofdev->dev; - struct net_device *dev = dev_get_drvdata(device); + struct net_device *dev = platform_get_drvdata(ofdev); struct ucc_geth_private *ugeth = netdev_priv(dev); unregister_netdev(dev); free_netdev(dev); ucc_geth_memclean(ugeth); - dev_set_drvdata(device, NULL); return 0; } diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c index e79aaf9ae52..cc83350d56b 100644 --- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c +++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c @@ -16,7 +16,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/errno.h> #include <linux/stddef.h> #include <linux/interrupt.h> @@ -418,5 +417,5 @@ static const struct ethtool_ops uec_ethtool_ops = { void uec_set_ethtool_ops(struct net_device *netdev) { - SET_ETHTOOL_OPS(netdev, &uec_ethtool_ops); + netdev->ethtool_ops = &uec_ethtool_ops; } diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 418068b941b..0c9d55c862a 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/phy.h> #include <linux/mdio.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/of_mdio.h> @@ -161,7 +162,9 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) /* Return all Fs if nothing was there */ if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) { - dev_err(&bus->dev, "MDIO read error\n"); + dev_err(&bus->dev, + "Error while reading PHY%d reg at %d.%d\n", + phy_id, dev_addr, regnum); return 0xffff; } @@ -227,7 +230,7 @@ static int xgmac_mdio_probe(struct platform_device *pdev) goto err_registration; } - dev_set_drvdata(&pdev->dev, bus); + platform_set_drvdata(pdev, bus); return 0; @@ -242,7 +245,7 @@ err_ioremap: static int xgmac_mdio_remove(struct platform_device *pdev) { - struct mii_bus *bus = dev_get_drvdata(&pdev->dev); + struct mii_bus *bus = platform_get_drvdata(pdev); mdiobus_unregister(bus); iounmap(bus->priv); |
