1adfc5217SJeff Kirsher /* 2adfc5217SJeff Kirsher * Driver for BCM963xx builtin Ethernet mac 3adfc5217SJeff Kirsher * 4adfc5217SJeff Kirsher * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 5adfc5217SJeff Kirsher * 6adfc5217SJeff Kirsher * This program is free software; you can redistribute it and/or modify 7adfc5217SJeff Kirsher * it under the terms of the GNU General Public License as published by 8adfc5217SJeff Kirsher * the Free Software Foundation; either version 2 of the License, or 9adfc5217SJeff Kirsher * (at your option) any later version. 10adfc5217SJeff Kirsher * 11adfc5217SJeff Kirsher * This program is distributed in the hope that it will be useful, 12adfc5217SJeff Kirsher * but WITHOUT ANY WARRANTY; without even the implied warranty of 13adfc5217SJeff Kirsher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14adfc5217SJeff Kirsher * GNU General Public License for more details. 15adfc5217SJeff Kirsher * 16adfc5217SJeff Kirsher * You should have received a copy of the GNU General Public License 17adfc5217SJeff Kirsher * along with this program; if not, write to the Free Software 18adfc5217SJeff Kirsher * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19adfc5217SJeff Kirsher */ 20adfc5217SJeff Kirsher #include <linux/init.h> 21adfc5217SJeff Kirsher #include <linux/interrupt.h> 22adfc5217SJeff Kirsher #include <linux/module.h> 23adfc5217SJeff Kirsher #include <linux/clk.h> 24adfc5217SJeff Kirsher #include <linux/etherdevice.h> 25adfc5217SJeff Kirsher #include <linux/slab.h> 26adfc5217SJeff Kirsher #include <linux/delay.h> 27adfc5217SJeff Kirsher #include <linux/ethtool.h> 28adfc5217SJeff Kirsher #include <linux/crc32.h> 29adfc5217SJeff Kirsher #include <linux/err.h> 30adfc5217SJeff Kirsher #include <linux/dma-mapping.h> 31adfc5217SJeff Kirsher #include <linux/platform_device.h> 32adfc5217SJeff Kirsher #include <linux/if_vlan.h> 33adfc5217SJeff Kirsher 34adfc5217SJeff Kirsher #include <bcm63xx_dev_enet.h> 35adfc5217SJeff Kirsher #include "bcm63xx_enet.h" 36adfc5217SJeff Kirsher 37adfc5217SJeff Kirsher static char bcm_enet_driver_name[] = "bcm63xx_enet"; 38adfc5217SJeff Kirsher static char bcm_enet_driver_version[] = "1.0"; 39adfc5217SJeff Kirsher 40adfc5217SJeff Kirsher static int copybreak __read_mostly = 128; 41adfc5217SJeff Kirsher module_param(copybreak, int, 0); 42adfc5217SJeff Kirsher MODULE_PARM_DESC(copybreak, "Receive copy threshold"); 43adfc5217SJeff Kirsher 440ae99b5fSMaxime Bizon /* io registers memory shared between all devices */ 450ae99b5fSMaxime Bizon static void __iomem *bcm_enet_shared_base[3]; 46adfc5217SJeff Kirsher 47adfc5217SJeff Kirsher /* 48adfc5217SJeff Kirsher * io helpers to access mac registers 49adfc5217SJeff Kirsher */ 50adfc5217SJeff Kirsher static inline u32 enet_readl(struct bcm_enet_priv *priv, u32 off) 51adfc5217SJeff Kirsher { 52adfc5217SJeff Kirsher return bcm_readl(priv->base + off); 53adfc5217SJeff Kirsher } 54adfc5217SJeff Kirsher 55adfc5217SJeff Kirsher static inline void enet_writel(struct bcm_enet_priv *priv, 56adfc5217SJeff Kirsher u32 val, u32 off) 57adfc5217SJeff Kirsher { 58adfc5217SJeff Kirsher bcm_writel(val, priv->base + off); 59adfc5217SJeff Kirsher } 60adfc5217SJeff Kirsher 61adfc5217SJeff Kirsher /* 626f00a022SMaxime Bizon * io helpers to access switch registers 63adfc5217SJeff Kirsher */ 646f00a022SMaxime Bizon static inline u32 enetsw_readl(struct bcm_enet_priv *priv, u32 off) 656f00a022SMaxime Bizon { 666f00a022SMaxime Bizon return bcm_readl(priv->base + off); 676f00a022SMaxime Bizon } 686f00a022SMaxime Bizon 696f00a022SMaxime Bizon static inline void enetsw_writel(struct bcm_enet_priv *priv, 706f00a022SMaxime Bizon u32 val, u32 off) 716f00a022SMaxime Bizon { 726f00a022SMaxime Bizon bcm_writel(val, priv->base + off); 736f00a022SMaxime Bizon } 746f00a022SMaxime Bizon 756f00a022SMaxime Bizon static inline u16 enetsw_readw(struct bcm_enet_priv *priv, u32 off) 766f00a022SMaxime Bizon { 776f00a022SMaxime Bizon return bcm_readw(priv->base + off); 786f00a022SMaxime Bizon } 796f00a022SMaxime Bizon 806f00a022SMaxime Bizon static inline void enetsw_writew(struct bcm_enet_priv *priv, 816f00a022SMaxime Bizon u16 val, u32 off) 826f00a022SMaxime Bizon { 836f00a022SMaxime Bizon bcm_writew(val, priv->base + off); 846f00a022SMaxime Bizon } 856f00a022SMaxime Bizon 866f00a022SMaxime Bizon static inline u8 enetsw_readb(struct bcm_enet_priv *priv, u32 off) 876f00a022SMaxime Bizon { 886f00a022SMaxime Bizon return bcm_readb(priv->base + off); 896f00a022SMaxime Bizon } 906f00a022SMaxime Bizon 916f00a022SMaxime Bizon static inline void enetsw_writeb(struct bcm_enet_priv *priv, 926f00a022SMaxime Bizon u8 val, u32 off) 936f00a022SMaxime Bizon { 946f00a022SMaxime Bizon bcm_writeb(val, priv->base + off); 956f00a022SMaxime Bizon } 966f00a022SMaxime Bizon 976f00a022SMaxime Bizon 986f00a022SMaxime Bizon /* io helpers to access shared registers */ 99adfc5217SJeff Kirsher static inline u32 enet_dma_readl(struct bcm_enet_priv *priv, u32 off) 100adfc5217SJeff Kirsher { 1010ae99b5fSMaxime Bizon return bcm_readl(bcm_enet_shared_base[0] + off); 102adfc5217SJeff Kirsher } 103adfc5217SJeff Kirsher 104adfc5217SJeff Kirsher static inline void enet_dma_writel(struct bcm_enet_priv *priv, 105adfc5217SJeff Kirsher u32 val, u32 off) 106adfc5217SJeff Kirsher { 1070ae99b5fSMaxime Bizon bcm_writel(val, bcm_enet_shared_base[0] + off); 1080ae99b5fSMaxime Bizon } 1090ae99b5fSMaxime Bizon 1103dc6475cSFlorian Fainelli static inline u32 enet_dmac_readl(struct bcm_enet_priv *priv, u32 off, int chan) 1110ae99b5fSMaxime Bizon { 1123dc6475cSFlorian Fainelli return bcm_readl(bcm_enet_shared_base[1] + 1133dc6475cSFlorian Fainelli bcm63xx_enetdmacreg(off) + chan * priv->dma_chan_width); 1140ae99b5fSMaxime Bizon } 1150ae99b5fSMaxime Bizon 1160ae99b5fSMaxime Bizon static inline void enet_dmac_writel(struct bcm_enet_priv *priv, 1173dc6475cSFlorian Fainelli u32 val, u32 off, int chan) 1180ae99b5fSMaxime Bizon { 1193dc6475cSFlorian Fainelli bcm_writel(val, bcm_enet_shared_base[1] + 1203dc6475cSFlorian Fainelli bcm63xx_enetdmacreg(off) + chan * priv->dma_chan_width); 1210ae99b5fSMaxime Bizon } 1220ae99b5fSMaxime Bizon 1233dc6475cSFlorian Fainelli static inline u32 enet_dmas_readl(struct bcm_enet_priv *priv, u32 off, int chan) 1240ae99b5fSMaxime Bizon { 1253dc6475cSFlorian Fainelli return bcm_readl(bcm_enet_shared_base[2] + off + chan * priv->dma_chan_width); 1260ae99b5fSMaxime Bizon } 1270ae99b5fSMaxime Bizon 1280ae99b5fSMaxime Bizon static inline void enet_dmas_writel(struct bcm_enet_priv *priv, 1293dc6475cSFlorian Fainelli u32 val, u32 off, int chan) 1300ae99b5fSMaxime Bizon { 1313dc6475cSFlorian Fainelli bcm_writel(val, bcm_enet_shared_base[2] + off + chan * priv->dma_chan_width); 132adfc5217SJeff Kirsher } 133adfc5217SJeff Kirsher 134adfc5217SJeff Kirsher /* 135adfc5217SJeff Kirsher * write given data into mii register and wait for transfer to end 136adfc5217SJeff Kirsher * with timeout (average measured transfer time is 25us) 137adfc5217SJeff Kirsher */ 138adfc5217SJeff Kirsher static int do_mdio_op(struct bcm_enet_priv *priv, unsigned int data) 139adfc5217SJeff Kirsher { 140adfc5217SJeff Kirsher int limit; 141adfc5217SJeff Kirsher 142adfc5217SJeff Kirsher /* make sure mii interrupt status is cleared */ 143adfc5217SJeff Kirsher enet_writel(priv, ENET_IR_MII, ENET_IR_REG); 144adfc5217SJeff Kirsher 145adfc5217SJeff Kirsher enet_writel(priv, data, ENET_MIIDATA_REG); 146adfc5217SJeff Kirsher wmb(); 147adfc5217SJeff Kirsher 148adfc5217SJeff Kirsher /* busy wait on mii interrupt bit, with timeout */ 149adfc5217SJeff Kirsher limit = 1000; 150adfc5217SJeff Kirsher do { 151adfc5217SJeff Kirsher if (enet_readl(priv, ENET_IR_REG) & ENET_IR_MII) 152adfc5217SJeff Kirsher break; 153adfc5217SJeff Kirsher udelay(1); 154adfc5217SJeff Kirsher } while (limit-- > 0); 155adfc5217SJeff Kirsher 156adfc5217SJeff Kirsher return (limit < 0) ? 1 : 0; 157adfc5217SJeff Kirsher } 158adfc5217SJeff Kirsher 159adfc5217SJeff Kirsher /* 160adfc5217SJeff Kirsher * MII internal read callback 161adfc5217SJeff Kirsher */ 162adfc5217SJeff Kirsher static int bcm_enet_mdio_read(struct bcm_enet_priv *priv, int mii_id, 163adfc5217SJeff Kirsher int regnum) 164adfc5217SJeff Kirsher { 165adfc5217SJeff Kirsher u32 tmp, val; 166adfc5217SJeff Kirsher 167adfc5217SJeff Kirsher tmp = regnum << ENET_MIIDATA_REG_SHIFT; 168adfc5217SJeff Kirsher tmp |= 0x2 << ENET_MIIDATA_TA_SHIFT; 169adfc5217SJeff Kirsher tmp |= mii_id << ENET_MIIDATA_PHYID_SHIFT; 170adfc5217SJeff Kirsher tmp |= ENET_MIIDATA_OP_READ_MASK; 171adfc5217SJeff Kirsher 172adfc5217SJeff Kirsher if (do_mdio_op(priv, tmp)) 173adfc5217SJeff Kirsher return -1; 174adfc5217SJeff Kirsher 175adfc5217SJeff Kirsher val = enet_readl(priv, ENET_MIIDATA_REG); 176adfc5217SJeff Kirsher val &= 0xffff; 177adfc5217SJeff Kirsher return val; 178adfc5217SJeff Kirsher } 179adfc5217SJeff Kirsher 180adfc5217SJeff Kirsher /* 181adfc5217SJeff Kirsher * MII internal write callback 182adfc5217SJeff Kirsher */ 183adfc5217SJeff Kirsher static int bcm_enet_mdio_write(struct bcm_enet_priv *priv, int mii_id, 184adfc5217SJeff Kirsher int regnum, u16 value) 185adfc5217SJeff Kirsher { 186adfc5217SJeff Kirsher u32 tmp; 187adfc5217SJeff Kirsher 188adfc5217SJeff Kirsher tmp = (value & 0xffff) << ENET_MIIDATA_DATA_SHIFT; 189adfc5217SJeff Kirsher tmp |= 0x2 << ENET_MIIDATA_TA_SHIFT; 190adfc5217SJeff Kirsher tmp |= regnum << ENET_MIIDATA_REG_SHIFT; 191adfc5217SJeff Kirsher tmp |= mii_id << ENET_MIIDATA_PHYID_SHIFT; 192adfc5217SJeff Kirsher tmp |= ENET_MIIDATA_OP_WRITE_MASK; 193adfc5217SJeff Kirsher 194adfc5217SJeff Kirsher (void)do_mdio_op(priv, tmp); 195adfc5217SJeff Kirsher return 0; 196adfc5217SJeff Kirsher } 197adfc5217SJeff Kirsher 198adfc5217SJeff Kirsher /* 199adfc5217SJeff Kirsher * MII read callback from phylib 200adfc5217SJeff Kirsher */ 201adfc5217SJeff Kirsher static int bcm_enet_mdio_read_phylib(struct mii_bus *bus, int mii_id, 202adfc5217SJeff Kirsher int regnum) 203adfc5217SJeff Kirsher { 204adfc5217SJeff Kirsher return bcm_enet_mdio_read(bus->priv, mii_id, regnum); 205adfc5217SJeff Kirsher } 206adfc5217SJeff Kirsher 207adfc5217SJeff Kirsher /* 208adfc5217SJeff Kirsher * MII write callback from phylib 209adfc5217SJeff Kirsher */ 210adfc5217SJeff Kirsher static int bcm_enet_mdio_write_phylib(struct mii_bus *bus, int mii_id, 211adfc5217SJeff Kirsher int regnum, u16 value) 212adfc5217SJeff Kirsher { 213adfc5217SJeff Kirsher return bcm_enet_mdio_write(bus->priv, mii_id, regnum, value); 214adfc5217SJeff Kirsher } 215adfc5217SJeff Kirsher 216adfc5217SJeff Kirsher /* 217adfc5217SJeff Kirsher * MII read callback from mii core 218adfc5217SJeff Kirsher */ 219adfc5217SJeff Kirsher static int bcm_enet_mdio_read_mii(struct net_device *dev, int mii_id, 220adfc5217SJeff Kirsher int regnum) 221adfc5217SJeff Kirsher { 222adfc5217SJeff Kirsher return bcm_enet_mdio_read(netdev_priv(dev), mii_id, regnum); 223adfc5217SJeff Kirsher } 224adfc5217SJeff Kirsher 225adfc5217SJeff Kirsher /* 226adfc5217SJeff Kirsher * MII write callback from mii core 227adfc5217SJeff Kirsher */ 228adfc5217SJeff Kirsher static void bcm_enet_mdio_write_mii(struct net_device *dev, int mii_id, 229adfc5217SJeff Kirsher int regnum, int value) 230adfc5217SJeff Kirsher { 231adfc5217SJeff Kirsher bcm_enet_mdio_write(netdev_priv(dev), mii_id, regnum, value); 232adfc5217SJeff Kirsher } 233adfc5217SJeff Kirsher 234adfc5217SJeff Kirsher /* 235adfc5217SJeff Kirsher * refill rx queue 236adfc5217SJeff Kirsher */ 237adfc5217SJeff Kirsher static int bcm_enet_refill_rx(struct net_device *dev) 238adfc5217SJeff Kirsher { 239adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 240adfc5217SJeff Kirsher 241adfc5217SJeff Kirsher priv = netdev_priv(dev); 242adfc5217SJeff Kirsher 243adfc5217SJeff Kirsher while (priv->rx_desc_count < priv->rx_ring_size) { 244adfc5217SJeff Kirsher struct bcm_enet_desc *desc; 245adfc5217SJeff Kirsher struct sk_buff *skb; 246adfc5217SJeff Kirsher dma_addr_t p; 247adfc5217SJeff Kirsher int desc_idx; 248adfc5217SJeff Kirsher u32 len_stat; 249adfc5217SJeff Kirsher 250adfc5217SJeff Kirsher desc_idx = priv->rx_dirty_desc; 251adfc5217SJeff Kirsher desc = &priv->rx_desc_cpu[desc_idx]; 252adfc5217SJeff Kirsher 253adfc5217SJeff Kirsher if (!priv->rx_skb[desc_idx]) { 254adfc5217SJeff Kirsher skb = netdev_alloc_skb(dev, priv->rx_skb_size); 255adfc5217SJeff Kirsher if (!skb) 256adfc5217SJeff Kirsher break; 257adfc5217SJeff Kirsher priv->rx_skb[desc_idx] = skb; 258adfc5217SJeff Kirsher p = dma_map_single(&priv->pdev->dev, skb->data, 259adfc5217SJeff Kirsher priv->rx_skb_size, 260adfc5217SJeff Kirsher DMA_FROM_DEVICE); 261adfc5217SJeff Kirsher desc->address = p; 262adfc5217SJeff Kirsher } 263adfc5217SJeff Kirsher 264adfc5217SJeff Kirsher len_stat = priv->rx_skb_size << DMADESC_LENGTH_SHIFT; 265adfc5217SJeff Kirsher len_stat |= DMADESC_OWNER_MASK; 266adfc5217SJeff Kirsher if (priv->rx_dirty_desc == priv->rx_ring_size - 1) { 2673dc6475cSFlorian Fainelli len_stat |= (DMADESC_WRAP_MASK >> priv->dma_desc_shift); 268adfc5217SJeff Kirsher priv->rx_dirty_desc = 0; 269adfc5217SJeff Kirsher } else { 270adfc5217SJeff Kirsher priv->rx_dirty_desc++; 271adfc5217SJeff Kirsher } 272adfc5217SJeff Kirsher wmb(); 273adfc5217SJeff Kirsher desc->len_stat = len_stat; 274adfc5217SJeff Kirsher 275adfc5217SJeff Kirsher priv->rx_desc_count++; 276adfc5217SJeff Kirsher 277adfc5217SJeff Kirsher /* tell dma engine we allocated one buffer */ 2783dc6475cSFlorian Fainelli if (priv->dma_has_sram) 279adfc5217SJeff Kirsher enet_dma_writel(priv, 1, ENETDMA_BUFALLOC_REG(priv->rx_chan)); 2803dc6475cSFlorian Fainelli else 2813dc6475cSFlorian Fainelli enet_dmac_writel(priv, 1, ENETDMAC_BUFALLOC, priv->rx_chan); 282adfc5217SJeff Kirsher } 283adfc5217SJeff Kirsher 284adfc5217SJeff Kirsher /* If rx ring is still empty, set a timer to try allocating 285adfc5217SJeff Kirsher * again at a later time. */ 286adfc5217SJeff Kirsher if (priv->rx_desc_count == 0 && netif_running(dev)) { 287adfc5217SJeff Kirsher dev_warn(&priv->pdev->dev, "unable to refill rx ring\n"); 288adfc5217SJeff Kirsher priv->rx_timeout.expires = jiffies + HZ; 289adfc5217SJeff Kirsher add_timer(&priv->rx_timeout); 290adfc5217SJeff Kirsher } 291adfc5217SJeff Kirsher 292adfc5217SJeff Kirsher return 0; 293adfc5217SJeff Kirsher } 294adfc5217SJeff Kirsher 295adfc5217SJeff Kirsher /* 296adfc5217SJeff Kirsher * timer callback to defer refill rx queue in case we're OOM 297adfc5217SJeff Kirsher */ 298adfc5217SJeff Kirsher static void bcm_enet_refill_rx_timer(unsigned long data) 299adfc5217SJeff Kirsher { 300adfc5217SJeff Kirsher struct net_device *dev; 301adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 302adfc5217SJeff Kirsher 303adfc5217SJeff Kirsher dev = (struct net_device *)data; 304adfc5217SJeff Kirsher priv = netdev_priv(dev); 305adfc5217SJeff Kirsher 306adfc5217SJeff Kirsher spin_lock(&priv->rx_lock); 307adfc5217SJeff Kirsher bcm_enet_refill_rx((struct net_device *)data); 308adfc5217SJeff Kirsher spin_unlock(&priv->rx_lock); 309adfc5217SJeff Kirsher } 310adfc5217SJeff Kirsher 311adfc5217SJeff Kirsher /* 312adfc5217SJeff Kirsher * extract packet from rx queue 313adfc5217SJeff Kirsher */ 314adfc5217SJeff Kirsher static int bcm_enet_receive_queue(struct net_device *dev, int budget) 315adfc5217SJeff Kirsher { 316adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 317adfc5217SJeff Kirsher struct device *kdev; 318adfc5217SJeff Kirsher int processed; 319adfc5217SJeff Kirsher 320adfc5217SJeff Kirsher priv = netdev_priv(dev); 321adfc5217SJeff Kirsher kdev = &priv->pdev->dev; 322adfc5217SJeff Kirsher processed = 0; 323adfc5217SJeff Kirsher 324adfc5217SJeff Kirsher /* don't scan ring further than number of refilled 325adfc5217SJeff Kirsher * descriptor */ 326adfc5217SJeff Kirsher if (budget > priv->rx_desc_count) 327adfc5217SJeff Kirsher budget = priv->rx_desc_count; 328adfc5217SJeff Kirsher 329adfc5217SJeff Kirsher do { 330adfc5217SJeff Kirsher struct bcm_enet_desc *desc; 331adfc5217SJeff Kirsher struct sk_buff *skb; 332adfc5217SJeff Kirsher int desc_idx; 333adfc5217SJeff Kirsher u32 len_stat; 334adfc5217SJeff Kirsher unsigned int len; 335adfc5217SJeff Kirsher 336adfc5217SJeff Kirsher desc_idx = priv->rx_curr_desc; 337adfc5217SJeff Kirsher desc = &priv->rx_desc_cpu[desc_idx]; 338adfc5217SJeff Kirsher 339adfc5217SJeff Kirsher /* make sure we actually read the descriptor status at 340adfc5217SJeff Kirsher * each loop */ 341adfc5217SJeff Kirsher rmb(); 342adfc5217SJeff Kirsher 343adfc5217SJeff Kirsher len_stat = desc->len_stat; 344adfc5217SJeff Kirsher 345adfc5217SJeff Kirsher /* break if dma ownership belongs to hw */ 346adfc5217SJeff Kirsher if (len_stat & DMADESC_OWNER_MASK) 347adfc5217SJeff Kirsher break; 348adfc5217SJeff Kirsher 349adfc5217SJeff Kirsher processed++; 350adfc5217SJeff Kirsher priv->rx_curr_desc++; 351adfc5217SJeff Kirsher if (priv->rx_curr_desc == priv->rx_ring_size) 352adfc5217SJeff Kirsher priv->rx_curr_desc = 0; 353adfc5217SJeff Kirsher priv->rx_desc_count--; 354adfc5217SJeff Kirsher 355adfc5217SJeff Kirsher /* if the packet does not have start of packet _and_ 356adfc5217SJeff Kirsher * end of packet flag set, then just recycle it */ 3573dc6475cSFlorian Fainelli if ((len_stat & (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) != 3583dc6475cSFlorian Fainelli (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) { 359adfc5217SJeff Kirsher dev->stats.rx_dropped++; 360adfc5217SJeff Kirsher continue; 361adfc5217SJeff Kirsher } 362adfc5217SJeff Kirsher 363adfc5217SJeff Kirsher /* recycle packet if it's marked as bad */ 3646f00a022SMaxime Bizon if (!priv->enet_is_sw && 3656f00a022SMaxime Bizon unlikely(len_stat & DMADESC_ERR_MASK)) { 366adfc5217SJeff Kirsher dev->stats.rx_errors++; 367adfc5217SJeff Kirsher 368adfc5217SJeff Kirsher if (len_stat & DMADESC_OVSIZE_MASK) 369adfc5217SJeff Kirsher dev->stats.rx_length_errors++; 370adfc5217SJeff Kirsher if (len_stat & DMADESC_CRC_MASK) 371adfc5217SJeff Kirsher dev->stats.rx_crc_errors++; 372adfc5217SJeff Kirsher if (len_stat & DMADESC_UNDER_MASK) 373adfc5217SJeff Kirsher dev->stats.rx_frame_errors++; 374adfc5217SJeff Kirsher if (len_stat & DMADESC_OV_MASK) 375adfc5217SJeff Kirsher dev->stats.rx_fifo_errors++; 376adfc5217SJeff Kirsher continue; 377adfc5217SJeff Kirsher } 378adfc5217SJeff Kirsher 379adfc5217SJeff Kirsher /* valid packet */ 380adfc5217SJeff Kirsher skb = priv->rx_skb[desc_idx]; 381adfc5217SJeff Kirsher len = (len_stat & DMADESC_LENGTH_MASK) >> DMADESC_LENGTH_SHIFT; 382adfc5217SJeff Kirsher /* don't include FCS */ 383adfc5217SJeff Kirsher len -= 4; 384adfc5217SJeff Kirsher 385adfc5217SJeff Kirsher if (len < copybreak) { 386adfc5217SJeff Kirsher struct sk_buff *nskb; 387adfc5217SJeff Kirsher 38845abfb10SAlexander Duyck nskb = napi_alloc_skb(&priv->napi, len); 389adfc5217SJeff Kirsher if (!nskb) { 390adfc5217SJeff Kirsher /* forget packet, just rearm desc */ 391adfc5217SJeff Kirsher dev->stats.rx_dropped++; 392adfc5217SJeff Kirsher continue; 393adfc5217SJeff Kirsher } 394adfc5217SJeff Kirsher 395adfc5217SJeff Kirsher dma_sync_single_for_cpu(kdev, desc->address, 396adfc5217SJeff Kirsher len, DMA_FROM_DEVICE); 397adfc5217SJeff Kirsher memcpy(nskb->data, skb->data, len); 398adfc5217SJeff Kirsher dma_sync_single_for_device(kdev, desc->address, 399adfc5217SJeff Kirsher len, DMA_FROM_DEVICE); 400adfc5217SJeff Kirsher skb = nskb; 401adfc5217SJeff Kirsher } else { 402adfc5217SJeff Kirsher dma_unmap_single(&priv->pdev->dev, desc->address, 403adfc5217SJeff Kirsher priv->rx_skb_size, DMA_FROM_DEVICE); 404adfc5217SJeff Kirsher priv->rx_skb[desc_idx] = NULL; 405adfc5217SJeff Kirsher } 406adfc5217SJeff Kirsher 407adfc5217SJeff Kirsher skb_put(skb, len); 408adfc5217SJeff Kirsher skb->protocol = eth_type_trans(skb, dev); 409adfc5217SJeff Kirsher dev->stats.rx_packets++; 410adfc5217SJeff Kirsher dev->stats.rx_bytes += len; 411adfc5217SJeff Kirsher netif_receive_skb(skb); 412adfc5217SJeff Kirsher 413adfc5217SJeff Kirsher } while (--budget > 0); 414adfc5217SJeff Kirsher 415adfc5217SJeff Kirsher if (processed || !priv->rx_desc_count) { 416adfc5217SJeff Kirsher bcm_enet_refill_rx(dev); 417adfc5217SJeff Kirsher 418adfc5217SJeff Kirsher /* kick rx dma */ 4193dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_en_mask, 4203dc6475cSFlorian Fainelli ENETDMAC_CHANCFG, priv->rx_chan); 421adfc5217SJeff Kirsher } 422adfc5217SJeff Kirsher 423adfc5217SJeff Kirsher return processed; 424adfc5217SJeff Kirsher } 425adfc5217SJeff Kirsher 426adfc5217SJeff Kirsher 427adfc5217SJeff Kirsher /* 428adfc5217SJeff Kirsher * try to or force reclaim of transmitted buffers 429adfc5217SJeff Kirsher */ 430adfc5217SJeff Kirsher static int bcm_enet_tx_reclaim(struct net_device *dev, int force) 431adfc5217SJeff Kirsher { 432adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 433adfc5217SJeff Kirsher int released; 434adfc5217SJeff Kirsher 435adfc5217SJeff Kirsher priv = netdev_priv(dev); 436adfc5217SJeff Kirsher released = 0; 437adfc5217SJeff Kirsher 438adfc5217SJeff Kirsher while (priv->tx_desc_count < priv->tx_ring_size) { 439adfc5217SJeff Kirsher struct bcm_enet_desc *desc; 440adfc5217SJeff Kirsher struct sk_buff *skb; 441adfc5217SJeff Kirsher 442adfc5217SJeff Kirsher /* We run in a bh and fight against start_xmit, which 443adfc5217SJeff Kirsher * is called with bh disabled */ 444adfc5217SJeff Kirsher spin_lock(&priv->tx_lock); 445adfc5217SJeff Kirsher 446adfc5217SJeff Kirsher desc = &priv->tx_desc_cpu[priv->tx_dirty_desc]; 447adfc5217SJeff Kirsher 448adfc5217SJeff Kirsher if (!force && (desc->len_stat & DMADESC_OWNER_MASK)) { 449adfc5217SJeff Kirsher spin_unlock(&priv->tx_lock); 450adfc5217SJeff Kirsher break; 451adfc5217SJeff Kirsher } 452adfc5217SJeff Kirsher 453adfc5217SJeff Kirsher /* ensure other field of the descriptor were not read 454adfc5217SJeff Kirsher * before we checked ownership */ 455adfc5217SJeff Kirsher rmb(); 456adfc5217SJeff Kirsher 457adfc5217SJeff Kirsher skb = priv->tx_skb[priv->tx_dirty_desc]; 458adfc5217SJeff Kirsher priv->tx_skb[priv->tx_dirty_desc] = NULL; 459adfc5217SJeff Kirsher dma_unmap_single(&priv->pdev->dev, desc->address, skb->len, 460adfc5217SJeff Kirsher DMA_TO_DEVICE); 461adfc5217SJeff Kirsher 462adfc5217SJeff Kirsher priv->tx_dirty_desc++; 463adfc5217SJeff Kirsher if (priv->tx_dirty_desc == priv->tx_ring_size) 464adfc5217SJeff Kirsher priv->tx_dirty_desc = 0; 465adfc5217SJeff Kirsher priv->tx_desc_count++; 466adfc5217SJeff Kirsher 467adfc5217SJeff Kirsher spin_unlock(&priv->tx_lock); 468adfc5217SJeff Kirsher 469adfc5217SJeff Kirsher if (desc->len_stat & DMADESC_UNDER_MASK) 470adfc5217SJeff Kirsher dev->stats.tx_errors++; 471adfc5217SJeff Kirsher 472adfc5217SJeff Kirsher dev_kfree_skb(skb); 473adfc5217SJeff Kirsher released++; 474adfc5217SJeff Kirsher } 475adfc5217SJeff Kirsher 476adfc5217SJeff Kirsher if (netif_queue_stopped(dev) && released) 477adfc5217SJeff Kirsher netif_wake_queue(dev); 478adfc5217SJeff Kirsher 479adfc5217SJeff Kirsher return released; 480adfc5217SJeff Kirsher } 481adfc5217SJeff Kirsher 482adfc5217SJeff Kirsher /* 483adfc5217SJeff Kirsher * poll func, called by network core 484adfc5217SJeff Kirsher */ 485adfc5217SJeff Kirsher static int bcm_enet_poll(struct napi_struct *napi, int budget) 486adfc5217SJeff Kirsher { 487adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 488adfc5217SJeff Kirsher struct net_device *dev; 489cd33ccf5SNicolas Schichan int rx_work_done; 490adfc5217SJeff Kirsher 491adfc5217SJeff Kirsher priv = container_of(napi, struct bcm_enet_priv, napi); 492adfc5217SJeff Kirsher dev = priv->net_dev; 493adfc5217SJeff Kirsher 494adfc5217SJeff Kirsher /* ack interrupts */ 4953dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 4963dc6475cSFlorian Fainelli ENETDMAC_IR, priv->rx_chan); 4973dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 4983dc6475cSFlorian Fainelli ENETDMAC_IR, priv->tx_chan); 499adfc5217SJeff Kirsher 500adfc5217SJeff Kirsher /* reclaim sent skb */ 501cd33ccf5SNicolas Schichan bcm_enet_tx_reclaim(dev, 0); 502adfc5217SJeff Kirsher 503adfc5217SJeff Kirsher spin_lock(&priv->rx_lock); 504adfc5217SJeff Kirsher rx_work_done = bcm_enet_receive_queue(dev, budget); 505adfc5217SJeff Kirsher spin_unlock(&priv->rx_lock); 506adfc5217SJeff Kirsher 507cd33ccf5SNicolas Schichan if (rx_work_done >= budget) { 508cd33ccf5SNicolas Schichan /* rx queue is not yet empty/clean */ 509adfc5217SJeff Kirsher return rx_work_done; 510adfc5217SJeff Kirsher } 511adfc5217SJeff Kirsher 512adfc5217SJeff Kirsher /* no more packet in rx/tx queue, remove device from poll 513adfc5217SJeff Kirsher * queue */ 5146ad20165SEric Dumazet napi_complete_done(napi, rx_work_done); 515adfc5217SJeff Kirsher 516adfc5217SJeff Kirsher /* restore rx/tx interrupt */ 5173dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 5183dc6475cSFlorian Fainelli ENETDMAC_IRMASK, priv->rx_chan); 5193dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 5203dc6475cSFlorian Fainelli ENETDMAC_IRMASK, priv->tx_chan); 521adfc5217SJeff Kirsher 522adfc5217SJeff Kirsher return rx_work_done; 523adfc5217SJeff Kirsher } 524adfc5217SJeff Kirsher 525adfc5217SJeff Kirsher /* 526adfc5217SJeff Kirsher * mac interrupt handler 527adfc5217SJeff Kirsher */ 528adfc5217SJeff Kirsher static irqreturn_t bcm_enet_isr_mac(int irq, void *dev_id) 529adfc5217SJeff Kirsher { 530adfc5217SJeff Kirsher struct net_device *dev; 531adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 532adfc5217SJeff Kirsher u32 stat; 533adfc5217SJeff Kirsher 534adfc5217SJeff Kirsher dev = dev_id; 535adfc5217SJeff Kirsher priv = netdev_priv(dev); 536adfc5217SJeff Kirsher 537adfc5217SJeff Kirsher stat = enet_readl(priv, ENET_IR_REG); 538adfc5217SJeff Kirsher if (!(stat & ENET_IR_MIB)) 539adfc5217SJeff Kirsher return IRQ_NONE; 540adfc5217SJeff Kirsher 541adfc5217SJeff Kirsher /* clear & mask interrupt */ 542adfc5217SJeff Kirsher enet_writel(priv, ENET_IR_MIB, ENET_IR_REG); 543adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_IRMASK_REG); 544adfc5217SJeff Kirsher 545adfc5217SJeff Kirsher /* read mib registers in workqueue */ 546adfc5217SJeff Kirsher schedule_work(&priv->mib_update_task); 547adfc5217SJeff Kirsher 548adfc5217SJeff Kirsher return IRQ_HANDLED; 549adfc5217SJeff Kirsher } 550adfc5217SJeff Kirsher 551adfc5217SJeff Kirsher /* 552adfc5217SJeff Kirsher * rx/tx dma interrupt handler 553adfc5217SJeff Kirsher */ 554adfc5217SJeff Kirsher static irqreturn_t bcm_enet_isr_dma(int irq, void *dev_id) 555adfc5217SJeff Kirsher { 556adfc5217SJeff Kirsher struct net_device *dev; 557adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 558adfc5217SJeff Kirsher 559adfc5217SJeff Kirsher dev = dev_id; 560adfc5217SJeff Kirsher priv = netdev_priv(dev); 561adfc5217SJeff Kirsher 562adfc5217SJeff Kirsher /* mask rx/tx interrupts */ 5633dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan); 5643dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan); 565adfc5217SJeff Kirsher 566adfc5217SJeff Kirsher napi_schedule(&priv->napi); 567adfc5217SJeff Kirsher 568adfc5217SJeff Kirsher return IRQ_HANDLED; 569adfc5217SJeff Kirsher } 570adfc5217SJeff Kirsher 571adfc5217SJeff Kirsher /* 572adfc5217SJeff Kirsher * tx request callback 573adfc5217SJeff Kirsher */ 574adfc5217SJeff Kirsher static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) 575adfc5217SJeff Kirsher { 576adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 577adfc5217SJeff Kirsher struct bcm_enet_desc *desc; 578adfc5217SJeff Kirsher u32 len_stat; 579adfc5217SJeff Kirsher int ret; 580adfc5217SJeff Kirsher 581adfc5217SJeff Kirsher priv = netdev_priv(dev); 582adfc5217SJeff Kirsher 583adfc5217SJeff Kirsher /* lock against tx reclaim */ 584adfc5217SJeff Kirsher spin_lock(&priv->tx_lock); 585adfc5217SJeff Kirsher 586adfc5217SJeff Kirsher /* make sure the tx hw queue is not full, should not happen 587adfc5217SJeff Kirsher * since we stop queue before it's the case */ 588adfc5217SJeff Kirsher if (unlikely(!priv->tx_desc_count)) { 589adfc5217SJeff Kirsher netif_stop_queue(dev); 590adfc5217SJeff Kirsher dev_err(&priv->pdev->dev, "xmit called with no tx desc " 591adfc5217SJeff Kirsher "available?\n"); 592adfc5217SJeff Kirsher ret = NETDEV_TX_BUSY; 593adfc5217SJeff Kirsher goto out_unlock; 594adfc5217SJeff Kirsher } 595adfc5217SJeff Kirsher 5966f00a022SMaxime Bizon /* pad small packets sent on a switch device */ 5976f00a022SMaxime Bizon if (priv->enet_is_sw && skb->len < 64) { 5986f00a022SMaxime Bizon int needed = 64 - skb->len; 5996f00a022SMaxime Bizon char *data; 6006f00a022SMaxime Bizon 6016f00a022SMaxime Bizon if (unlikely(skb_tailroom(skb) < needed)) { 6026f00a022SMaxime Bizon struct sk_buff *nskb; 6036f00a022SMaxime Bizon 6046f00a022SMaxime Bizon nskb = skb_copy_expand(skb, 0, needed, GFP_ATOMIC); 6056f00a022SMaxime Bizon if (!nskb) { 6066f00a022SMaxime Bizon ret = NETDEV_TX_BUSY; 6076f00a022SMaxime Bizon goto out_unlock; 6086f00a022SMaxime Bizon } 6096f00a022SMaxime Bizon dev_kfree_skb(skb); 6106f00a022SMaxime Bizon skb = nskb; 6116f00a022SMaxime Bizon } 612aa9f979cSJohannes Berg data = skb_put_zero(skb, needed); 6136f00a022SMaxime Bizon } 6146f00a022SMaxime Bizon 615adfc5217SJeff Kirsher /* point to the next available desc */ 616adfc5217SJeff Kirsher desc = &priv->tx_desc_cpu[priv->tx_curr_desc]; 617adfc5217SJeff Kirsher priv->tx_skb[priv->tx_curr_desc] = skb; 618adfc5217SJeff Kirsher 619adfc5217SJeff Kirsher /* fill descriptor */ 620adfc5217SJeff Kirsher desc->address = dma_map_single(&priv->pdev->dev, skb->data, skb->len, 621adfc5217SJeff Kirsher DMA_TO_DEVICE); 622adfc5217SJeff Kirsher 623adfc5217SJeff Kirsher len_stat = (skb->len << DMADESC_LENGTH_SHIFT) & DMADESC_LENGTH_MASK; 6243dc6475cSFlorian Fainelli len_stat |= (DMADESC_ESOP_MASK >> priv->dma_desc_shift) | 625adfc5217SJeff Kirsher DMADESC_APPEND_CRC | 626adfc5217SJeff Kirsher DMADESC_OWNER_MASK; 627adfc5217SJeff Kirsher 628adfc5217SJeff Kirsher priv->tx_curr_desc++; 629adfc5217SJeff Kirsher if (priv->tx_curr_desc == priv->tx_ring_size) { 630adfc5217SJeff Kirsher priv->tx_curr_desc = 0; 6313dc6475cSFlorian Fainelli len_stat |= (DMADESC_WRAP_MASK >> priv->dma_desc_shift); 632adfc5217SJeff Kirsher } 633adfc5217SJeff Kirsher priv->tx_desc_count--; 634adfc5217SJeff Kirsher 635adfc5217SJeff Kirsher /* dma might be already polling, make sure we update desc 636adfc5217SJeff Kirsher * fields in correct order */ 637adfc5217SJeff Kirsher wmb(); 638adfc5217SJeff Kirsher desc->len_stat = len_stat; 639adfc5217SJeff Kirsher wmb(); 640adfc5217SJeff Kirsher 641adfc5217SJeff Kirsher /* kick tx dma */ 6423dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_en_mask, 6433dc6475cSFlorian Fainelli ENETDMAC_CHANCFG, priv->tx_chan); 644adfc5217SJeff Kirsher 645adfc5217SJeff Kirsher /* stop queue if no more desc available */ 646adfc5217SJeff Kirsher if (!priv->tx_desc_count) 647adfc5217SJeff Kirsher netif_stop_queue(dev); 648adfc5217SJeff Kirsher 649adfc5217SJeff Kirsher dev->stats.tx_bytes += skb->len; 650adfc5217SJeff Kirsher dev->stats.tx_packets++; 651adfc5217SJeff Kirsher ret = NETDEV_TX_OK; 652adfc5217SJeff Kirsher 653adfc5217SJeff Kirsher out_unlock: 654adfc5217SJeff Kirsher spin_unlock(&priv->tx_lock); 655adfc5217SJeff Kirsher return ret; 656adfc5217SJeff Kirsher } 657adfc5217SJeff Kirsher 658adfc5217SJeff Kirsher /* 659adfc5217SJeff Kirsher * Change the interface's mac address. 660adfc5217SJeff Kirsher */ 661adfc5217SJeff Kirsher static int bcm_enet_set_mac_address(struct net_device *dev, void *p) 662adfc5217SJeff Kirsher { 663adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 664adfc5217SJeff Kirsher struct sockaddr *addr = p; 665adfc5217SJeff Kirsher u32 val; 666adfc5217SJeff Kirsher 667adfc5217SJeff Kirsher priv = netdev_priv(dev); 668adfc5217SJeff Kirsher memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); 669adfc5217SJeff Kirsher 670adfc5217SJeff Kirsher /* use perfect match register 0 to store my mac address */ 671adfc5217SJeff Kirsher val = (dev->dev_addr[2] << 24) | (dev->dev_addr[3] << 16) | 672adfc5217SJeff Kirsher (dev->dev_addr[4] << 8) | dev->dev_addr[5]; 673adfc5217SJeff Kirsher enet_writel(priv, val, ENET_PML_REG(0)); 674adfc5217SJeff Kirsher 675adfc5217SJeff Kirsher val = (dev->dev_addr[0] << 8 | dev->dev_addr[1]); 676adfc5217SJeff Kirsher val |= ENET_PMH_DATAVALID_MASK; 677adfc5217SJeff Kirsher enet_writel(priv, val, ENET_PMH_REG(0)); 678adfc5217SJeff Kirsher 679adfc5217SJeff Kirsher return 0; 680adfc5217SJeff Kirsher } 681adfc5217SJeff Kirsher 682adfc5217SJeff Kirsher /* 683adfc5217SJeff Kirsher * Change rx mode (promiscuous/allmulti) and update multicast list 684adfc5217SJeff Kirsher */ 685adfc5217SJeff Kirsher static void bcm_enet_set_multicast_list(struct net_device *dev) 686adfc5217SJeff Kirsher { 687adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 688adfc5217SJeff Kirsher struct netdev_hw_addr *ha; 689adfc5217SJeff Kirsher u32 val; 690adfc5217SJeff Kirsher int i; 691adfc5217SJeff Kirsher 692adfc5217SJeff Kirsher priv = netdev_priv(dev); 693adfc5217SJeff Kirsher 694adfc5217SJeff Kirsher val = enet_readl(priv, ENET_RXCFG_REG); 695adfc5217SJeff Kirsher 696adfc5217SJeff Kirsher if (dev->flags & IFF_PROMISC) 697adfc5217SJeff Kirsher val |= ENET_RXCFG_PROMISC_MASK; 698adfc5217SJeff Kirsher else 699adfc5217SJeff Kirsher val &= ~ENET_RXCFG_PROMISC_MASK; 700adfc5217SJeff Kirsher 701adfc5217SJeff Kirsher /* only 3 perfect match registers left, first one is used for 702adfc5217SJeff Kirsher * own mac address */ 703adfc5217SJeff Kirsher if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > 3) 704adfc5217SJeff Kirsher val |= ENET_RXCFG_ALLMCAST_MASK; 705adfc5217SJeff Kirsher else 706adfc5217SJeff Kirsher val &= ~ENET_RXCFG_ALLMCAST_MASK; 707adfc5217SJeff Kirsher 708adfc5217SJeff Kirsher /* no need to set perfect match registers if we catch all 709adfc5217SJeff Kirsher * multicast */ 710adfc5217SJeff Kirsher if (val & ENET_RXCFG_ALLMCAST_MASK) { 711adfc5217SJeff Kirsher enet_writel(priv, val, ENET_RXCFG_REG); 712adfc5217SJeff Kirsher return; 713adfc5217SJeff Kirsher } 714adfc5217SJeff Kirsher 715adfc5217SJeff Kirsher i = 0; 716adfc5217SJeff Kirsher netdev_for_each_mc_addr(ha, dev) { 717adfc5217SJeff Kirsher u8 *dmi_addr; 718adfc5217SJeff Kirsher u32 tmp; 719adfc5217SJeff Kirsher 720adfc5217SJeff Kirsher if (i == 3) 721adfc5217SJeff Kirsher break; 722adfc5217SJeff Kirsher /* update perfect match registers */ 723adfc5217SJeff Kirsher dmi_addr = ha->addr; 724adfc5217SJeff Kirsher tmp = (dmi_addr[2] << 24) | (dmi_addr[3] << 16) | 725adfc5217SJeff Kirsher (dmi_addr[4] << 8) | dmi_addr[5]; 726adfc5217SJeff Kirsher enet_writel(priv, tmp, ENET_PML_REG(i + 1)); 727adfc5217SJeff Kirsher 728adfc5217SJeff Kirsher tmp = (dmi_addr[0] << 8 | dmi_addr[1]); 729adfc5217SJeff Kirsher tmp |= ENET_PMH_DATAVALID_MASK; 730adfc5217SJeff Kirsher enet_writel(priv, tmp, ENET_PMH_REG(i++ + 1)); 731adfc5217SJeff Kirsher } 732adfc5217SJeff Kirsher 733adfc5217SJeff Kirsher for (; i < 3; i++) { 734adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_PML_REG(i + 1)); 735adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_PMH_REG(i + 1)); 736adfc5217SJeff Kirsher } 737adfc5217SJeff Kirsher 738adfc5217SJeff Kirsher enet_writel(priv, val, ENET_RXCFG_REG); 739adfc5217SJeff Kirsher } 740adfc5217SJeff Kirsher 741adfc5217SJeff Kirsher /* 742adfc5217SJeff Kirsher * set mac duplex parameters 743adfc5217SJeff Kirsher */ 744adfc5217SJeff Kirsher static void bcm_enet_set_duplex(struct bcm_enet_priv *priv, int fullduplex) 745adfc5217SJeff Kirsher { 746adfc5217SJeff Kirsher u32 val; 747adfc5217SJeff Kirsher 748adfc5217SJeff Kirsher val = enet_readl(priv, ENET_TXCTL_REG); 749adfc5217SJeff Kirsher if (fullduplex) 750adfc5217SJeff Kirsher val |= ENET_TXCTL_FD_MASK; 751adfc5217SJeff Kirsher else 752adfc5217SJeff Kirsher val &= ~ENET_TXCTL_FD_MASK; 753adfc5217SJeff Kirsher enet_writel(priv, val, ENET_TXCTL_REG); 754adfc5217SJeff Kirsher } 755adfc5217SJeff Kirsher 756adfc5217SJeff Kirsher /* 757adfc5217SJeff Kirsher * set mac flow control parameters 758adfc5217SJeff Kirsher */ 759adfc5217SJeff Kirsher static void bcm_enet_set_flow(struct bcm_enet_priv *priv, int rx_en, int tx_en) 760adfc5217SJeff Kirsher { 761adfc5217SJeff Kirsher u32 val; 762adfc5217SJeff Kirsher 763adfc5217SJeff Kirsher /* rx flow control (pause frame handling) */ 764adfc5217SJeff Kirsher val = enet_readl(priv, ENET_RXCFG_REG); 765adfc5217SJeff Kirsher if (rx_en) 766adfc5217SJeff Kirsher val |= ENET_RXCFG_ENFLOW_MASK; 767adfc5217SJeff Kirsher else 768adfc5217SJeff Kirsher val &= ~ENET_RXCFG_ENFLOW_MASK; 769adfc5217SJeff Kirsher enet_writel(priv, val, ENET_RXCFG_REG); 770adfc5217SJeff Kirsher 7713dc6475cSFlorian Fainelli if (!priv->dma_has_sram) 7723dc6475cSFlorian Fainelli return; 7733dc6475cSFlorian Fainelli 774adfc5217SJeff Kirsher /* tx flow control (pause frame generation) */ 775adfc5217SJeff Kirsher val = enet_dma_readl(priv, ENETDMA_CFG_REG); 776adfc5217SJeff Kirsher if (tx_en) 777adfc5217SJeff Kirsher val |= ENETDMA_CFG_FLOWCH_MASK(priv->rx_chan); 778adfc5217SJeff Kirsher else 779adfc5217SJeff Kirsher val &= ~ENETDMA_CFG_FLOWCH_MASK(priv->rx_chan); 780adfc5217SJeff Kirsher enet_dma_writel(priv, val, ENETDMA_CFG_REG); 781adfc5217SJeff Kirsher } 782adfc5217SJeff Kirsher 783adfc5217SJeff Kirsher /* 784adfc5217SJeff Kirsher * link changed callback (from phylib) 785adfc5217SJeff Kirsher */ 786adfc5217SJeff Kirsher static void bcm_enet_adjust_phy_link(struct net_device *dev) 787adfc5217SJeff Kirsher { 788adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 789adfc5217SJeff Kirsher struct phy_device *phydev; 790adfc5217SJeff Kirsher int status_changed; 791adfc5217SJeff Kirsher 792adfc5217SJeff Kirsher priv = netdev_priv(dev); 793625eb866SPhilippe Reynes phydev = dev->phydev; 794adfc5217SJeff Kirsher status_changed = 0; 795adfc5217SJeff Kirsher 796adfc5217SJeff Kirsher if (priv->old_link != phydev->link) { 797adfc5217SJeff Kirsher status_changed = 1; 798adfc5217SJeff Kirsher priv->old_link = phydev->link; 799adfc5217SJeff Kirsher } 800adfc5217SJeff Kirsher 801adfc5217SJeff Kirsher /* reflect duplex change in mac configuration */ 802adfc5217SJeff Kirsher if (phydev->link && phydev->duplex != priv->old_duplex) { 803adfc5217SJeff Kirsher bcm_enet_set_duplex(priv, 804adfc5217SJeff Kirsher (phydev->duplex == DUPLEX_FULL) ? 1 : 0); 805adfc5217SJeff Kirsher status_changed = 1; 806adfc5217SJeff Kirsher priv->old_duplex = phydev->duplex; 807adfc5217SJeff Kirsher } 808adfc5217SJeff Kirsher 809adfc5217SJeff Kirsher /* enable flow control if remote advertise it (trust phylib to 810adfc5217SJeff Kirsher * check that duplex is full */ 811adfc5217SJeff Kirsher if (phydev->link && phydev->pause != priv->old_pause) { 812adfc5217SJeff Kirsher int rx_pause_en, tx_pause_en; 813adfc5217SJeff Kirsher 814adfc5217SJeff Kirsher if (phydev->pause) { 815adfc5217SJeff Kirsher /* pause was advertised by lpa and us */ 816adfc5217SJeff Kirsher rx_pause_en = 1; 817adfc5217SJeff Kirsher tx_pause_en = 1; 818adfc5217SJeff Kirsher } else if (!priv->pause_auto) { 81903671057SMasahiro Yamada /* pause setting overridden by user */ 820adfc5217SJeff Kirsher rx_pause_en = priv->pause_rx; 821adfc5217SJeff Kirsher tx_pause_en = priv->pause_tx; 822adfc5217SJeff Kirsher } else { 823adfc5217SJeff Kirsher rx_pause_en = 0; 824adfc5217SJeff Kirsher tx_pause_en = 0; 825adfc5217SJeff Kirsher } 826adfc5217SJeff Kirsher 827adfc5217SJeff Kirsher bcm_enet_set_flow(priv, rx_pause_en, tx_pause_en); 828adfc5217SJeff Kirsher status_changed = 1; 829adfc5217SJeff Kirsher priv->old_pause = phydev->pause; 830adfc5217SJeff Kirsher } 831adfc5217SJeff Kirsher 832adfc5217SJeff Kirsher if (status_changed) { 833adfc5217SJeff Kirsher pr_info("%s: link %s", dev->name, phydev->link ? 834adfc5217SJeff Kirsher "UP" : "DOWN"); 835adfc5217SJeff Kirsher if (phydev->link) 836adfc5217SJeff Kirsher pr_cont(" - %d/%s - flow control %s", phydev->speed, 837adfc5217SJeff Kirsher DUPLEX_FULL == phydev->duplex ? "full" : "half", 838adfc5217SJeff Kirsher phydev->pause == 1 ? "rx&tx" : "off"); 839adfc5217SJeff Kirsher 840adfc5217SJeff Kirsher pr_cont("\n"); 841adfc5217SJeff Kirsher } 842adfc5217SJeff Kirsher } 843adfc5217SJeff Kirsher 844adfc5217SJeff Kirsher /* 845adfc5217SJeff Kirsher * link changed callback (if phylib is not used) 846adfc5217SJeff Kirsher */ 847adfc5217SJeff Kirsher static void bcm_enet_adjust_link(struct net_device *dev) 848adfc5217SJeff Kirsher { 849adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 850adfc5217SJeff Kirsher 851adfc5217SJeff Kirsher priv = netdev_priv(dev); 852adfc5217SJeff Kirsher bcm_enet_set_duplex(priv, priv->force_duplex_full); 853adfc5217SJeff Kirsher bcm_enet_set_flow(priv, priv->pause_rx, priv->pause_tx); 854adfc5217SJeff Kirsher netif_carrier_on(dev); 855adfc5217SJeff Kirsher 856adfc5217SJeff Kirsher pr_info("%s: link forced UP - %d/%s - flow control %s/%s\n", 857adfc5217SJeff Kirsher dev->name, 858adfc5217SJeff Kirsher priv->force_speed_100 ? 100 : 10, 859adfc5217SJeff Kirsher priv->force_duplex_full ? "full" : "half", 860adfc5217SJeff Kirsher priv->pause_rx ? "rx" : "off", 861adfc5217SJeff Kirsher priv->pause_tx ? "tx" : "off"); 862adfc5217SJeff Kirsher } 863adfc5217SJeff Kirsher 864adfc5217SJeff Kirsher /* 865adfc5217SJeff Kirsher * open callback, allocate dma rings & buffers and start rx operation 866adfc5217SJeff Kirsher */ 867adfc5217SJeff Kirsher static int bcm_enet_open(struct net_device *dev) 868adfc5217SJeff Kirsher { 869adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 870adfc5217SJeff Kirsher struct sockaddr addr; 871adfc5217SJeff Kirsher struct device *kdev; 872adfc5217SJeff Kirsher struct phy_device *phydev; 873adfc5217SJeff Kirsher int i, ret; 874adfc5217SJeff Kirsher unsigned int size; 875adfc5217SJeff Kirsher char phy_id[MII_BUS_ID_SIZE + 3]; 876adfc5217SJeff Kirsher void *p; 877adfc5217SJeff Kirsher u32 val; 878adfc5217SJeff Kirsher 879adfc5217SJeff Kirsher priv = netdev_priv(dev); 880adfc5217SJeff Kirsher kdev = &priv->pdev->dev; 881adfc5217SJeff Kirsher 882adfc5217SJeff Kirsher if (priv->has_phy) { 883adfc5217SJeff Kirsher /* connect to PHY */ 884adfc5217SJeff Kirsher snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, 885c56e9e2aSFlorian Fainelli priv->mii_bus->id, priv->phy_id); 886adfc5217SJeff Kirsher 887f9a8f83bSFlorian Fainelli phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, 888adfc5217SJeff Kirsher PHY_INTERFACE_MODE_MII); 889adfc5217SJeff Kirsher 890adfc5217SJeff Kirsher if (IS_ERR(phydev)) { 891adfc5217SJeff Kirsher dev_err(kdev, "could not attach to PHY\n"); 892adfc5217SJeff Kirsher return PTR_ERR(phydev); 893adfc5217SJeff Kirsher } 894adfc5217SJeff Kirsher 895adfc5217SJeff Kirsher /* mask with MAC supported features */ 896adfc5217SJeff Kirsher phydev->supported &= (SUPPORTED_10baseT_Half | 897adfc5217SJeff Kirsher SUPPORTED_10baseT_Full | 898adfc5217SJeff Kirsher SUPPORTED_100baseT_Half | 899adfc5217SJeff Kirsher SUPPORTED_100baseT_Full | 900adfc5217SJeff Kirsher SUPPORTED_Autoneg | 901adfc5217SJeff Kirsher SUPPORTED_Pause | 902adfc5217SJeff Kirsher SUPPORTED_MII); 903adfc5217SJeff Kirsher phydev->advertising = phydev->supported; 904adfc5217SJeff Kirsher 905adfc5217SJeff Kirsher if (priv->pause_auto && priv->pause_rx && priv->pause_tx) 906adfc5217SJeff Kirsher phydev->advertising |= SUPPORTED_Pause; 907adfc5217SJeff Kirsher else 908adfc5217SJeff Kirsher phydev->advertising &= ~SUPPORTED_Pause; 909adfc5217SJeff Kirsher 9102220943aSAndrew Lunn phy_attached_info(phydev); 911adfc5217SJeff Kirsher 912adfc5217SJeff Kirsher priv->old_link = 0; 913adfc5217SJeff Kirsher priv->old_duplex = -1; 914adfc5217SJeff Kirsher priv->old_pause = -1; 915df384d43SArnd Bergmann } else { 916df384d43SArnd Bergmann phydev = NULL; 917adfc5217SJeff Kirsher } 918adfc5217SJeff Kirsher 919adfc5217SJeff Kirsher /* mask all interrupts and request them */ 920adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_IRMASK_REG); 9213dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan); 9223dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan); 923adfc5217SJeff Kirsher 924adfc5217SJeff Kirsher ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev); 925adfc5217SJeff Kirsher if (ret) 926adfc5217SJeff Kirsher goto out_phy_disconnect; 927adfc5217SJeff Kirsher 928df9f1b9fSMichael Opdenacker ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, 0, 929adfc5217SJeff Kirsher dev->name, dev); 930adfc5217SJeff Kirsher if (ret) 931adfc5217SJeff Kirsher goto out_freeirq; 932adfc5217SJeff Kirsher 933adfc5217SJeff Kirsher ret = request_irq(priv->irq_tx, bcm_enet_isr_dma, 934df9f1b9fSMichael Opdenacker 0, dev->name, dev); 935adfc5217SJeff Kirsher if (ret) 936adfc5217SJeff Kirsher goto out_freeirq_rx; 937adfc5217SJeff Kirsher 938adfc5217SJeff Kirsher /* initialize perfect match registers */ 939adfc5217SJeff Kirsher for (i = 0; i < 4; i++) { 940adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_PML_REG(i)); 941adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_PMH_REG(i)); 942adfc5217SJeff Kirsher } 943adfc5217SJeff Kirsher 944adfc5217SJeff Kirsher /* write device mac address */ 945adfc5217SJeff Kirsher memcpy(addr.sa_data, dev->dev_addr, ETH_ALEN); 946adfc5217SJeff Kirsher bcm_enet_set_mac_address(dev, &addr); 947adfc5217SJeff Kirsher 948adfc5217SJeff Kirsher /* allocate rx dma ring */ 949adfc5217SJeff Kirsher size = priv->rx_ring_size * sizeof(struct bcm_enet_desc); 950ede23fa8SJoe Perches p = dma_zalloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); 951adfc5217SJeff Kirsher if (!p) { 952adfc5217SJeff Kirsher ret = -ENOMEM; 953adfc5217SJeff Kirsher goto out_freeirq_tx; 954adfc5217SJeff Kirsher } 955adfc5217SJeff Kirsher 956adfc5217SJeff Kirsher priv->rx_desc_alloc_size = size; 957adfc5217SJeff Kirsher priv->rx_desc_cpu = p; 958adfc5217SJeff Kirsher 959adfc5217SJeff Kirsher /* allocate tx dma ring */ 960adfc5217SJeff Kirsher size = priv->tx_ring_size * sizeof(struct bcm_enet_desc); 961ede23fa8SJoe Perches p = dma_zalloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); 962adfc5217SJeff Kirsher if (!p) { 963adfc5217SJeff Kirsher ret = -ENOMEM; 964adfc5217SJeff Kirsher goto out_free_rx_ring; 965adfc5217SJeff Kirsher } 966adfc5217SJeff Kirsher 967adfc5217SJeff Kirsher priv->tx_desc_alloc_size = size; 968adfc5217SJeff Kirsher priv->tx_desc_cpu = p; 969adfc5217SJeff Kirsher 970b2adaca9SJoe Perches priv->tx_skb = kcalloc(priv->tx_ring_size, sizeof(struct sk_buff *), 971adfc5217SJeff Kirsher GFP_KERNEL); 972adfc5217SJeff Kirsher if (!priv->tx_skb) { 973adfc5217SJeff Kirsher ret = -ENOMEM; 974adfc5217SJeff Kirsher goto out_free_tx_ring; 975adfc5217SJeff Kirsher } 976adfc5217SJeff Kirsher 977adfc5217SJeff Kirsher priv->tx_desc_count = priv->tx_ring_size; 978adfc5217SJeff Kirsher priv->tx_dirty_desc = 0; 979adfc5217SJeff Kirsher priv->tx_curr_desc = 0; 980adfc5217SJeff Kirsher spin_lock_init(&priv->tx_lock); 981adfc5217SJeff Kirsher 982adfc5217SJeff Kirsher /* init & fill rx ring with skbs */ 983b2adaca9SJoe Perches priv->rx_skb = kcalloc(priv->rx_ring_size, sizeof(struct sk_buff *), 984adfc5217SJeff Kirsher GFP_KERNEL); 985adfc5217SJeff Kirsher if (!priv->rx_skb) { 986adfc5217SJeff Kirsher ret = -ENOMEM; 987adfc5217SJeff Kirsher goto out_free_tx_skb; 988adfc5217SJeff Kirsher } 989adfc5217SJeff Kirsher 990adfc5217SJeff Kirsher priv->rx_desc_count = 0; 991adfc5217SJeff Kirsher priv->rx_dirty_desc = 0; 992adfc5217SJeff Kirsher priv->rx_curr_desc = 0; 993adfc5217SJeff Kirsher 994adfc5217SJeff Kirsher /* initialize flow control buffer allocation */ 9953dc6475cSFlorian Fainelli if (priv->dma_has_sram) 996adfc5217SJeff Kirsher enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, 997adfc5217SJeff Kirsher ENETDMA_BUFALLOC_REG(priv->rx_chan)); 9983dc6475cSFlorian Fainelli else 9993dc6475cSFlorian Fainelli enet_dmac_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, 10003dc6475cSFlorian Fainelli ENETDMAC_BUFALLOC, priv->rx_chan); 1001adfc5217SJeff Kirsher 1002adfc5217SJeff Kirsher if (bcm_enet_refill_rx(dev)) { 1003adfc5217SJeff Kirsher dev_err(kdev, "cannot allocate rx skb queue\n"); 1004adfc5217SJeff Kirsher ret = -ENOMEM; 1005adfc5217SJeff Kirsher goto out; 1006adfc5217SJeff Kirsher } 1007adfc5217SJeff Kirsher 1008adfc5217SJeff Kirsher /* write rx & tx ring addresses */ 10093dc6475cSFlorian Fainelli if (priv->dma_has_sram) { 10100ae99b5fSMaxime Bizon enet_dmas_writel(priv, priv->rx_desc_dma, 10113dc6475cSFlorian Fainelli ENETDMAS_RSTART_REG, priv->rx_chan); 10120ae99b5fSMaxime Bizon enet_dmas_writel(priv, priv->tx_desc_dma, 10133dc6475cSFlorian Fainelli ENETDMAS_RSTART_REG, priv->tx_chan); 10143dc6475cSFlorian Fainelli } else { 10153dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->rx_desc_dma, 10163dc6475cSFlorian Fainelli ENETDMAC_RSTART, priv->rx_chan); 10173dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->tx_desc_dma, 10183dc6475cSFlorian Fainelli ENETDMAC_RSTART, priv->tx_chan); 10193dc6475cSFlorian Fainelli } 1020adfc5217SJeff Kirsher 1021adfc5217SJeff Kirsher /* clear remaining state ram for rx & tx channel */ 10223dc6475cSFlorian Fainelli if (priv->dma_has_sram) { 10233dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->rx_chan); 10243dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->tx_chan); 10253dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->rx_chan); 10263dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->tx_chan); 10273dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->rx_chan); 10283dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->tx_chan); 10293dc6475cSFlorian Fainelli } else { 10303dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_FC, priv->rx_chan); 10313dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_FC, priv->tx_chan); 10323dc6475cSFlorian Fainelli } 1033adfc5217SJeff Kirsher 1034adfc5217SJeff Kirsher /* set max rx/tx length */ 1035adfc5217SJeff Kirsher enet_writel(priv, priv->hw_mtu, ENET_RXMAXLEN_REG); 1036adfc5217SJeff Kirsher enet_writel(priv, priv->hw_mtu, ENET_TXMAXLEN_REG); 1037adfc5217SJeff Kirsher 1038adfc5217SJeff Kirsher /* set dma maximum burst len */ 10396f00a022SMaxime Bizon enet_dmac_writel(priv, priv->dma_maxburst, 10403dc6475cSFlorian Fainelli ENETDMAC_MAXBURST, priv->rx_chan); 10416f00a022SMaxime Bizon enet_dmac_writel(priv, priv->dma_maxburst, 10423dc6475cSFlorian Fainelli ENETDMAC_MAXBURST, priv->tx_chan); 1043adfc5217SJeff Kirsher 1044adfc5217SJeff Kirsher /* set correct transmit fifo watermark */ 1045adfc5217SJeff Kirsher enet_writel(priv, BCMENET_TX_FIFO_TRESH, ENET_TXWMARK_REG); 1046adfc5217SJeff Kirsher 1047adfc5217SJeff Kirsher /* set flow control low/high threshold to 1/3 / 2/3 */ 10483dc6475cSFlorian Fainelli if (priv->dma_has_sram) { 1049adfc5217SJeff Kirsher val = priv->rx_ring_size / 3; 1050adfc5217SJeff Kirsher enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan)); 1051adfc5217SJeff Kirsher val = (priv->rx_ring_size * 2) / 3; 1052adfc5217SJeff Kirsher enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan)); 10533dc6475cSFlorian Fainelli } else { 10543dc6475cSFlorian Fainelli enet_dmac_writel(priv, 5, ENETDMAC_FC, priv->rx_chan); 10553dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->rx_ring_size, ENETDMAC_LEN, priv->rx_chan); 10563dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->tx_ring_size, ENETDMAC_LEN, priv->tx_chan); 10573dc6475cSFlorian Fainelli } 1058adfc5217SJeff Kirsher 1059adfc5217SJeff Kirsher /* all set, enable mac and interrupts, start dma engine and 1060adfc5217SJeff Kirsher * kick rx dma channel */ 1061adfc5217SJeff Kirsher wmb(); 1062adfc5217SJeff Kirsher val = enet_readl(priv, ENET_CTL_REG); 1063adfc5217SJeff Kirsher val |= ENET_CTL_ENABLE_MASK; 1064adfc5217SJeff Kirsher enet_writel(priv, val, ENET_CTL_REG); 1065d6213c1fSJonas Gorski if (priv->dma_has_sram) 1066adfc5217SJeff Kirsher enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); 10673dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_en_mask, 10683dc6475cSFlorian Fainelli ENETDMAC_CHANCFG, priv->rx_chan); 1069adfc5217SJeff Kirsher 1070adfc5217SJeff Kirsher /* watch "mib counters about to overflow" interrupt */ 1071adfc5217SJeff Kirsher enet_writel(priv, ENET_IR_MIB, ENET_IR_REG); 1072adfc5217SJeff Kirsher enet_writel(priv, ENET_IR_MIB, ENET_IRMASK_REG); 1073adfc5217SJeff Kirsher 1074adfc5217SJeff Kirsher /* watch "packet transferred" interrupt in rx and tx */ 10753dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 10763dc6475cSFlorian Fainelli ENETDMAC_IR, priv->rx_chan); 10773dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 10783dc6475cSFlorian Fainelli ENETDMAC_IR, priv->tx_chan); 1079adfc5217SJeff Kirsher 1080adfc5217SJeff Kirsher /* make sure we enable napi before rx interrupt */ 1081adfc5217SJeff Kirsher napi_enable(&priv->napi); 1082adfc5217SJeff Kirsher 10833dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 10843dc6475cSFlorian Fainelli ENETDMAC_IRMASK, priv->rx_chan); 10853dc6475cSFlorian Fainelli enet_dmac_writel(priv, priv->dma_chan_int_mask, 10863dc6475cSFlorian Fainelli ENETDMAC_IRMASK, priv->tx_chan); 1087adfc5217SJeff Kirsher 1088df384d43SArnd Bergmann if (phydev) 1089625eb866SPhilippe Reynes phy_start(phydev); 1090adfc5217SJeff Kirsher else 1091adfc5217SJeff Kirsher bcm_enet_adjust_link(dev); 1092adfc5217SJeff Kirsher 1093adfc5217SJeff Kirsher netif_start_queue(dev); 1094adfc5217SJeff Kirsher return 0; 1095adfc5217SJeff Kirsher 1096adfc5217SJeff Kirsher out: 1097adfc5217SJeff Kirsher for (i = 0; i < priv->rx_ring_size; i++) { 1098adfc5217SJeff Kirsher struct bcm_enet_desc *desc; 1099adfc5217SJeff Kirsher 1100adfc5217SJeff Kirsher if (!priv->rx_skb[i]) 1101adfc5217SJeff Kirsher continue; 1102adfc5217SJeff Kirsher 1103adfc5217SJeff Kirsher desc = &priv->rx_desc_cpu[i]; 1104adfc5217SJeff Kirsher dma_unmap_single(kdev, desc->address, priv->rx_skb_size, 1105adfc5217SJeff Kirsher DMA_FROM_DEVICE); 1106adfc5217SJeff Kirsher kfree_skb(priv->rx_skb[i]); 1107adfc5217SJeff Kirsher } 1108adfc5217SJeff Kirsher kfree(priv->rx_skb); 1109adfc5217SJeff Kirsher 1110adfc5217SJeff Kirsher out_free_tx_skb: 1111adfc5217SJeff Kirsher kfree(priv->tx_skb); 1112adfc5217SJeff Kirsher 1113adfc5217SJeff Kirsher out_free_tx_ring: 1114adfc5217SJeff Kirsher dma_free_coherent(kdev, priv->tx_desc_alloc_size, 1115adfc5217SJeff Kirsher priv->tx_desc_cpu, priv->tx_desc_dma); 1116adfc5217SJeff Kirsher 1117adfc5217SJeff Kirsher out_free_rx_ring: 1118adfc5217SJeff Kirsher dma_free_coherent(kdev, priv->rx_desc_alloc_size, 1119adfc5217SJeff Kirsher priv->rx_desc_cpu, priv->rx_desc_dma); 1120adfc5217SJeff Kirsher 1121adfc5217SJeff Kirsher out_freeirq_tx: 1122adfc5217SJeff Kirsher free_irq(priv->irq_tx, dev); 1123adfc5217SJeff Kirsher 1124adfc5217SJeff Kirsher out_freeirq_rx: 1125adfc5217SJeff Kirsher free_irq(priv->irq_rx, dev); 1126adfc5217SJeff Kirsher 1127adfc5217SJeff Kirsher out_freeirq: 1128adfc5217SJeff Kirsher free_irq(dev->irq, dev); 1129adfc5217SJeff Kirsher 1130adfc5217SJeff Kirsher out_phy_disconnect: 1131df384d43SArnd Bergmann if (phydev) 1132625eb866SPhilippe Reynes phy_disconnect(phydev); 1133adfc5217SJeff Kirsher 1134adfc5217SJeff Kirsher return ret; 1135adfc5217SJeff Kirsher } 1136adfc5217SJeff Kirsher 1137adfc5217SJeff Kirsher /* 1138adfc5217SJeff Kirsher * disable mac 1139adfc5217SJeff Kirsher */ 1140adfc5217SJeff Kirsher static void bcm_enet_disable_mac(struct bcm_enet_priv *priv) 1141adfc5217SJeff Kirsher { 1142adfc5217SJeff Kirsher int limit; 1143adfc5217SJeff Kirsher u32 val; 1144adfc5217SJeff Kirsher 1145adfc5217SJeff Kirsher val = enet_readl(priv, ENET_CTL_REG); 1146adfc5217SJeff Kirsher val |= ENET_CTL_DISABLE_MASK; 1147adfc5217SJeff Kirsher enet_writel(priv, val, ENET_CTL_REG); 1148adfc5217SJeff Kirsher 1149adfc5217SJeff Kirsher limit = 1000; 1150adfc5217SJeff Kirsher do { 1151adfc5217SJeff Kirsher u32 val; 1152adfc5217SJeff Kirsher 1153adfc5217SJeff Kirsher val = enet_readl(priv, ENET_CTL_REG); 1154adfc5217SJeff Kirsher if (!(val & ENET_CTL_DISABLE_MASK)) 1155adfc5217SJeff Kirsher break; 1156adfc5217SJeff Kirsher udelay(1); 1157adfc5217SJeff Kirsher } while (limit--); 1158adfc5217SJeff Kirsher } 1159adfc5217SJeff Kirsher 1160adfc5217SJeff Kirsher /* 1161adfc5217SJeff Kirsher * disable dma in given channel 1162adfc5217SJeff Kirsher */ 1163adfc5217SJeff Kirsher static void bcm_enet_disable_dma(struct bcm_enet_priv *priv, int chan) 1164adfc5217SJeff Kirsher { 1165adfc5217SJeff Kirsher int limit; 1166adfc5217SJeff Kirsher 11673dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_CHANCFG, chan); 1168adfc5217SJeff Kirsher 1169adfc5217SJeff Kirsher limit = 1000; 1170adfc5217SJeff Kirsher do { 1171adfc5217SJeff Kirsher u32 val; 1172adfc5217SJeff Kirsher 11733dc6475cSFlorian Fainelli val = enet_dmac_readl(priv, ENETDMAC_CHANCFG, chan); 11740ae99b5fSMaxime Bizon if (!(val & ENETDMAC_CHANCFG_EN_MASK)) 1175adfc5217SJeff Kirsher break; 1176adfc5217SJeff Kirsher udelay(1); 1177adfc5217SJeff Kirsher } while (limit--); 1178adfc5217SJeff Kirsher } 1179adfc5217SJeff Kirsher 1180adfc5217SJeff Kirsher /* 1181adfc5217SJeff Kirsher * stop callback 1182adfc5217SJeff Kirsher */ 1183adfc5217SJeff Kirsher static int bcm_enet_stop(struct net_device *dev) 1184adfc5217SJeff Kirsher { 1185adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1186adfc5217SJeff Kirsher struct device *kdev; 1187adfc5217SJeff Kirsher int i; 1188adfc5217SJeff Kirsher 1189adfc5217SJeff Kirsher priv = netdev_priv(dev); 1190adfc5217SJeff Kirsher kdev = &priv->pdev->dev; 1191adfc5217SJeff Kirsher 1192adfc5217SJeff Kirsher netif_stop_queue(dev); 1193adfc5217SJeff Kirsher napi_disable(&priv->napi); 1194adfc5217SJeff Kirsher if (priv->has_phy) 1195625eb866SPhilippe Reynes phy_stop(dev->phydev); 1196adfc5217SJeff Kirsher del_timer_sync(&priv->rx_timeout); 1197adfc5217SJeff Kirsher 1198adfc5217SJeff Kirsher /* mask all interrupts */ 1199adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_IRMASK_REG); 12003dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan); 12013dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan); 1202adfc5217SJeff Kirsher 1203adfc5217SJeff Kirsher /* make sure no mib update is scheduled */ 1204adfc5217SJeff Kirsher cancel_work_sync(&priv->mib_update_task); 1205adfc5217SJeff Kirsher 1206adfc5217SJeff Kirsher /* disable dma & mac */ 1207adfc5217SJeff Kirsher bcm_enet_disable_dma(priv, priv->tx_chan); 1208adfc5217SJeff Kirsher bcm_enet_disable_dma(priv, priv->rx_chan); 1209adfc5217SJeff Kirsher bcm_enet_disable_mac(priv); 1210adfc5217SJeff Kirsher 1211adfc5217SJeff Kirsher /* force reclaim of all tx buffers */ 1212adfc5217SJeff Kirsher bcm_enet_tx_reclaim(dev, 1); 1213adfc5217SJeff Kirsher 1214adfc5217SJeff Kirsher /* free the rx skb ring */ 1215adfc5217SJeff Kirsher for (i = 0; i < priv->rx_ring_size; i++) { 1216adfc5217SJeff Kirsher struct bcm_enet_desc *desc; 1217adfc5217SJeff Kirsher 1218adfc5217SJeff Kirsher if (!priv->rx_skb[i]) 1219adfc5217SJeff Kirsher continue; 1220adfc5217SJeff Kirsher 1221adfc5217SJeff Kirsher desc = &priv->rx_desc_cpu[i]; 1222adfc5217SJeff Kirsher dma_unmap_single(kdev, desc->address, priv->rx_skb_size, 1223adfc5217SJeff Kirsher DMA_FROM_DEVICE); 1224adfc5217SJeff Kirsher kfree_skb(priv->rx_skb[i]); 1225adfc5217SJeff Kirsher } 1226adfc5217SJeff Kirsher 1227adfc5217SJeff Kirsher /* free remaining allocated memory */ 1228adfc5217SJeff Kirsher kfree(priv->rx_skb); 1229adfc5217SJeff Kirsher kfree(priv->tx_skb); 1230adfc5217SJeff Kirsher dma_free_coherent(kdev, priv->rx_desc_alloc_size, 1231adfc5217SJeff Kirsher priv->rx_desc_cpu, priv->rx_desc_dma); 1232adfc5217SJeff Kirsher dma_free_coherent(kdev, priv->tx_desc_alloc_size, 1233adfc5217SJeff Kirsher priv->tx_desc_cpu, priv->tx_desc_dma); 1234adfc5217SJeff Kirsher free_irq(priv->irq_tx, dev); 1235adfc5217SJeff Kirsher free_irq(priv->irq_rx, dev); 1236adfc5217SJeff Kirsher free_irq(dev->irq, dev); 1237adfc5217SJeff Kirsher 1238adfc5217SJeff Kirsher /* release phy */ 1239625eb866SPhilippe Reynes if (priv->has_phy) 1240625eb866SPhilippe Reynes phy_disconnect(dev->phydev); 1241adfc5217SJeff Kirsher 1242adfc5217SJeff Kirsher return 0; 1243adfc5217SJeff Kirsher } 1244adfc5217SJeff Kirsher 1245adfc5217SJeff Kirsher /* 1246adfc5217SJeff Kirsher * ethtool callbacks 1247adfc5217SJeff Kirsher */ 1248adfc5217SJeff Kirsher struct bcm_enet_stats { 1249adfc5217SJeff Kirsher char stat_string[ETH_GSTRING_LEN]; 1250adfc5217SJeff Kirsher int sizeof_stat; 1251adfc5217SJeff Kirsher int stat_offset; 1252adfc5217SJeff Kirsher int mib_reg; 1253adfc5217SJeff Kirsher }; 1254adfc5217SJeff Kirsher 1255adfc5217SJeff Kirsher #define GEN_STAT(m) sizeof(((struct bcm_enet_priv *)0)->m), \ 1256adfc5217SJeff Kirsher offsetof(struct bcm_enet_priv, m) 1257adfc5217SJeff Kirsher #define DEV_STAT(m) sizeof(((struct net_device_stats *)0)->m), \ 1258adfc5217SJeff Kirsher offsetof(struct net_device_stats, m) 1259adfc5217SJeff Kirsher 1260adfc5217SJeff Kirsher static const struct bcm_enet_stats bcm_enet_gstrings_stats[] = { 1261adfc5217SJeff Kirsher { "rx_packets", DEV_STAT(rx_packets), -1 }, 1262adfc5217SJeff Kirsher { "tx_packets", DEV_STAT(tx_packets), -1 }, 1263adfc5217SJeff Kirsher { "rx_bytes", DEV_STAT(rx_bytes), -1 }, 1264adfc5217SJeff Kirsher { "tx_bytes", DEV_STAT(tx_bytes), -1 }, 1265adfc5217SJeff Kirsher { "rx_errors", DEV_STAT(rx_errors), -1 }, 1266adfc5217SJeff Kirsher { "tx_errors", DEV_STAT(tx_errors), -1 }, 1267adfc5217SJeff Kirsher { "rx_dropped", DEV_STAT(rx_dropped), -1 }, 1268adfc5217SJeff Kirsher { "tx_dropped", DEV_STAT(tx_dropped), -1 }, 1269adfc5217SJeff Kirsher 1270adfc5217SJeff Kirsher { "rx_good_octets", GEN_STAT(mib.rx_gd_octets), ETH_MIB_RX_GD_OCTETS}, 1271adfc5217SJeff Kirsher { "rx_good_pkts", GEN_STAT(mib.rx_gd_pkts), ETH_MIB_RX_GD_PKTS }, 1272adfc5217SJeff Kirsher { "rx_broadcast", GEN_STAT(mib.rx_brdcast), ETH_MIB_RX_BRDCAST }, 1273adfc5217SJeff Kirsher { "rx_multicast", GEN_STAT(mib.rx_mult), ETH_MIB_RX_MULT }, 1274adfc5217SJeff Kirsher { "rx_64_octets", GEN_STAT(mib.rx_64), ETH_MIB_RX_64 }, 1275adfc5217SJeff Kirsher { "rx_65_127_oct", GEN_STAT(mib.rx_65_127), ETH_MIB_RX_65_127 }, 1276adfc5217SJeff Kirsher { "rx_128_255_oct", GEN_STAT(mib.rx_128_255), ETH_MIB_RX_128_255 }, 1277adfc5217SJeff Kirsher { "rx_256_511_oct", GEN_STAT(mib.rx_256_511), ETH_MIB_RX_256_511 }, 1278adfc5217SJeff Kirsher { "rx_512_1023_oct", GEN_STAT(mib.rx_512_1023), ETH_MIB_RX_512_1023 }, 1279adfc5217SJeff Kirsher { "rx_1024_max_oct", GEN_STAT(mib.rx_1024_max), ETH_MIB_RX_1024_MAX }, 1280adfc5217SJeff Kirsher { "rx_jabber", GEN_STAT(mib.rx_jab), ETH_MIB_RX_JAB }, 1281adfc5217SJeff Kirsher { "rx_oversize", GEN_STAT(mib.rx_ovr), ETH_MIB_RX_OVR }, 1282adfc5217SJeff Kirsher { "rx_fragment", GEN_STAT(mib.rx_frag), ETH_MIB_RX_FRAG }, 1283adfc5217SJeff Kirsher { "rx_dropped", GEN_STAT(mib.rx_drop), ETH_MIB_RX_DROP }, 1284adfc5217SJeff Kirsher { "rx_crc_align", GEN_STAT(mib.rx_crc_align), ETH_MIB_RX_CRC_ALIGN }, 1285adfc5217SJeff Kirsher { "rx_undersize", GEN_STAT(mib.rx_und), ETH_MIB_RX_UND }, 1286adfc5217SJeff Kirsher { "rx_crc", GEN_STAT(mib.rx_crc), ETH_MIB_RX_CRC }, 1287adfc5217SJeff Kirsher { "rx_align", GEN_STAT(mib.rx_align), ETH_MIB_RX_ALIGN }, 1288adfc5217SJeff Kirsher { "rx_symbol_error", GEN_STAT(mib.rx_sym), ETH_MIB_RX_SYM }, 1289adfc5217SJeff Kirsher { "rx_pause", GEN_STAT(mib.rx_pause), ETH_MIB_RX_PAUSE }, 1290adfc5217SJeff Kirsher { "rx_control", GEN_STAT(mib.rx_cntrl), ETH_MIB_RX_CNTRL }, 1291adfc5217SJeff Kirsher 1292adfc5217SJeff Kirsher { "tx_good_octets", GEN_STAT(mib.tx_gd_octets), ETH_MIB_TX_GD_OCTETS }, 1293adfc5217SJeff Kirsher { "tx_good_pkts", GEN_STAT(mib.tx_gd_pkts), ETH_MIB_TX_GD_PKTS }, 1294adfc5217SJeff Kirsher { "tx_broadcast", GEN_STAT(mib.tx_brdcast), ETH_MIB_TX_BRDCAST }, 1295adfc5217SJeff Kirsher { "tx_multicast", GEN_STAT(mib.tx_mult), ETH_MIB_TX_MULT }, 1296adfc5217SJeff Kirsher { "tx_64_oct", GEN_STAT(mib.tx_64), ETH_MIB_TX_64 }, 1297adfc5217SJeff Kirsher { "tx_65_127_oct", GEN_STAT(mib.tx_65_127), ETH_MIB_TX_65_127 }, 1298adfc5217SJeff Kirsher { "tx_128_255_oct", GEN_STAT(mib.tx_128_255), ETH_MIB_TX_128_255 }, 1299adfc5217SJeff Kirsher { "tx_256_511_oct", GEN_STAT(mib.tx_256_511), ETH_MIB_TX_256_511 }, 1300adfc5217SJeff Kirsher { "tx_512_1023_oct", GEN_STAT(mib.tx_512_1023), ETH_MIB_TX_512_1023}, 1301adfc5217SJeff Kirsher { "tx_1024_max_oct", GEN_STAT(mib.tx_1024_max), ETH_MIB_TX_1024_MAX }, 1302adfc5217SJeff Kirsher { "tx_jabber", GEN_STAT(mib.tx_jab), ETH_MIB_TX_JAB }, 1303adfc5217SJeff Kirsher { "tx_oversize", GEN_STAT(mib.tx_ovr), ETH_MIB_TX_OVR }, 1304adfc5217SJeff Kirsher { "tx_fragment", GEN_STAT(mib.tx_frag), ETH_MIB_TX_FRAG }, 1305adfc5217SJeff Kirsher { "tx_underrun", GEN_STAT(mib.tx_underrun), ETH_MIB_TX_UNDERRUN }, 1306adfc5217SJeff Kirsher { "tx_collisions", GEN_STAT(mib.tx_col), ETH_MIB_TX_COL }, 1307adfc5217SJeff Kirsher { "tx_single_collision", GEN_STAT(mib.tx_1_col), ETH_MIB_TX_1_COL }, 1308adfc5217SJeff Kirsher { "tx_multiple_collision", GEN_STAT(mib.tx_m_col), ETH_MIB_TX_M_COL }, 1309adfc5217SJeff Kirsher { "tx_excess_collision", GEN_STAT(mib.tx_ex_col), ETH_MIB_TX_EX_COL }, 1310adfc5217SJeff Kirsher { "tx_late_collision", GEN_STAT(mib.tx_late), ETH_MIB_TX_LATE }, 1311adfc5217SJeff Kirsher { "tx_deferred", GEN_STAT(mib.tx_def), ETH_MIB_TX_DEF }, 1312adfc5217SJeff Kirsher { "tx_carrier_sense", GEN_STAT(mib.tx_crs), ETH_MIB_TX_CRS }, 1313adfc5217SJeff Kirsher { "tx_pause", GEN_STAT(mib.tx_pause), ETH_MIB_TX_PAUSE }, 1314adfc5217SJeff Kirsher 1315adfc5217SJeff Kirsher }; 1316adfc5217SJeff Kirsher 13176afc0d7aSTobias Klauser #define BCM_ENET_STATS_LEN ARRAY_SIZE(bcm_enet_gstrings_stats) 1318adfc5217SJeff Kirsher 1319adfc5217SJeff Kirsher static const u32 unused_mib_regs[] = { 1320adfc5217SJeff Kirsher ETH_MIB_TX_ALL_OCTETS, 1321adfc5217SJeff Kirsher ETH_MIB_TX_ALL_PKTS, 1322adfc5217SJeff Kirsher ETH_MIB_RX_ALL_OCTETS, 1323adfc5217SJeff Kirsher ETH_MIB_RX_ALL_PKTS, 1324adfc5217SJeff Kirsher }; 1325adfc5217SJeff Kirsher 1326adfc5217SJeff Kirsher 1327adfc5217SJeff Kirsher static void bcm_enet_get_drvinfo(struct net_device *netdev, 1328adfc5217SJeff Kirsher struct ethtool_drvinfo *drvinfo) 1329adfc5217SJeff Kirsher { 13307826d43fSJiri Pirko strlcpy(drvinfo->driver, bcm_enet_driver_name, sizeof(drvinfo->driver)); 13317826d43fSJiri Pirko strlcpy(drvinfo->version, bcm_enet_driver_version, 13327826d43fSJiri Pirko sizeof(drvinfo->version)); 13337826d43fSJiri Pirko strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); 13347826d43fSJiri Pirko strlcpy(drvinfo->bus_info, "bcm63xx", sizeof(drvinfo->bus_info)); 1335adfc5217SJeff Kirsher } 1336adfc5217SJeff Kirsher 1337adfc5217SJeff Kirsher static int bcm_enet_get_sset_count(struct net_device *netdev, 1338adfc5217SJeff Kirsher int string_set) 1339adfc5217SJeff Kirsher { 1340adfc5217SJeff Kirsher switch (string_set) { 1341adfc5217SJeff Kirsher case ETH_SS_STATS: 1342adfc5217SJeff Kirsher return BCM_ENET_STATS_LEN; 1343adfc5217SJeff Kirsher default: 1344adfc5217SJeff Kirsher return -EINVAL; 1345adfc5217SJeff Kirsher } 1346adfc5217SJeff Kirsher } 1347adfc5217SJeff Kirsher 1348adfc5217SJeff Kirsher static void bcm_enet_get_strings(struct net_device *netdev, 1349adfc5217SJeff Kirsher u32 stringset, u8 *data) 1350adfc5217SJeff Kirsher { 1351adfc5217SJeff Kirsher int i; 1352adfc5217SJeff Kirsher 1353adfc5217SJeff Kirsher switch (stringset) { 1354adfc5217SJeff Kirsher case ETH_SS_STATS: 1355adfc5217SJeff Kirsher for (i = 0; i < BCM_ENET_STATS_LEN; i++) { 1356adfc5217SJeff Kirsher memcpy(data + i * ETH_GSTRING_LEN, 1357adfc5217SJeff Kirsher bcm_enet_gstrings_stats[i].stat_string, 1358adfc5217SJeff Kirsher ETH_GSTRING_LEN); 1359adfc5217SJeff Kirsher } 1360adfc5217SJeff Kirsher break; 1361adfc5217SJeff Kirsher } 1362adfc5217SJeff Kirsher } 1363adfc5217SJeff Kirsher 1364adfc5217SJeff Kirsher static void update_mib_counters(struct bcm_enet_priv *priv) 1365adfc5217SJeff Kirsher { 1366adfc5217SJeff Kirsher int i; 1367adfc5217SJeff Kirsher 1368adfc5217SJeff Kirsher for (i = 0; i < BCM_ENET_STATS_LEN; i++) { 1369adfc5217SJeff Kirsher const struct bcm_enet_stats *s; 1370adfc5217SJeff Kirsher u32 val; 1371adfc5217SJeff Kirsher char *p; 1372adfc5217SJeff Kirsher 1373adfc5217SJeff Kirsher s = &bcm_enet_gstrings_stats[i]; 1374adfc5217SJeff Kirsher if (s->mib_reg == -1) 1375adfc5217SJeff Kirsher continue; 1376adfc5217SJeff Kirsher 1377adfc5217SJeff Kirsher val = enet_readl(priv, ENET_MIB_REG(s->mib_reg)); 1378adfc5217SJeff Kirsher p = (char *)priv + s->stat_offset; 1379adfc5217SJeff Kirsher 1380adfc5217SJeff Kirsher if (s->sizeof_stat == sizeof(u64)) 1381adfc5217SJeff Kirsher *(u64 *)p += val; 1382adfc5217SJeff Kirsher else 1383adfc5217SJeff Kirsher *(u32 *)p += val; 1384adfc5217SJeff Kirsher } 1385adfc5217SJeff Kirsher 1386adfc5217SJeff Kirsher /* also empty unused mib counters to make sure mib counter 1387adfc5217SJeff Kirsher * overflow interrupt is cleared */ 1388adfc5217SJeff Kirsher for (i = 0; i < ARRAY_SIZE(unused_mib_regs); i++) 1389adfc5217SJeff Kirsher (void)enet_readl(priv, ENET_MIB_REG(unused_mib_regs[i])); 1390adfc5217SJeff Kirsher } 1391adfc5217SJeff Kirsher 1392adfc5217SJeff Kirsher static void bcm_enet_update_mib_counters_defer(struct work_struct *t) 1393adfc5217SJeff Kirsher { 1394adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1395adfc5217SJeff Kirsher 1396adfc5217SJeff Kirsher priv = container_of(t, struct bcm_enet_priv, mib_update_task); 1397adfc5217SJeff Kirsher mutex_lock(&priv->mib_update_lock); 1398adfc5217SJeff Kirsher update_mib_counters(priv); 1399adfc5217SJeff Kirsher mutex_unlock(&priv->mib_update_lock); 1400adfc5217SJeff Kirsher 1401adfc5217SJeff Kirsher /* reenable mib interrupt */ 1402adfc5217SJeff Kirsher if (netif_running(priv->net_dev)) 1403adfc5217SJeff Kirsher enet_writel(priv, ENET_IR_MIB, ENET_IRMASK_REG); 1404adfc5217SJeff Kirsher } 1405adfc5217SJeff Kirsher 1406adfc5217SJeff Kirsher static void bcm_enet_get_ethtool_stats(struct net_device *netdev, 1407adfc5217SJeff Kirsher struct ethtool_stats *stats, 1408adfc5217SJeff Kirsher u64 *data) 1409adfc5217SJeff Kirsher { 1410adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1411adfc5217SJeff Kirsher int i; 1412adfc5217SJeff Kirsher 1413adfc5217SJeff Kirsher priv = netdev_priv(netdev); 1414adfc5217SJeff Kirsher 1415adfc5217SJeff Kirsher mutex_lock(&priv->mib_update_lock); 1416adfc5217SJeff Kirsher update_mib_counters(priv); 1417adfc5217SJeff Kirsher 1418adfc5217SJeff Kirsher for (i = 0; i < BCM_ENET_STATS_LEN; i++) { 1419adfc5217SJeff Kirsher const struct bcm_enet_stats *s; 1420adfc5217SJeff Kirsher char *p; 1421adfc5217SJeff Kirsher 1422adfc5217SJeff Kirsher s = &bcm_enet_gstrings_stats[i]; 1423adfc5217SJeff Kirsher if (s->mib_reg == -1) 1424adfc5217SJeff Kirsher p = (char *)&netdev->stats; 1425adfc5217SJeff Kirsher else 1426adfc5217SJeff Kirsher p = (char *)priv; 1427adfc5217SJeff Kirsher p += s->stat_offset; 1428adfc5217SJeff Kirsher data[i] = (s->sizeof_stat == sizeof(u64)) ? 1429adfc5217SJeff Kirsher *(u64 *)p : *(u32 *)p; 1430adfc5217SJeff Kirsher } 1431adfc5217SJeff Kirsher mutex_unlock(&priv->mib_update_lock); 1432adfc5217SJeff Kirsher } 1433adfc5217SJeff Kirsher 14347260aac9SMaxime Bizon static int bcm_enet_nway_reset(struct net_device *dev) 14357260aac9SMaxime Bizon { 14367260aac9SMaxime Bizon struct bcm_enet_priv *priv; 14377260aac9SMaxime Bizon 14387260aac9SMaxime Bizon priv = netdev_priv(dev); 143942469bf5SFlorian Fainelli if (priv->has_phy) 14400fa1dfd6SFlorian Fainelli return phy_ethtool_nway_reset(dev); 14417260aac9SMaxime Bizon 14427260aac9SMaxime Bizon return -EOPNOTSUPP; 14437260aac9SMaxime Bizon } 14447260aac9SMaxime Bizon 1445639cfa9eSPhilippe Reynes static int bcm_enet_get_link_ksettings(struct net_device *dev, 1446639cfa9eSPhilippe Reynes struct ethtool_link_ksettings *cmd) 1447adfc5217SJeff Kirsher { 1448adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1449639cfa9eSPhilippe Reynes u32 supported, advertising; 1450adfc5217SJeff Kirsher 1451adfc5217SJeff Kirsher priv = netdev_priv(dev); 1452adfc5217SJeff Kirsher 1453adfc5217SJeff Kirsher if (priv->has_phy) { 1454625eb866SPhilippe Reynes if (!dev->phydev) 1455adfc5217SJeff Kirsher return -ENODEV; 14565514174fSyuval.shaia@oracle.com 14575514174fSyuval.shaia@oracle.com phy_ethtool_ksettings_get(dev->phydev, cmd); 14585514174fSyuval.shaia@oracle.com 14595514174fSyuval.shaia@oracle.com return 0; 1460adfc5217SJeff Kirsher } else { 1461639cfa9eSPhilippe Reynes cmd->base.autoneg = 0; 1462639cfa9eSPhilippe Reynes cmd->base.speed = (priv->force_speed_100) ? 1463639cfa9eSPhilippe Reynes SPEED_100 : SPEED_10; 1464639cfa9eSPhilippe Reynes cmd->base.duplex = (priv->force_duplex_full) ? 1465adfc5217SJeff Kirsher DUPLEX_FULL : DUPLEX_HALF; 1466639cfa9eSPhilippe Reynes supported = ADVERTISED_10baseT_Half | 1467adfc5217SJeff Kirsher ADVERTISED_10baseT_Full | 1468adfc5217SJeff Kirsher ADVERTISED_100baseT_Half | 1469adfc5217SJeff Kirsher ADVERTISED_100baseT_Full; 1470639cfa9eSPhilippe Reynes advertising = 0; 1471639cfa9eSPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 1472639cfa9eSPhilippe Reynes cmd->link_modes.supported, supported); 1473639cfa9eSPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 1474639cfa9eSPhilippe Reynes cmd->link_modes.advertising, advertising); 1475639cfa9eSPhilippe Reynes cmd->base.port = PORT_MII; 1476adfc5217SJeff Kirsher } 1477adfc5217SJeff Kirsher return 0; 1478adfc5217SJeff Kirsher } 1479adfc5217SJeff Kirsher 1480639cfa9eSPhilippe Reynes static int bcm_enet_set_link_ksettings(struct net_device *dev, 1481639cfa9eSPhilippe Reynes const struct ethtool_link_ksettings *cmd) 1482adfc5217SJeff Kirsher { 1483adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1484adfc5217SJeff Kirsher 1485adfc5217SJeff Kirsher priv = netdev_priv(dev); 1486adfc5217SJeff Kirsher if (priv->has_phy) { 1487625eb866SPhilippe Reynes if (!dev->phydev) 1488adfc5217SJeff Kirsher return -ENODEV; 1489639cfa9eSPhilippe Reynes return phy_ethtool_ksettings_set(dev->phydev, cmd); 1490adfc5217SJeff Kirsher } else { 1491adfc5217SJeff Kirsher 1492639cfa9eSPhilippe Reynes if (cmd->base.autoneg || 1493639cfa9eSPhilippe Reynes (cmd->base.speed != SPEED_100 && 1494639cfa9eSPhilippe Reynes cmd->base.speed != SPEED_10) || 1495639cfa9eSPhilippe Reynes cmd->base.port != PORT_MII) 1496adfc5217SJeff Kirsher return -EINVAL; 1497adfc5217SJeff Kirsher 1498639cfa9eSPhilippe Reynes priv->force_speed_100 = 1499639cfa9eSPhilippe Reynes (cmd->base.speed == SPEED_100) ? 1 : 0; 1500639cfa9eSPhilippe Reynes priv->force_duplex_full = 1501639cfa9eSPhilippe Reynes (cmd->base.duplex == DUPLEX_FULL) ? 1 : 0; 1502adfc5217SJeff Kirsher 1503adfc5217SJeff Kirsher if (netif_running(dev)) 1504adfc5217SJeff Kirsher bcm_enet_adjust_link(dev); 1505adfc5217SJeff Kirsher return 0; 1506adfc5217SJeff Kirsher } 1507adfc5217SJeff Kirsher } 1508adfc5217SJeff Kirsher 1509adfc5217SJeff Kirsher static void bcm_enet_get_ringparam(struct net_device *dev, 1510adfc5217SJeff Kirsher struct ethtool_ringparam *ering) 1511adfc5217SJeff Kirsher { 1512adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1513adfc5217SJeff Kirsher 1514adfc5217SJeff Kirsher priv = netdev_priv(dev); 1515adfc5217SJeff Kirsher 1516adfc5217SJeff Kirsher /* rx/tx ring is actually only limited by memory */ 1517adfc5217SJeff Kirsher ering->rx_max_pending = 8192; 1518adfc5217SJeff Kirsher ering->tx_max_pending = 8192; 1519adfc5217SJeff Kirsher ering->rx_pending = priv->rx_ring_size; 1520adfc5217SJeff Kirsher ering->tx_pending = priv->tx_ring_size; 1521adfc5217SJeff Kirsher } 1522adfc5217SJeff Kirsher 1523adfc5217SJeff Kirsher static int bcm_enet_set_ringparam(struct net_device *dev, 1524adfc5217SJeff Kirsher struct ethtool_ringparam *ering) 1525adfc5217SJeff Kirsher { 1526adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1527adfc5217SJeff Kirsher int was_running; 1528adfc5217SJeff Kirsher 1529adfc5217SJeff Kirsher priv = netdev_priv(dev); 1530adfc5217SJeff Kirsher 1531adfc5217SJeff Kirsher was_running = 0; 1532adfc5217SJeff Kirsher if (netif_running(dev)) { 1533adfc5217SJeff Kirsher bcm_enet_stop(dev); 1534adfc5217SJeff Kirsher was_running = 1; 1535adfc5217SJeff Kirsher } 1536adfc5217SJeff Kirsher 1537adfc5217SJeff Kirsher priv->rx_ring_size = ering->rx_pending; 1538adfc5217SJeff Kirsher priv->tx_ring_size = ering->tx_pending; 1539adfc5217SJeff Kirsher 1540adfc5217SJeff Kirsher if (was_running) { 1541adfc5217SJeff Kirsher int err; 1542adfc5217SJeff Kirsher 1543adfc5217SJeff Kirsher err = bcm_enet_open(dev); 1544adfc5217SJeff Kirsher if (err) 1545adfc5217SJeff Kirsher dev_close(dev); 1546adfc5217SJeff Kirsher else 1547adfc5217SJeff Kirsher bcm_enet_set_multicast_list(dev); 1548adfc5217SJeff Kirsher } 1549adfc5217SJeff Kirsher return 0; 1550adfc5217SJeff Kirsher } 1551adfc5217SJeff Kirsher 1552adfc5217SJeff Kirsher static void bcm_enet_get_pauseparam(struct net_device *dev, 1553adfc5217SJeff Kirsher struct ethtool_pauseparam *ecmd) 1554adfc5217SJeff Kirsher { 1555adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1556adfc5217SJeff Kirsher 1557adfc5217SJeff Kirsher priv = netdev_priv(dev); 1558adfc5217SJeff Kirsher ecmd->autoneg = priv->pause_auto; 1559adfc5217SJeff Kirsher ecmd->rx_pause = priv->pause_rx; 1560adfc5217SJeff Kirsher ecmd->tx_pause = priv->pause_tx; 1561adfc5217SJeff Kirsher } 1562adfc5217SJeff Kirsher 1563adfc5217SJeff Kirsher static int bcm_enet_set_pauseparam(struct net_device *dev, 1564adfc5217SJeff Kirsher struct ethtool_pauseparam *ecmd) 1565adfc5217SJeff Kirsher { 1566adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1567adfc5217SJeff Kirsher 1568adfc5217SJeff Kirsher priv = netdev_priv(dev); 1569adfc5217SJeff Kirsher 1570adfc5217SJeff Kirsher if (priv->has_phy) { 1571adfc5217SJeff Kirsher if (ecmd->autoneg && (ecmd->rx_pause != ecmd->tx_pause)) { 1572adfc5217SJeff Kirsher /* asymetric pause mode not supported, 1573adfc5217SJeff Kirsher * actually possible but integrated PHY has RO 1574adfc5217SJeff Kirsher * asym_pause bit */ 1575adfc5217SJeff Kirsher return -EINVAL; 1576adfc5217SJeff Kirsher } 1577adfc5217SJeff Kirsher } else { 1578adfc5217SJeff Kirsher /* no pause autoneg on direct mii connection */ 1579adfc5217SJeff Kirsher if (ecmd->autoneg) 1580adfc5217SJeff Kirsher return -EINVAL; 1581adfc5217SJeff Kirsher } 1582adfc5217SJeff Kirsher 1583adfc5217SJeff Kirsher priv->pause_auto = ecmd->autoneg; 1584adfc5217SJeff Kirsher priv->pause_rx = ecmd->rx_pause; 1585adfc5217SJeff Kirsher priv->pause_tx = ecmd->tx_pause; 1586adfc5217SJeff Kirsher 1587adfc5217SJeff Kirsher return 0; 1588adfc5217SJeff Kirsher } 1589adfc5217SJeff Kirsher 15901aff0cbeSstephen hemminger static const struct ethtool_ops bcm_enet_ethtool_ops = { 1591adfc5217SJeff Kirsher .get_strings = bcm_enet_get_strings, 1592adfc5217SJeff Kirsher .get_sset_count = bcm_enet_get_sset_count, 1593adfc5217SJeff Kirsher .get_ethtool_stats = bcm_enet_get_ethtool_stats, 15947260aac9SMaxime Bizon .nway_reset = bcm_enet_nway_reset, 1595adfc5217SJeff Kirsher .get_drvinfo = bcm_enet_get_drvinfo, 1596adfc5217SJeff Kirsher .get_link = ethtool_op_get_link, 1597adfc5217SJeff Kirsher .get_ringparam = bcm_enet_get_ringparam, 1598adfc5217SJeff Kirsher .set_ringparam = bcm_enet_set_ringparam, 1599adfc5217SJeff Kirsher .get_pauseparam = bcm_enet_get_pauseparam, 1600adfc5217SJeff Kirsher .set_pauseparam = bcm_enet_set_pauseparam, 1601639cfa9eSPhilippe Reynes .get_link_ksettings = bcm_enet_get_link_ksettings, 1602639cfa9eSPhilippe Reynes .set_link_ksettings = bcm_enet_set_link_ksettings, 1603adfc5217SJeff Kirsher }; 1604adfc5217SJeff Kirsher 1605adfc5217SJeff Kirsher static int bcm_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 1606adfc5217SJeff Kirsher { 1607adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1608adfc5217SJeff Kirsher 1609adfc5217SJeff Kirsher priv = netdev_priv(dev); 1610adfc5217SJeff Kirsher if (priv->has_phy) { 1611625eb866SPhilippe Reynes if (!dev->phydev) 1612adfc5217SJeff Kirsher return -ENODEV; 1613625eb866SPhilippe Reynes return phy_mii_ioctl(dev->phydev, rq, cmd); 1614adfc5217SJeff Kirsher } else { 1615adfc5217SJeff Kirsher struct mii_if_info mii; 1616adfc5217SJeff Kirsher 1617adfc5217SJeff Kirsher mii.dev = dev; 1618adfc5217SJeff Kirsher mii.mdio_read = bcm_enet_mdio_read_mii; 1619adfc5217SJeff Kirsher mii.mdio_write = bcm_enet_mdio_write_mii; 1620adfc5217SJeff Kirsher mii.phy_id = 0; 1621adfc5217SJeff Kirsher mii.phy_id_mask = 0x3f; 1622adfc5217SJeff Kirsher mii.reg_num_mask = 0x1f; 1623adfc5217SJeff Kirsher return generic_mii_ioctl(&mii, if_mii(rq), cmd, NULL); 1624adfc5217SJeff Kirsher } 1625adfc5217SJeff Kirsher } 1626adfc5217SJeff Kirsher 1627adfc5217SJeff Kirsher /* 1628e1c6dccaSJarod Wilson * adjust mtu, can't be called while device is running 1629adfc5217SJeff Kirsher */ 1630e1c6dccaSJarod Wilson static int bcm_enet_change_mtu(struct net_device *dev, int new_mtu) 1631adfc5217SJeff Kirsher { 1632e1c6dccaSJarod Wilson struct bcm_enet_priv *priv = netdev_priv(dev); 1633e1c6dccaSJarod Wilson int actual_mtu = new_mtu; 1634adfc5217SJeff Kirsher 1635e1c6dccaSJarod Wilson if (netif_running(dev)) 1636e1c6dccaSJarod Wilson return -EBUSY; 1637adfc5217SJeff Kirsher 1638adfc5217SJeff Kirsher /* add ethernet header + vlan tag size */ 1639adfc5217SJeff Kirsher actual_mtu += VLAN_ETH_HLEN; 1640adfc5217SJeff Kirsher 1641adfc5217SJeff Kirsher /* 1642adfc5217SJeff Kirsher * setup maximum size before we get overflow mark in 1643adfc5217SJeff Kirsher * descriptor, note that this will not prevent reception of 1644adfc5217SJeff Kirsher * big frames, they will be split into multiple buffers 1645adfc5217SJeff Kirsher * anyway 1646adfc5217SJeff Kirsher */ 1647adfc5217SJeff Kirsher priv->hw_mtu = actual_mtu; 1648adfc5217SJeff Kirsher 1649adfc5217SJeff Kirsher /* 1650adfc5217SJeff Kirsher * align rx buffer size to dma burst len, account FCS since 1651adfc5217SJeff Kirsher * it's appended 1652adfc5217SJeff Kirsher */ 1653adfc5217SJeff Kirsher priv->rx_skb_size = ALIGN(actual_mtu + ETH_FCS_LEN, 16546f00a022SMaxime Bizon priv->dma_maxburst * 4); 1655adfc5217SJeff Kirsher 1656adfc5217SJeff Kirsher dev->mtu = new_mtu; 1657adfc5217SJeff Kirsher return 0; 1658adfc5217SJeff Kirsher } 1659adfc5217SJeff Kirsher 1660adfc5217SJeff Kirsher /* 1661adfc5217SJeff Kirsher * preinit hardware to allow mii operation while device is down 1662adfc5217SJeff Kirsher */ 1663adfc5217SJeff Kirsher static void bcm_enet_hw_preinit(struct bcm_enet_priv *priv) 1664adfc5217SJeff Kirsher { 1665adfc5217SJeff Kirsher u32 val; 1666adfc5217SJeff Kirsher int limit; 1667adfc5217SJeff Kirsher 1668adfc5217SJeff Kirsher /* make sure mac is disabled */ 1669adfc5217SJeff Kirsher bcm_enet_disable_mac(priv); 1670adfc5217SJeff Kirsher 1671adfc5217SJeff Kirsher /* soft reset mac */ 1672adfc5217SJeff Kirsher val = ENET_CTL_SRESET_MASK; 1673adfc5217SJeff Kirsher enet_writel(priv, val, ENET_CTL_REG); 1674adfc5217SJeff Kirsher wmb(); 1675adfc5217SJeff Kirsher 1676adfc5217SJeff Kirsher limit = 1000; 1677adfc5217SJeff Kirsher do { 1678adfc5217SJeff Kirsher val = enet_readl(priv, ENET_CTL_REG); 1679adfc5217SJeff Kirsher if (!(val & ENET_CTL_SRESET_MASK)) 1680adfc5217SJeff Kirsher break; 1681adfc5217SJeff Kirsher udelay(1); 1682adfc5217SJeff Kirsher } while (limit--); 1683adfc5217SJeff Kirsher 1684adfc5217SJeff Kirsher /* select correct mii interface */ 1685adfc5217SJeff Kirsher val = enet_readl(priv, ENET_CTL_REG); 1686adfc5217SJeff Kirsher if (priv->use_external_mii) 1687adfc5217SJeff Kirsher val |= ENET_CTL_EPHYSEL_MASK; 1688adfc5217SJeff Kirsher else 1689adfc5217SJeff Kirsher val &= ~ENET_CTL_EPHYSEL_MASK; 1690adfc5217SJeff Kirsher enet_writel(priv, val, ENET_CTL_REG); 1691adfc5217SJeff Kirsher 1692adfc5217SJeff Kirsher /* turn on mdc clock */ 1693adfc5217SJeff Kirsher enet_writel(priv, (0x1f << ENET_MIISC_MDCFREQDIV_SHIFT) | 1694adfc5217SJeff Kirsher ENET_MIISC_PREAMBLEEN_MASK, ENET_MIISC_REG); 1695adfc5217SJeff Kirsher 1696adfc5217SJeff Kirsher /* set mib counters to self-clear when read */ 1697adfc5217SJeff Kirsher val = enet_readl(priv, ENET_MIBCTL_REG); 1698adfc5217SJeff Kirsher val |= ENET_MIBCTL_RDCLEAR_MASK; 1699adfc5217SJeff Kirsher enet_writel(priv, val, ENET_MIBCTL_REG); 1700adfc5217SJeff Kirsher } 1701adfc5217SJeff Kirsher 1702adfc5217SJeff Kirsher static const struct net_device_ops bcm_enet_ops = { 1703adfc5217SJeff Kirsher .ndo_open = bcm_enet_open, 1704adfc5217SJeff Kirsher .ndo_stop = bcm_enet_stop, 1705adfc5217SJeff Kirsher .ndo_start_xmit = bcm_enet_start_xmit, 1706adfc5217SJeff Kirsher .ndo_set_mac_address = bcm_enet_set_mac_address, 1707afc4b13dSJiri Pirko .ndo_set_rx_mode = bcm_enet_set_multicast_list, 1708adfc5217SJeff Kirsher .ndo_do_ioctl = bcm_enet_ioctl, 1709adfc5217SJeff Kirsher .ndo_change_mtu = bcm_enet_change_mtu, 1710adfc5217SJeff Kirsher }; 1711adfc5217SJeff Kirsher 1712adfc5217SJeff Kirsher /* 1713adfc5217SJeff Kirsher * allocate netdevice, request register memory and register device. 1714adfc5217SJeff Kirsher */ 1715047fc566SBill Pemberton static int bcm_enet_probe(struct platform_device *pdev) 1716adfc5217SJeff Kirsher { 1717adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1718adfc5217SJeff Kirsher struct net_device *dev; 1719adfc5217SJeff Kirsher struct bcm63xx_enet_platform_data *pd; 1720adfc5217SJeff Kirsher struct resource *res_mem, *res_irq, *res_irq_rx, *res_irq_tx; 1721adfc5217SJeff Kirsher struct mii_bus *bus; 1722adfc5217SJeff Kirsher const char *clk_name; 1723adfc5217SJeff Kirsher int i, ret; 1724adfc5217SJeff Kirsher 1725adfc5217SJeff Kirsher /* stop if shared driver failed, assume driver->probe will be 1726adfc5217SJeff Kirsher * called in the same order we register devices (correct ?) */ 17270ae99b5fSMaxime Bizon if (!bcm_enet_shared_base[0]) 1728adfc5217SJeff Kirsher return -ENODEV; 1729adfc5217SJeff Kirsher 1730adfc5217SJeff Kirsher res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1731adfc5217SJeff Kirsher res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1); 1732adfc5217SJeff Kirsher res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 2); 1733f607e059SJulia Lawall if (!res_irq || !res_irq_rx || !res_irq_tx) 1734adfc5217SJeff Kirsher return -ENODEV; 1735adfc5217SJeff Kirsher 1736adfc5217SJeff Kirsher ret = 0; 1737adfc5217SJeff Kirsher dev = alloc_etherdev(sizeof(*priv)); 1738adfc5217SJeff Kirsher if (!dev) 1739adfc5217SJeff Kirsher return -ENOMEM; 1740adfc5217SJeff Kirsher priv = netdev_priv(dev); 1741adfc5217SJeff Kirsher 17426f00a022SMaxime Bizon priv->enet_is_sw = false; 17436f00a022SMaxime Bizon priv->dma_maxburst = BCMENET_DMA_MAXBURST; 17446f00a022SMaxime Bizon 1745e1c6dccaSJarod Wilson ret = bcm_enet_change_mtu(dev, dev->mtu); 1746adfc5217SJeff Kirsher if (ret) 1747adfc5217SJeff Kirsher goto out; 1748adfc5217SJeff Kirsher 1749f607e059SJulia Lawall res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1750f607e059SJulia Lawall priv->base = devm_ioremap_resource(&pdev->dev, res_mem); 1751f607e059SJulia Lawall if (IS_ERR(priv->base)) { 1752f607e059SJulia Lawall ret = PTR_ERR(priv->base); 1753adfc5217SJeff Kirsher goto out; 1754adfc5217SJeff Kirsher } 1755adfc5217SJeff Kirsher 1756adfc5217SJeff Kirsher dev->irq = priv->irq = res_irq->start; 1757adfc5217SJeff Kirsher priv->irq_rx = res_irq_rx->start; 1758adfc5217SJeff Kirsher priv->irq_tx = res_irq_tx->start; 1759adfc5217SJeff Kirsher priv->mac_id = pdev->id; 1760adfc5217SJeff Kirsher 1761adfc5217SJeff Kirsher /* get rx & tx dma channel id for this mac */ 1762adfc5217SJeff Kirsher if (priv->mac_id == 0) { 1763adfc5217SJeff Kirsher priv->rx_chan = 0; 1764adfc5217SJeff Kirsher priv->tx_chan = 1; 1765adfc5217SJeff Kirsher clk_name = "enet0"; 1766adfc5217SJeff Kirsher } else { 1767adfc5217SJeff Kirsher priv->rx_chan = 2; 1768adfc5217SJeff Kirsher priv->tx_chan = 3; 1769adfc5217SJeff Kirsher clk_name = "enet1"; 1770adfc5217SJeff Kirsher } 1771adfc5217SJeff Kirsher 1772adfc5217SJeff Kirsher priv->mac_clk = clk_get(&pdev->dev, clk_name); 1773adfc5217SJeff Kirsher if (IS_ERR(priv->mac_clk)) { 1774adfc5217SJeff Kirsher ret = PTR_ERR(priv->mac_clk); 17751c03da05SJonas Gorski goto out; 1776adfc5217SJeff Kirsher } 17779c86b846SJonas Gorski ret = clk_prepare_enable(priv->mac_clk); 17789c86b846SJonas Gorski if (ret) 17799c86b846SJonas Gorski goto out_put_clk_mac; 1780adfc5217SJeff Kirsher 1781adfc5217SJeff Kirsher /* initialize default and fetch platform data */ 1782adfc5217SJeff Kirsher priv->rx_ring_size = BCMENET_DEF_RX_DESC; 1783adfc5217SJeff Kirsher priv->tx_ring_size = BCMENET_DEF_TX_DESC; 1784adfc5217SJeff Kirsher 1785cf0e7794SJingoo Han pd = dev_get_platdata(&pdev->dev); 1786adfc5217SJeff Kirsher if (pd) { 1787adfc5217SJeff Kirsher memcpy(dev->dev_addr, pd->mac_addr, ETH_ALEN); 1788adfc5217SJeff Kirsher priv->has_phy = pd->has_phy; 1789adfc5217SJeff Kirsher priv->phy_id = pd->phy_id; 1790adfc5217SJeff Kirsher priv->has_phy_interrupt = pd->has_phy_interrupt; 1791adfc5217SJeff Kirsher priv->phy_interrupt = pd->phy_interrupt; 1792adfc5217SJeff Kirsher priv->use_external_mii = !pd->use_internal_phy; 1793adfc5217SJeff Kirsher priv->pause_auto = pd->pause_auto; 1794adfc5217SJeff Kirsher priv->pause_rx = pd->pause_rx; 1795adfc5217SJeff Kirsher priv->pause_tx = pd->pause_tx; 1796adfc5217SJeff Kirsher priv->force_duplex_full = pd->force_duplex_full; 1797adfc5217SJeff Kirsher priv->force_speed_100 = pd->force_speed_100; 17983dc6475cSFlorian Fainelli priv->dma_chan_en_mask = pd->dma_chan_en_mask; 17993dc6475cSFlorian Fainelli priv->dma_chan_int_mask = pd->dma_chan_int_mask; 18003dc6475cSFlorian Fainelli priv->dma_chan_width = pd->dma_chan_width; 18013dc6475cSFlorian Fainelli priv->dma_has_sram = pd->dma_has_sram; 18023dc6475cSFlorian Fainelli priv->dma_desc_shift = pd->dma_desc_shift; 1803adfc5217SJeff Kirsher } 1804adfc5217SJeff Kirsher 1805adfc5217SJeff Kirsher if (priv->mac_id == 0 && priv->has_phy && !priv->use_external_mii) { 1806adfc5217SJeff Kirsher /* using internal PHY, enable clock */ 1807adfc5217SJeff Kirsher priv->phy_clk = clk_get(&pdev->dev, "ephy"); 1808adfc5217SJeff Kirsher if (IS_ERR(priv->phy_clk)) { 1809adfc5217SJeff Kirsher ret = PTR_ERR(priv->phy_clk); 1810adfc5217SJeff Kirsher priv->phy_clk = NULL; 18119c86b846SJonas Gorski goto out_disable_clk_mac; 1812adfc5217SJeff Kirsher } 18139c86b846SJonas Gorski ret = clk_prepare_enable(priv->phy_clk); 18149c86b846SJonas Gorski if (ret) 18159c86b846SJonas Gorski goto out_put_clk_phy; 1816adfc5217SJeff Kirsher } 1817adfc5217SJeff Kirsher 1818adfc5217SJeff Kirsher /* do minimal hardware init to be able to probe mii bus */ 1819adfc5217SJeff Kirsher bcm_enet_hw_preinit(priv); 1820adfc5217SJeff Kirsher 1821adfc5217SJeff Kirsher /* MII bus registration */ 1822adfc5217SJeff Kirsher if (priv->has_phy) { 1823adfc5217SJeff Kirsher 1824adfc5217SJeff Kirsher priv->mii_bus = mdiobus_alloc(); 1825adfc5217SJeff Kirsher if (!priv->mii_bus) { 1826adfc5217SJeff Kirsher ret = -ENOMEM; 1827adfc5217SJeff Kirsher goto out_uninit_hw; 1828adfc5217SJeff Kirsher } 1829adfc5217SJeff Kirsher 1830adfc5217SJeff Kirsher bus = priv->mii_bus; 1831adfc5217SJeff Kirsher bus->name = "bcm63xx_enet MII bus"; 1832adfc5217SJeff Kirsher bus->parent = &pdev->dev; 1833adfc5217SJeff Kirsher bus->priv = priv; 1834adfc5217SJeff Kirsher bus->read = bcm_enet_mdio_read_phylib; 1835adfc5217SJeff Kirsher bus->write = bcm_enet_mdio_write_phylib; 18363e617506SFlorian Fainelli sprintf(bus->id, "%s-%d", pdev->name, priv->mac_id); 1837adfc5217SJeff Kirsher 1838adfc5217SJeff Kirsher /* only probe bus where we think the PHY is, because 1839adfc5217SJeff Kirsher * the mdio read operation return 0 instead of 0xffff 1840adfc5217SJeff Kirsher * if a slave is not present on hw */ 1841adfc5217SJeff Kirsher bus->phy_mask = ~(1 << priv->phy_id); 1842adfc5217SJeff Kirsher 1843adfc5217SJeff Kirsher if (priv->has_phy_interrupt) 1844adfc5217SJeff Kirsher bus->irq[priv->phy_id] = priv->phy_interrupt; 1845adfc5217SJeff Kirsher 1846adfc5217SJeff Kirsher ret = mdiobus_register(bus); 1847adfc5217SJeff Kirsher if (ret) { 1848adfc5217SJeff Kirsher dev_err(&pdev->dev, "unable to register mdio bus\n"); 1849adfc5217SJeff Kirsher goto out_free_mdio; 1850adfc5217SJeff Kirsher } 1851adfc5217SJeff Kirsher } else { 1852adfc5217SJeff Kirsher 1853adfc5217SJeff Kirsher /* run platform code to initialize PHY device */ 1854323b15b9Sxypron.glpk@gmx.de if (pd && pd->mii_config && 1855adfc5217SJeff Kirsher pd->mii_config(dev, 1, bcm_enet_mdio_read_mii, 1856adfc5217SJeff Kirsher bcm_enet_mdio_write_mii)) { 1857adfc5217SJeff Kirsher dev_err(&pdev->dev, "unable to configure mdio bus\n"); 1858adfc5217SJeff Kirsher goto out_uninit_hw; 1859adfc5217SJeff Kirsher } 1860adfc5217SJeff Kirsher } 1861adfc5217SJeff Kirsher 1862adfc5217SJeff Kirsher spin_lock_init(&priv->rx_lock); 1863adfc5217SJeff Kirsher 1864adfc5217SJeff Kirsher /* init rx timeout (used for oom) */ 1865c3bd81ccSAllen Pais setup_timer(&priv->rx_timeout, bcm_enet_refill_rx_timer, 1866c3bd81ccSAllen Pais (unsigned long)dev); 1867adfc5217SJeff Kirsher 1868adfc5217SJeff Kirsher /* init the mib update lock&work */ 1869adfc5217SJeff Kirsher mutex_init(&priv->mib_update_lock); 1870adfc5217SJeff Kirsher INIT_WORK(&priv->mib_update_task, bcm_enet_update_mib_counters_defer); 1871adfc5217SJeff Kirsher 1872adfc5217SJeff Kirsher /* zero mib counters */ 1873adfc5217SJeff Kirsher for (i = 0; i < ENET_MIB_REG_COUNT; i++) 1874adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_MIB_REG(i)); 1875adfc5217SJeff Kirsher 1876adfc5217SJeff Kirsher /* register netdevice */ 1877adfc5217SJeff Kirsher dev->netdev_ops = &bcm_enet_ops; 1878adfc5217SJeff Kirsher netif_napi_add(dev, &priv->napi, bcm_enet_poll, 16); 1879adfc5217SJeff Kirsher 18807ad24ea4SWilfried Klaebe dev->ethtool_ops = &bcm_enet_ethtool_ops; 1881e1c6dccaSJarod Wilson /* MTU range: 46 - 2028 */ 1882e1c6dccaSJarod Wilson dev->min_mtu = ETH_ZLEN - ETH_HLEN; 1883e1c6dccaSJarod Wilson dev->max_mtu = BCMENET_MAX_MTU - VLAN_ETH_HLEN; 1884adfc5217SJeff Kirsher SET_NETDEV_DEV(dev, &pdev->dev); 1885adfc5217SJeff Kirsher 1886adfc5217SJeff Kirsher ret = register_netdev(dev); 1887adfc5217SJeff Kirsher if (ret) 1888adfc5217SJeff Kirsher goto out_unregister_mdio; 1889adfc5217SJeff Kirsher 1890adfc5217SJeff Kirsher netif_carrier_off(dev); 1891adfc5217SJeff Kirsher platform_set_drvdata(pdev, dev); 1892adfc5217SJeff Kirsher priv->pdev = pdev; 1893adfc5217SJeff Kirsher priv->net_dev = dev; 1894adfc5217SJeff Kirsher 1895adfc5217SJeff Kirsher return 0; 1896adfc5217SJeff Kirsher 1897adfc5217SJeff Kirsher out_unregister_mdio: 18982a80b5e1SJonas Gorski if (priv->mii_bus) 1899adfc5217SJeff Kirsher mdiobus_unregister(priv->mii_bus); 1900adfc5217SJeff Kirsher 1901adfc5217SJeff Kirsher out_free_mdio: 1902adfc5217SJeff Kirsher if (priv->mii_bus) 1903adfc5217SJeff Kirsher mdiobus_free(priv->mii_bus); 1904adfc5217SJeff Kirsher 1905adfc5217SJeff Kirsher out_uninit_hw: 1906adfc5217SJeff Kirsher /* turn off mdc clock */ 1907adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_MIISC_REG); 19089c86b846SJonas Gorski if (priv->phy_clk) 1909624e2d21SJonas Gorski clk_disable_unprepare(priv->phy_clk); 1910adfc5217SJeff Kirsher 19119c86b846SJonas Gorski out_put_clk_phy: 19129c86b846SJonas Gorski if (priv->phy_clk) 19139c86b846SJonas Gorski clk_put(priv->phy_clk); 19149c86b846SJonas Gorski 19159c86b846SJonas Gorski out_disable_clk_mac: 1916624e2d21SJonas Gorski clk_disable_unprepare(priv->mac_clk); 19179c86b846SJonas Gorski out_put_clk_mac: 1918adfc5217SJeff Kirsher clk_put(priv->mac_clk); 1919adfc5217SJeff Kirsher out: 1920adfc5217SJeff Kirsher free_netdev(dev); 1921adfc5217SJeff Kirsher return ret; 1922adfc5217SJeff Kirsher } 1923adfc5217SJeff Kirsher 1924adfc5217SJeff Kirsher 1925adfc5217SJeff Kirsher /* 1926adfc5217SJeff Kirsher * exit func, stops hardware and unregisters netdevice 1927adfc5217SJeff Kirsher */ 1928047fc566SBill Pemberton static int bcm_enet_remove(struct platform_device *pdev) 1929adfc5217SJeff Kirsher { 1930adfc5217SJeff Kirsher struct bcm_enet_priv *priv; 1931adfc5217SJeff Kirsher struct net_device *dev; 1932adfc5217SJeff Kirsher 1933adfc5217SJeff Kirsher /* stop netdevice */ 1934adfc5217SJeff Kirsher dev = platform_get_drvdata(pdev); 1935adfc5217SJeff Kirsher priv = netdev_priv(dev); 1936adfc5217SJeff Kirsher unregister_netdev(dev); 1937adfc5217SJeff Kirsher 1938adfc5217SJeff Kirsher /* turn off mdc clock */ 1939adfc5217SJeff Kirsher enet_writel(priv, 0, ENET_MIISC_REG); 1940adfc5217SJeff Kirsher 1941adfc5217SJeff Kirsher if (priv->has_phy) { 1942adfc5217SJeff Kirsher mdiobus_unregister(priv->mii_bus); 1943adfc5217SJeff Kirsher mdiobus_free(priv->mii_bus); 1944adfc5217SJeff Kirsher } else { 1945adfc5217SJeff Kirsher struct bcm63xx_enet_platform_data *pd; 1946adfc5217SJeff Kirsher 1947cf0e7794SJingoo Han pd = dev_get_platdata(&pdev->dev); 1948adfc5217SJeff Kirsher if (pd && pd->mii_config) 1949adfc5217SJeff Kirsher pd->mii_config(dev, 0, bcm_enet_mdio_read_mii, 1950adfc5217SJeff Kirsher bcm_enet_mdio_write_mii); 1951adfc5217SJeff Kirsher } 1952adfc5217SJeff Kirsher 1953adfc5217SJeff Kirsher /* disable hw block clocks */ 1954adfc5217SJeff Kirsher if (priv->phy_clk) { 1955624e2d21SJonas Gorski clk_disable_unprepare(priv->phy_clk); 1956adfc5217SJeff Kirsher clk_put(priv->phy_clk); 1957adfc5217SJeff Kirsher } 1958624e2d21SJonas Gorski clk_disable_unprepare(priv->mac_clk); 1959adfc5217SJeff Kirsher clk_put(priv->mac_clk); 1960adfc5217SJeff Kirsher 1961adfc5217SJeff Kirsher free_netdev(dev); 1962adfc5217SJeff Kirsher return 0; 1963adfc5217SJeff Kirsher } 1964adfc5217SJeff Kirsher 1965adfc5217SJeff Kirsher struct platform_driver bcm63xx_enet_driver = { 1966adfc5217SJeff Kirsher .probe = bcm_enet_probe, 1967047fc566SBill Pemberton .remove = bcm_enet_remove, 1968adfc5217SJeff Kirsher .driver = { 1969adfc5217SJeff Kirsher .name = "bcm63xx_enet", 1970adfc5217SJeff Kirsher .owner = THIS_MODULE, 1971adfc5217SJeff Kirsher }, 1972adfc5217SJeff Kirsher }; 1973adfc5217SJeff Kirsher 1974adfc5217SJeff Kirsher /* 19756f00a022SMaxime Bizon * switch mii access callbacks 1976adfc5217SJeff Kirsher */ 19776f00a022SMaxime Bizon static int bcmenet_sw_mdio_read(struct bcm_enet_priv *priv, 19786f00a022SMaxime Bizon int ext, int phy_id, int location) 19796f00a022SMaxime Bizon { 19806f00a022SMaxime Bizon u32 reg; 19816f00a022SMaxime Bizon int ret; 19826f00a022SMaxime Bizon 19836f00a022SMaxime Bizon spin_lock_bh(&priv->enetsw_mdio_lock); 19846f00a022SMaxime Bizon enetsw_writel(priv, 0, ENETSW_MDIOC_REG); 19856f00a022SMaxime Bizon 19866f00a022SMaxime Bizon reg = ENETSW_MDIOC_RD_MASK | 19876f00a022SMaxime Bizon (phy_id << ENETSW_MDIOC_PHYID_SHIFT) | 19886f00a022SMaxime Bizon (location << ENETSW_MDIOC_REG_SHIFT); 19896f00a022SMaxime Bizon 19906f00a022SMaxime Bizon if (ext) 19916f00a022SMaxime Bizon reg |= ENETSW_MDIOC_EXT_MASK; 19926f00a022SMaxime Bizon 19936f00a022SMaxime Bizon enetsw_writel(priv, reg, ENETSW_MDIOC_REG); 19946f00a022SMaxime Bizon udelay(50); 19956f00a022SMaxime Bizon ret = enetsw_readw(priv, ENETSW_MDIOD_REG); 19966f00a022SMaxime Bizon spin_unlock_bh(&priv->enetsw_mdio_lock); 19976f00a022SMaxime Bizon return ret; 19986f00a022SMaxime Bizon } 19996f00a022SMaxime Bizon 20006f00a022SMaxime Bizon static void bcmenet_sw_mdio_write(struct bcm_enet_priv *priv, 20016f00a022SMaxime Bizon int ext, int phy_id, int location, 20026f00a022SMaxime Bizon uint16_t data) 20036f00a022SMaxime Bizon { 20046f00a022SMaxime Bizon u32 reg; 20056f00a022SMaxime Bizon 20066f00a022SMaxime Bizon spin_lock_bh(&priv->enetsw_mdio_lock); 20076f00a022SMaxime Bizon enetsw_writel(priv, 0, ENETSW_MDIOC_REG); 20086f00a022SMaxime Bizon 20096f00a022SMaxime Bizon reg = ENETSW_MDIOC_WR_MASK | 20106f00a022SMaxime Bizon (phy_id << ENETSW_MDIOC_PHYID_SHIFT) | 20116f00a022SMaxime Bizon (location << ENETSW_MDIOC_REG_SHIFT); 20126f00a022SMaxime Bizon 20136f00a022SMaxime Bizon if (ext) 20146f00a022SMaxime Bizon reg |= ENETSW_MDIOC_EXT_MASK; 20156f00a022SMaxime Bizon 20166f00a022SMaxime Bizon reg |= data; 20176f00a022SMaxime Bizon 20186f00a022SMaxime Bizon enetsw_writel(priv, reg, ENETSW_MDIOC_REG); 20196f00a022SMaxime Bizon udelay(50); 20206f00a022SMaxime Bizon spin_unlock_bh(&priv->enetsw_mdio_lock); 20216f00a022SMaxime Bizon } 20226f00a022SMaxime Bizon 20236f00a022SMaxime Bizon static inline int bcm_enet_port_is_rgmii(int portid) 20246f00a022SMaxime Bizon { 20256f00a022SMaxime Bizon return portid >= ENETSW_RGMII_PORT0; 20266f00a022SMaxime Bizon } 20276f00a022SMaxime Bizon 20286f00a022SMaxime Bizon /* 20296f00a022SMaxime Bizon * enet sw PHY polling 20306f00a022SMaxime Bizon */ 20316f00a022SMaxime Bizon static void swphy_poll_timer(unsigned long data) 20326f00a022SMaxime Bizon { 20336f00a022SMaxime Bizon struct bcm_enet_priv *priv = (struct bcm_enet_priv *)data; 20346f00a022SMaxime Bizon unsigned int i; 20356f00a022SMaxime Bizon 20366f00a022SMaxime Bizon for (i = 0; i < priv->num_ports; i++) { 20376f00a022SMaxime Bizon struct bcm63xx_enetsw_port *port; 2038aebd9947SSimon Arlott int val, j, up, advertise, lpa, speed, duplex, media; 20396f00a022SMaxime Bizon int external_phy = bcm_enet_port_is_rgmii(i); 20406f00a022SMaxime Bizon u8 override; 20416f00a022SMaxime Bizon 20426f00a022SMaxime Bizon port = &priv->used_ports[i]; 20436f00a022SMaxime Bizon if (!port->used) 20446f00a022SMaxime Bizon continue; 20456f00a022SMaxime Bizon 20466f00a022SMaxime Bizon if (port->bypass_link) 20476f00a022SMaxime Bizon continue; 20486f00a022SMaxime Bizon 20496f00a022SMaxime Bizon /* dummy read to clear */ 20506f00a022SMaxime Bizon for (j = 0; j < 2; j++) 20516f00a022SMaxime Bizon val = bcmenet_sw_mdio_read(priv, external_phy, 20526f00a022SMaxime Bizon port->phy_id, MII_BMSR); 20536f00a022SMaxime Bizon 20546f00a022SMaxime Bizon if (val == 0xffff) 20556f00a022SMaxime Bizon continue; 20566f00a022SMaxime Bizon 20576f00a022SMaxime Bizon up = (val & BMSR_LSTATUS) ? 1 : 0; 20586f00a022SMaxime Bizon if (!(up ^ priv->sw_port_link[i])) 20596f00a022SMaxime Bizon continue; 20606f00a022SMaxime Bizon 20616f00a022SMaxime Bizon priv->sw_port_link[i] = up; 20626f00a022SMaxime Bizon 20636f00a022SMaxime Bizon /* link changed */ 20646f00a022SMaxime Bizon if (!up) { 20656f00a022SMaxime Bizon dev_info(&priv->pdev->dev, "link DOWN on %s\n", 20666f00a022SMaxime Bizon port->name); 20676f00a022SMaxime Bizon enetsw_writeb(priv, ENETSW_PORTOV_ENABLE_MASK, 20686f00a022SMaxime Bizon ENETSW_PORTOV_REG(i)); 20696f00a022SMaxime Bizon enetsw_writeb(priv, ENETSW_PTCTRL_RXDIS_MASK | 20706f00a022SMaxime Bizon ENETSW_PTCTRL_TXDIS_MASK, 20716f00a022SMaxime Bizon ENETSW_PTCTRL_REG(i)); 20726f00a022SMaxime Bizon continue; 20736f00a022SMaxime Bizon } 20746f00a022SMaxime Bizon 20756f00a022SMaxime Bizon advertise = bcmenet_sw_mdio_read(priv, external_phy, 20766f00a022SMaxime Bizon port->phy_id, MII_ADVERTISE); 20776f00a022SMaxime Bizon 20786f00a022SMaxime Bizon lpa = bcmenet_sw_mdio_read(priv, external_phy, port->phy_id, 20796f00a022SMaxime Bizon MII_LPA); 20806f00a022SMaxime Bizon 20816f00a022SMaxime Bizon /* figure out media and duplex from advertise and LPA values */ 20826f00a022SMaxime Bizon media = mii_nway_result(lpa & advertise); 20836f00a022SMaxime Bizon duplex = (media & ADVERTISE_FULL) ? 1 : 0; 20846f00a022SMaxime Bizon 20856f00a022SMaxime Bizon if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) 20866f00a022SMaxime Bizon speed = 100; 20876f00a022SMaxime Bizon else 20886f00a022SMaxime Bizon speed = 10; 2089aebd9947SSimon Arlott 2090aebd9947SSimon Arlott if (val & BMSR_ESTATEN) { 2091aebd9947SSimon Arlott advertise = bcmenet_sw_mdio_read(priv, external_phy, 2092aebd9947SSimon Arlott port->phy_id, MII_CTRL1000); 2093aebd9947SSimon Arlott 2094aebd9947SSimon Arlott lpa = bcmenet_sw_mdio_read(priv, external_phy, 2095aebd9947SSimon Arlott port->phy_id, MII_STAT1000); 2096aebd9947SSimon Arlott 2097aebd9947SSimon Arlott if (advertise & (ADVERTISE_1000FULL | ADVERTISE_1000HALF) 2098aebd9947SSimon Arlott && lpa & (LPA_1000FULL | LPA_1000HALF)) { 2099aebd9947SSimon Arlott speed = 1000; 2100aebd9947SSimon Arlott duplex = (lpa & LPA_1000FULL); 2101aebd9947SSimon Arlott } 21026f00a022SMaxime Bizon } 21036f00a022SMaxime Bizon 21046f00a022SMaxime Bizon dev_info(&priv->pdev->dev, 21056f00a022SMaxime Bizon "link UP on %s, %dMbps, %s-duplex\n", 21066f00a022SMaxime Bizon port->name, speed, duplex ? "full" : "half"); 21076f00a022SMaxime Bizon 21086f00a022SMaxime Bizon override = ENETSW_PORTOV_ENABLE_MASK | 21096f00a022SMaxime Bizon ENETSW_PORTOV_LINKUP_MASK; 21106f00a022SMaxime Bizon 21116f00a022SMaxime Bizon if (speed == 1000) 21126f00a022SMaxime Bizon override |= ENETSW_IMPOV_1000_MASK; 21136f00a022SMaxime Bizon else if (speed == 100) 21146f00a022SMaxime Bizon override |= ENETSW_IMPOV_100_MASK; 21156f00a022SMaxime Bizon if (duplex) 21166f00a022SMaxime Bizon override |= ENETSW_IMPOV_FDX_MASK; 21176f00a022SMaxime Bizon 21186f00a022SMaxime Bizon enetsw_writeb(priv, override, ENETSW_PORTOV_REG(i)); 21196f00a022SMaxime Bizon enetsw_writeb(priv, 0, ENETSW_PTCTRL_REG(i)); 21206f00a022SMaxime Bizon } 21216f00a022SMaxime Bizon 21226f00a022SMaxime Bizon priv->swphy_poll.expires = jiffies + HZ; 21236f00a022SMaxime Bizon add_timer(&priv->swphy_poll); 21246f00a022SMaxime Bizon } 21256f00a022SMaxime Bizon 21266f00a022SMaxime Bizon /* 21276f00a022SMaxime Bizon * open callback, allocate dma rings & buffers and start rx operation 21286f00a022SMaxime Bizon */ 21296f00a022SMaxime Bizon static int bcm_enetsw_open(struct net_device *dev) 21306f00a022SMaxime Bizon { 21316f00a022SMaxime Bizon struct bcm_enet_priv *priv; 21326f00a022SMaxime Bizon struct device *kdev; 21336f00a022SMaxime Bizon int i, ret; 21346f00a022SMaxime Bizon unsigned int size; 21356f00a022SMaxime Bizon void *p; 21366f00a022SMaxime Bizon u32 val; 21376f00a022SMaxime Bizon 21386f00a022SMaxime Bizon priv = netdev_priv(dev); 21396f00a022SMaxime Bizon kdev = &priv->pdev->dev; 21406f00a022SMaxime Bizon 21416f00a022SMaxime Bizon /* mask all interrupts and request them */ 21423dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan); 21433dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan); 21446f00a022SMaxime Bizon 21456f00a022SMaxime Bizon ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, 2146df9f1b9fSMichael Opdenacker 0, dev->name, dev); 21476f00a022SMaxime Bizon if (ret) 21486f00a022SMaxime Bizon goto out_freeirq; 21496f00a022SMaxime Bizon 21506f00a022SMaxime Bizon if (priv->irq_tx != -1) { 21516f00a022SMaxime Bizon ret = request_irq(priv->irq_tx, bcm_enet_isr_dma, 2152df9f1b9fSMichael Opdenacker 0, dev->name, dev); 21536f00a022SMaxime Bizon if (ret) 21546f00a022SMaxime Bizon goto out_freeirq_rx; 21556f00a022SMaxime Bizon } 21566f00a022SMaxime Bizon 21576f00a022SMaxime Bizon /* allocate rx dma ring */ 21586f00a022SMaxime Bizon size = priv->rx_ring_size * sizeof(struct bcm_enet_desc); 21596f00a022SMaxime Bizon p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); 21606f00a022SMaxime Bizon if (!p) { 21616f00a022SMaxime Bizon dev_err(kdev, "cannot allocate rx ring %u\n", size); 21626f00a022SMaxime Bizon ret = -ENOMEM; 21636f00a022SMaxime Bizon goto out_freeirq_tx; 21646f00a022SMaxime Bizon } 21656f00a022SMaxime Bizon 21666f00a022SMaxime Bizon memset(p, 0, size); 21676f00a022SMaxime Bizon priv->rx_desc_alloc_size = size; 21686f00a022SMaxime Bizon priv->rx_desc_cpu = p; 21696f00a022SMaxime Bizon 21706f00a022SMaxime Bizon /* allocate tx dma ring */ 21716f00a022SMaxime Bizon size = priv->tx_ring_size * sizeof(struct bcm_enet_desc); 21726f00a022SMaxime Bizon p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); 21736f00a022SMaxime Bizon if (!p) { 21746f00a022SMaxime Bizon dev_err(kdev, "cannot allocate tx ring\n"); 21756f00a022SMaxime Bizon ret = -ENOMEM; 21766f00a022SMaxime Bizon goto out_free_rx_ring; 21776f00a022SMaxime Bizon } 21786f00a022SMaxime Bizon 21796f00a022SMaxime Bizon memset(p, 0, size); 21806f00a022SMaxime Bizon priv->tx_desc_alloc_size = size; 21816f00a022SMaxime Bizon priv->tx_desc_cpu = p; 21826f00a022SMaxime Bizon 21836f00a022SMaxime Bizon priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size, 21846f00a022SMaxime Bizon GFP_KERNEL); 21856f00a022SMaxime Bizon if (!priv->tx_skb) { 21866f00a022SMaxime Bizon dev_err(kdev, "cannot allocate rx skb queue\n"); 21876f00a022SMaxime Bizon ret = -ENOMEM; 21886f00a022SMaxime Bizon goto out_free_tx_ring; 21896f00a022SMaxime Bizon } 21906f00a022SMaxime Bizon 21916f00a022SMaxime Bizon priv->tx_desc_count = priv->tx_ring_size; 21926f00a022SMaxime Bizon priv->tx_dirty_desc = 0; 21936f00a022SMaxime Bizon priv->tx_curr_desc = 0; 21946f00a022SMaxime Bizon spin_lock_init(&priv->tx_lock); 21956f00a022SMaxime Bizon 21966f00a022SMaxime Bizon /* init & fill rx ring with skbs */ 21976f00a022SMaxime Bizon priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size, 21986f00a022SMaxime Bizon GFP_KERNEL); 21996f00a022SMaxime Bizon if (!priv->rx_skb) { 22006f00a022SMaxime Bizon dev_err(kdev, "cannot allocate rx skb queue\n"); 22016f00a022SMaxime Bizon ret = -ENOMEM; 22026f00a022SMaxime Bizon goto out_free_tx_skb; 22036f00a022SMaxime Bizon } 22046f00a022SMaxime Bizon 22056f00a022SMaxime Bizon priv->rx_desc_count = 0; 22066f00a022SMaxime Bizon priv->rx_dirty_desc = 0; 22076f00a022SMaxime Bizon priv->rx_curr_desc = 0; 22086f00a022SMaxime Bizon 22096f00a022SMaxime Bizon /* disable all ports */ 22106f00a022SMaxime Bizon for (i = 0; i < priv->num_ports; i++) { 22116f00a022SMaxime Bizon enetsw_writeb(priv, ENETSW_PORTOV_ENABLE_MASK, 22126f00a022SMaxime Bizon ENETSW_PORTOV_REG(i)); 22136f00a022SMaxime Bizon enetsw_writeb(priv, ENETSW_PTCTRL_RXDIS_MASK | 22146f00a022SMaxime Bizon ENETSW_PTCTRL_TXDIS_MASK, 22156f00a022SMaxime Bizon ENETSW_PTCTRL_REG(i)); 22166f00a022SMaxime Bizon 22176f00a022SMaxime Bizon priv->sw_port_link[i] = 0; 22186f00a022SMaxime Bizon } 22196f00a022SMaxime Bizon 22206f00a022SMaxime Bizon /* reset mib */ 22216f00a022SMaxime Bizon val = enetsw_readb(priv, ENETSW_GMCR_REG); 22226f00a022SMaxime Bizon val |= ENETSW_GMCR_RST_MIB_MASK; 22236f00a022SMaxime Bizon enetsw_writeb(priv, val, ENETSW_GMCR_REG); 22246f00a022SMaxime Bizon mdelay(1); 22256f00a022SMaxime Bizon val &= ~ENETSW_GMCR_RST_MIB_MASK; 22266f00a022SMaxime Bizon enetsw_writeb(priv, val, ENETSW_GMCR_REG); 22276f00a022SMaxime Bizon mdelay(1); 22286f00a022SMaxime Bizon 22296f00a022SMaxime Bizon /* force CPU port state */ 22306f00a022SMaxime Bizon val = enetsw_readb(priv, ENETSW_IMPOV_REG); 22316f00a022SMaxime Bizon val |= ENETSW_IMPOV_FORCE_MASK | ENETSW_IMPOV_LINKUP_MASK; 22326f00a022SMaxime Bizon enetsw_writeb(priv, val, ENETSW_IMPOV_REG); 22336f00a022SMaxime Bizon 22346f00a022SMaxime Bizon /* enable switch forward engine */ 22356f00a022SMaxime Bizon val = enetsw_readb(priv, ENETSW_SWMODE_REG); 22366f00a022SMaxime Bizon val |= ENETSW_SWMODE_FWD_EN_MASK; 22376f00a022SMaxime Bizon enetsw_writeb(priv, val, ENETSW_SWMODE_REG); 22386f00a022SMaxime Bizon 22396f00a022SMaxime Bizon /* enable jumbo on all ports */ 22406f00a022SMaxime Bizon enetsw_writel(priv, 0x1ff, ENETSW_JMBCTL_PORT_REG); 22416f00a022SMaxime Bizon enetsw_writew(priv, 9728, ENETSW_JMBCTL_MAXSIZE_REG); 22426f00a022SMaxime Bizon 22436f00a022SMaxime Bizon /* initialize flow control buffer allocation */ 22446f00a022SMaxime Bizon enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, 22456f00a022SMaxime Bizon ENETDMA_BUFALLOC_REG(priv->rx_chan)); 22466f00a022SMaxime Bizon 22476f00a022SMaxime Bizon if (bcm_enet_refill_rx(dev)) { 22486f00a022SMaxime Bizon dev_err(kdev, "cannot allocate rx skb queue\n"); 22496f00a022SMaxime Bizon ret = -ENOMEM; 22506f00a022SMaxime Bizon goto out; 22516f00a022SMaxime Bizon } 22526f00a022SMaxime Bizon 22536f00a022SMaxime Bizon /* write rx & tx ring addresses */ 22546f00a022SMaxime Bizon enet_dmas_writel(priv, priv->rx_desc_dma, 22553dc6475cSFlorian Fainelli ENETDMAS_RSTART_REG, priv->rx_chan); 22566f00a022SMaxime Bizon enet_dmas_writel(priv, priv->tx_desc_dma, 22573dc6475cSFlorian Fainelli ENETDMAS_RSTART_REG, priv->tx_chan); 22586f00a022SMaxime Bizon 22596f00a022SMaxime Bizon /* clear remaining state ram for rx & tx channel */ 22603dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->rx_chan); 22613dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->tx_chan); 22623dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->rx_chan); 22633dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->tx_chan); 22643dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->rx_chan); 22653dc6475cSFlorian Fainelli enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->tx_chan); 22666f00a022SMaxime Bizon 22676f00a022SMaxime Bizon /* set dma maximum burst len */ 22686f00a022SMaxime Bizon enet_dmac_writel(priv, priv->dma_maxburst, 22693dc6475cSFlorian Fainelli ENETDMAC_MAXBURST, priv->rx_chan); 22706f00a022SMaxime Bizon enet_dmac_writel(priv, priv->dma_maxburst, 22713dc6475cSFlorian Fainelli ENETDMAC_MAXBURST, priv->tx_chan); 22726f00a022SMaxime Bizon 22736f00a022SMaxime Bizon /* set flow control low/high threshold to 1/3 / 2/3 */ 22746f00a022SMaxime Bizon val = priv->rx_ring_size / 3; 22756f00a022SMaxime Bizon enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan)); 22766f00a022SMaxime Bizon val = (priv->rx_ring_size * 2) / 3; 22776f00a022SMaxime Bizon enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan)); 22786f00a022SMaxime Bizon 22796f00a022SMaxime Bizon /* all set, enable mac and interrupts, start dma engine and 22806f00a022SMaxime Bizon * kick rx dma channel 22816f00a022SMaxime Bizon */ 22826f00a022SMaxime Bizon wmb(); 22836f00a022SMaxime Bizon enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); 22846f00a022SMaxime Bizon enet_dmac_writel(priv, ENETDMAC_CHANCFG_EN_MASK, 22853dc6475cSFlorian Fainelli ENETDMAC_CHANCFG, priv->rx_chan); 22866f00a022SMaxime Bizon 22876f00a022SMaxime Bizon /* watch "packet transferred" interrupt in rx and tx */ 22886f00a022SMaxime Bizon enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, 22893dc6475cSFlorian Fainelli ENETDMAC_IR, priv->rx_chan); 22906f00a022SMaxime Bizon enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, 22913dc6475cSFlorian Fainelli ENETDMAC_IR, priv->tx_chan); 22926f00a022SMaxime Bizon 22936f00a022SMaxime Bizon /* make sure we enable napi before rx interrupt */ 22946f00a022SMaxime Bizon napi_enable(&priv->napi); 22956f00a022SMaxime Bizon 22966f00a022SMaxime Bizon enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, 22973dc6475cSFlorian Fainelli ENETDMAC_IRMASK, priv->rx_chan); 22986f00a022SMaxime Bizon enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, 22993dc6475cSFlorian Fainelli ENETDMAC_IRMASK, priv->tx_chan); 23006f00a022SMaxime Bizon 23016f00a022SMaxime Bizon netif_carrier_on(dev); 23026f00a022SMaxime Bizon netif_start_queue(dev); 23036f00a022SMaxime Bizon 23046f00a022SMaxime Bizon /* apply override config for bypass_link ports here. */ 23056f00a022SMaxime Bizon for (i = 0; i < priv->num_ports; i++) { 23066f00a022SMaxime Bizon struct bcm63xx_enetsw_port *port; 23076f00a022SMaxime Bizon u8 override; 23086f00a022SMaxime Bizon port = &priv->used_ports[i]; 23096f00a022SMaxime Bizon if (!port->used) 23106f00a022SMaxime Bizon continue; 23116f00a022SMaxime Bizon 23126f00a022SMaxime Bizon if (!port->bypass_link) 23136f00a022SMaxime Bizon continue; 23146f00a022SMaxime Bizon 23156f00a022SMaxime Bizon override = ENETSW_PORTOV_ENABLE_MASK | 23166f00a022SMaxime Bizon ENETSW_PORTOV_LINKUP_MASK; 23176f00a022SMaxime Bizon 23186f00a022SMaxime Bizon switch (port->force_speed) { 23196f00a022SMaxime Bizon case 1000: 23206f00a022SMaxime Bizon override |= ENETSW_IMPOV_1000_MASK; 23216f00a022SMaxime Bizon break; 23226f00a022SMaxime Bizon case 100: 23236f00a022SMaxime Bizon override |= ENETSW_IMPOV_100_MASK; 23246f00a022SMaxime Bizon break; 23256f00a022SMaxime Bizon case 10: 23266f00a022SMaxime Bizon break; 23276f00a022SMaxime Bizon default: 23286f00a022SMaxime Bizon pr_warn("invalid forced speed on port %s: assume 10\n", 23296f00a022SMaxime Bizon port->name); 23306f00a022SMaxime Bizon break; 23316f00a022SMaxime Bizon } 23326f00a022SMaxime Bizon 23336f00a022SMaxime Bizon if (port->force_duplex_full) 23346f00a022SMaxime Bizon override |= ENETSW_IMPOV_FDX_MASK; 23356f00a022SMaxime Bizon 23366f00a022SMaxime Bizon 23376f00a022SMaxime Bizon enetsw_writeb(priv, override, ENETSW_PORTOV_REG(i)); 23386f00a022SMaxime Bizon enetsw_writeb(priv, 0, ENETSW_PTCTRL_REG(i)); 23396f00a022SMaxime Bizon } 23406f00a022SMaxime Bizon 23416f00a022SMaxime Bizon /* start phy polling timer */ 23423bd3b9edSHimanshu Jha setup_timer(&priv->swphy_poll, swphy_poll_timer, (unsigned long)priv); 23433bd3b9edSHimanshu Jha mod_timer(&priv->swphy_poll, jiffies); 23446f00a022SMaxime Bizon return 0; 23456f00a022SMaxime Bizon 23466f00a022SMaxime Bizon out: 23476f00a022SMaxime Bizon for (i = 0; i < priv->rx_ring_size; i++) { 23486f00a022SMaxime Bizon struct bcm_enet_desc *desc; 23496f00a022SMaxime Bizon 23506f00a022SMaxime Bizon if (!priv->rx_skb[i]) 23516f00a022SMaxime Bizon continue; 23526f00a022SMaxime Bizon 23536f00a022SMaxime Bizon desc = &priv->rx_desc_cpu[i]; 23546f00a022SMaxime Bizon dma_unmap_single(kdev, desc->address, priv->rx_skb_size, 23556f00a022SMaxime Bizon DMA_FROM_DEVICE); 23566f00a022SMaxime Bizon kfree_skb(priv->rx_skb[i]); 23576f00a022SMaxime Bizon } 23586f00a022SMaxime Bizon kfree(priv->rx_skb); 23596f00a022SMaxime Bizon 23606f00a022SMaxime Bizon out_free_tx_skb: 23616f00a022SMaxime Bizon kfree(priv->tx_skb); 23626f00a022SMaxime Bizon 23636f00a022SMaxime Bizon out_free_tx_ring: 23646f00a022SMaxime Bizon dma_free_coherent(kdev, priv->tx_desc_alloc_size, 23656f00a022SMaxime Bizon priv->tx_desc_cpu, priv->tx_desc_dma); 23666f00a022SMaxime Bizon 23676f00a022SMaxime Bizon out_free_rx_ring: 23686f00a022SMaxime Bizon dma_free_coherent(kdev, priv->rx_desc_alloc_size, 23696f00a022SMaxime Bizon priv->rx_desc_cpu, priv->rx_desc_dma); 23706f00a022SMaxime Bizon 23716f00a022SMaxime Bizon out_freeirq_tx: 23726f00a022SMaxime Bizon if (priv->irq_tx != -1) 23736f00a022SMaxime Bizon free_irq(priv->irq_tx, dev); 23746f00a022SMaxime Bizon 23756f00a022SMaxime Bizon out_freeirq_rx: 23766f00a022SMaxime Bizon free_irq(priv->irq_rx, dev); 23776f00a022SMaxime Bizon 23786f00a022SMaxime Bizon out_freeirq: 23796f00a022SMaxime Bizon return ret; 23806f00a022SMaxime Bizon } 23816f00a022SMaxime Bizon 23826f00a022SMaxime Bizon /* stop callback */ 23836f00a022SMaxime Bizon static int bcm_enetsw_stop(struct net_device *dev) 23846f00a022SMaxime Bizon { 23856f00a022SMaxime Bizon struct bcm_enet_priv *priv; 23866f00a022SMaxime Bizon struct device *kdev; 23876f00a022SMaxime Bizon int i; 23886f00a022SMaxime Bizon 23896f00a022SMaxime Bizon priv = netdev_priv(dev); 23906f00a022SMaxime Bizon kdev = &priv->pdev->dev; 23916f00a022SMaxime Bizon 23926f00a022SMaxime Bizon del_timer_sync(&priv->swphy_poll); 23936f00a022SMaxime Bizon netif_stop_queue(dev); 23946f00a022SMaxime Bizon napi_disable(&priv->napi); 23956f00a022SMaxime Bizon del_timer_sync(&priv->rx_timeout); 23966f00a022SMaxime Bizon 23976f00a022SMaxime Bizon /* mask all interrupts */ 23983dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan); 23993dc6475cSFlorian Fainelli enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan); 24006f00a022SMaxime Bizon 24016f00a022SMaxime Bizon /* disable dma & mac */ 24026f00a022SMaxime Bizon bcm_enet_disable_dma(priv, priv->tx_chan); 24036f00a022SMaxime Bizon bcm_enet_disable_dma(priv, priv->rx_chan); 24046f00a022SMaxime Bizon 24056f00a022SMaxime Bizon /* force reclaim of all tx buffers */ 24066f00a022SMaxime Bizon bcm_enet_tx_reclaim(dev, 1); 24076f00a022SMaxime Bizon 24086f00a022SMaxime Bizon /* free the rx skb ring */ 24096f00a022SMaxime Bizon for (i = 0; i < priv->rx_ring_size; i++) { 24106f00a022SMaxime Bizon struct bcm_enet_desc *desc; 24116f00a022SMaxime Bizon 24126f00a022SMaxime Bizon if (!priv->rx_skb[i]) 24136f00a022SMaxime Bizon continue; 24146f00a022SMaxime Bizon 24156f00a022SMaxime Bizon desc = &priv->rx_desc_cpu[i]; 24166f00a022SMaxime Bizon dma_unmap_single(kdev, desc->address, priv->rx_skb_size, 24176f00a022SMaxime Bizon DMA_FROM_DEVICE); 24186f00a022SMaxime Bizon kfree_skb(priv->rx_skb[i]); 24196f00a022SMaxime Bizon } 24206f00a022SMaxime Bizon 24216f00a022SMaxime Bizon /* free remaining allocated memory */ 24226f00a022SMaxime Bizon kfree(priv->rx_skb); 24236f00a022SMaxime Bizon kfree(priv->tx_skb); 24246f00a022SMaxime Bizon dma_free_coherent(kdev, priv->rx_desc_alloc_size, 24256f00a022SMaxime Bizon priv->rx_desc_cpu, priv->rx_desc_dma); 24266f00a022SMaxime Bizon dma_free_coherent(kdev, priv->tx_desc_alloc_size, 24276f00a022SMaxime Bizon priv->tx_desc_cpu, priv->tx_desc_dma); 24286f00a022SMaxime Bizon if (priv->irq_tx != -1) 24296f00a022SMaxime Bizon free_irq(priv->irq_tx, dev); 24306f00a022SMaxime Bizon free_irq(priv->irq_rx, dev); 24316f00a022SMaxime Bizon 24326f00a022SMaxime Bizon return 0; 24336f00a022SMaxime Bizon } 24346f00a022SMaxime Bizon 24356f00a022SMaxime Bizon /* try to sort out phy external status by walking the used_port field 24366f00a022SMaxime Bizon * in the bcm_enet_priv structure. in case the phy address is not 24376f00a022SMaxime Bizon * assigned to any physical port on the switch, assume it is external 24386f00a022SMaxime Bizon * (and yell at the user). 24396f00a022SMaxime Bizon */ 24406f00a022SMaxime Bizon static int bcm_enetsw_phy_is_external(struct bcm_enet_priv *priv, int phy_id) 24416f00a022SMaxime Bizon { 24426f00a022SMaxime Bizon int i; 24436f00a022SMaxime Bizon 24446f00a022SMaxime Bizon for (i = 0; i < priv->num_ports; ++i) { 24456f00a022SMaxime Bizon if (!priv->used_ports[i].used) 24466f00a022SMaxime Bizon continue; 24476f00a022SMaxime Bizon if (priv->used_ports[i].phy_id == phy_id) 24486f00a022SMaxime Bizon return bcm_enet_port_is_rgmii(i); 24496f00a022SMaxime Bizon } 24506f00a022SMaxime Bizon 24516f00a022SMaxime Bizon printk_once(KERN_WARNING "bcm63xx_enet: could not find a used port with phy_id %i, assuming phy is external\n", 24526f00a022SMaxime Bizon phy_id); 24536f00a022SMaxime Bizon return 1; 24546f00a022SMaxime Bizon } 24556f00a022SMaxime Bizon 24566f00a022SMaxime Bizon /* can't use bcmenet_sw_mdio_read directly as we need to sort out 24576f00a022SMaxime Bizon * external/internal status of the given phy_id first. 24586f00a022SMaxime Bizon */ 24596f00a022SMaxime Bizon static int bcm_enetsw_mii_mdio_read(struct net_device *dev, int phy_id, 24606f00a022SMaxime Bizon int location) 24616f00a022SMaxime Bizon { 24626f00a022SMaxime Bizon struct bcm_enet_priv *priv; 24636f00a022SMaxime Bizon 24646f00a022SMaxime Bizon priv = netdev_priv(dev); 24656f00a022SMaxime Bizon return bcmenet_sw_mdio_read(priv, 24666f00a022SMaxime Bizon bcm_enetsw_phy_is_external(priv, phy_id), 24676f00a022SMaxime Bizon phy_id, location); 24686f00a022SMaxime Bizon } 24696f00a022SMaxime Bizon 24706f00a022SMaxime Bizon /* can't use bcmenet_sw_mdio_write directly as we need to sort out 24716f00a022SMaxime Bizon * external/internal status of the given phy_id first. 24726f00a022SMaxime Bizon */ 24736f00a022SMaxime Bizon static void bcm_enetsw_mii_mdio_write(struct net_device *dev, int phy_id, 24746f00a022SMaxime Bizon int location, 24756f00a022SMaxime Bizon int val) 24766f00a022SMaxime Bizon { 24776f00a022SMaxime Bizon struct bcm_enet_priv *priv; 24786f00a022SMaxime Bizon 24796f00a022SMaxime Bizon priv = netdev_priv(dev); 24806f00a022SMaxime Bizon bcmenet_sw_mdio_write(priv, bcm_enetsw_phy_is_external(priv, phy_id), 24816f00a022SMaxime Bizon phy_id, location, val); 24826f00a022SMaxime Bizon } 24836f00a022SMaxime Bizon 24846f00a022SMaxime Bizon static int bcm_enetsw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 24856f00a022SMaxime Bizon { 24866f00a022SMaxime Bizon struct mii_if_info mii; 24876f00a022SMaxime Bizon 24886f00a022SMaxime Bizon mii.dev = dev; 24896f00a022SMaxime Bizon mii.mdio_read = bcm_enetsw_mii_mdio_read; 24906f00a022SMaxime Bizon mii.mdio_write = bcm_enetsw_mii_mdio_write; 24916f00a022SMaxime Bizon mii.phy_id = 0; 24926f00a022SMaxime Bizon mii.phy_id_mask = 0x3f; 24936f00a022SMaxime Bizon mii.reg_num_mask = 0x1f; 24946f00a022SMaxime Bizon return generic_mii_ioctl(&mii, if_mii(rq), cmd, NULL); 24956f00a022SMaxime Bizon 24966f00a022SMaxime Bizon } 24976f00a022SMaxime Bizon 24986f00a022SMaxime Bizon static const struct net_device_ops bcm_enetsw_ops = { 24996f00a022SMaxime Bizon .ndo_open = bcm_enetsw_open, 25006f00a022SMaxime Bizon .ndo_stop = bcm_enetsw_stop, 25016f00a022SMaxime Bizon .ndo_start_xmit = bcm_enet_start_xmit, 25026f00a022SMaxime Bizon .ndo_change_mtu = bcm_enet_change_mtu, 25036f00a022SMaxime Bizon .ndo_do_ioctl = bcm_enetsw_ioctl, 25046f00a022SMaxime Bizon }; 25056f00a022SMaxime Bizon 25066f00a022SMaxime Bizon 25076f00a022SMaxime Bizon static const struct bcm_enet_stats bcm_enetsw_gstrings_stats[] = { 25086f00a022SMaxime Bizon { "rx_packets", DEV_STAT(rx_packets), -1 }, 25096f00a022SMaxime Bizon { "tx_packets", DEV_STAT(tx_packets), -1 }, 25106f00a022SMaxime Bizon { "rx_bytes", DEV_STAT(rx_bytes), -1 }, 25116f00a022SMaxime Bizon { "tx_bytes", DEV_STAT(tx_bytes), -1 }, 25126f00a022SMaxime Bizon { "rx_errors", DEV_STAT(rx_errors), -1 }, 25136f00a022SMaxime Bizon { "tx_errors", DEV_STAT(tx_errors), -1 }, 25146f00a022SMaxime Bizon { "rx_dropped", DEV_STAT(rx_dropped), -1 }, 25156f00a022SMaxime Bizon { "tx_dropped", DEV_STAT(tx_dropped), -1 }, 25166f00a022SMaxime Bizon 25176f00a022SMaxime Bizon { "tx_good_octets", GEN_STAT(mib.tx_gd_octets), ETHSW_MIB_RX_GD_OCT }, 25186f00a022SMaxime Bizon { "tx_unicast", GEN_STAT(mib.tx_unicast), ETHSW_MIB_RX_BRDCAST }, 25196f00a022SMaxime Bizon { "tx_broadcast", GEN_STAT(mib.tx_brdcast), ETHSW_MIB_RX_BRDCAST }, 25206f00a022SMaxime Bizon { "tx_multicast", GEN_STAT(mib.tx_mult), ETHSW_MIB_RX_MULT }, 25216f00a022SMaxime Bizon { "tx_64_octets", GEN_STAT(mib.tx_64), ETHSW_MIB_RX_64 }, 25226f00a022SMaxime Bizon { "tx_65_127_oct", GEN_STAT(mib.tx_65_127), ETHSW_MIB_RX_65_127 }, 25236f00a022SMaxime Bizon { "tx_128_255_oct", GEN_STAT(mib.tx_128_255), ETHSW_MIB_RX_128_255 }, 25246f00a022SMaxime Bizon { "tx_256_511_oct", GEN_STAT(mib.tx_256_511), ETHSW_MIB_RX_256_511 }, 25256f00a022SMaxime Bizon { "tx_512_1023_oct", GEN_STAT(mib.tx_512_1023), ETHSW_MIB_RX_512_1023}, 25266f00a022SMaxime Bizon { "tx_1024_1522_oct", GEN_STAT(mib.tx_1024_max), 25276f00a022SMaxime Bizon ETHSW_MIB_RX_1024_1522 }, 25286f00a022SMaxime Bizon { "tx_1523_2047_oct", GEN_STAT(mib.tx_1523_2047), 25296f00a022SMaxime Bizon ETHSW_MIB_RX_1523_2047 }, 25306f00a022SMaxime Bizon { "tx_2048_4095_oct", GEN_STAT(mib.tx_2048_4095), 25316f00a022SMaxime Bizon ETHSW_MIB_RX_2048_4095 }, 25326f00a022SMaxime Bizon { "tx_4096_8191_oct", GEN_STAT(mib.tx_4096_8191), 25336f00a022SMaxime Bizon ETHSW_MIB_RX_4096_8191 }, 25346f00a022SMaxime Bizon { "tx_8192_9728_oct", GEN_STAT(mib.tx_8192_9728), 25356f00a022SMaxime Bizon ETHSW_MIB_RX_8192_9728 }, 25366f00a022SMaxime Bizon { "tx_oversize", GEN_STAT(mib.tx_ovr), ETHSW_MIB_RX_OVR }, 25376f00a022SMaxime Bizon { "tx_oversize_drop", GEN_STAT(mib.tx_ovr), ETHSW_MIB_RX_OVR_DISC }, 25386f00a022SMaxime Bizon { "tx_dropped", GEN_STAT(mib.tx_drop), ETHSW_MIB_RX_DROP }, 25396f00a022SMaxime Bizon { "tx_undersize", GEN_STAT(mib.tx_underrun), ETHSW_MIB_RX_UND }, 25406f00a022SMaxime Bizon { "tx_pause", GEN_STAT(mib.tx_pause), ETHSW_MIB_RX_PAUSE }, 25416f00a022SMaxime Bizon 25426f00a022SMaxime Bizon { "rx_good_octets", GEN_STAT(mib.rx_gd_octets), ETHSW_MIB_TX_ALL_OCT }, 25436f00a022SMaxime Bizon { "rx_broadcast", GEN_STAT(mib.rx_brdcast), ETHSW_MIB_TX_BRDCAST }, 25446f00a022SMaxime Bizon { "rx_multicast", GEN_STAT(mib.rx_mult), ETHSW_MIB_TX_MULT }, 25456f00a022SMaxime Bizon { "rx_unicast", GEN_STAT(mib.rx_unicast), ETHSW_MIB_TX_MULT }, 25466f00a022SMaxime Bizon { "rx_pause", GEN_STAT(mib.rx_pause), ETHSW_MIB_TX_PAUSE }, 25476f00a022SMaxime Bizon { "rx_dropped", GEN_STAT(mib.rx_drop), ETHSW_MIB_TX_DROP_PKTS }, 25486f00a022SMaxime Bizon 25496f00a022SMaxime Bizon }; 25506f00a022SMaxime Bizon 25516f00a022SMaxime Bizon #define BCM_ENETSW_STATS_LEN \ 25526f00a022SMaxime Bizon (sizeof(bcm_enetsw_gstrings_stats) / sizeof(struct bcm_enet_stats)) 25536f00a022SMaxime Bizon 25546f00a022SMaxime Bizon static void bcm_enetsw_get_strings(struct net_device *netdev, 25556f00a022SMaxime Bizon u32 stringset, u8 *data) 25566f00a022SMaxime Bizon { 25576f00a022SMaxime Bizon int i; 25586f00a022SMaxime Bizon 25596f00a022SMaxime Bizon switch (stringset) { 25606f00a022SMaxime Bizon case ETH_SS_STATS: 25616f00a022SMaxime Bizon for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) { 25626f00a022SMaxime Bizon memcpy(data + i * ETH_GSTRING_LEN, 25636f00a022SMaxime Bizon bcm_enetsw_gstrings_stats[i].stat_string, 25646f00a022SMaxime Bizon ETH_GSTRING_LEN); 25656f00a022SMaxime Bizon } 25666f00a022SMaxime Bizon break; 25676f00a022SMaxime Bizon } 25686f00a022SMaxime Bizon } 25696f00a022SMaxime Bizon 25706f00a022SMaxime Bizon static int bcm_enetsw_get_sset_count(struct net_device *netdev, 25716f00a022SMaxime Bizon int string_set) 25726f00a022SMaxime Bizon { 25736f00a022SMaxime Bizon switch (string_set) { 25746f00a022SMaxime Bizon case ETH_SS_STATS: 25756f00a022SMaxime Bizon return BCM_ENETSW_STATS_LEN; 25766f00a022SMaxime Bizon default: 25776f00a022SMaxime Bizon return -EINVAL; 25786f00a022SMaxime Bizon } 25796f00a022SMaxime Bizon } 25806f00a022SMaxime Bizon 25816f00a022SMaxime Bizon static void bcm_enetsw_get_drvinfo(struct net_device *netdev, 25826f00a022SMaxime Bizon struct ethtool_drvinfo *drvinfo) 25836f00a022SMaxime Bizon { 25846f00a022SMaxime Bizon strncpy(drvinfo->driver, bcm_enet_driver_name, 32); 25856f00a022SMaxime Bizon strncpy(drvinfo->version, bcm_enet_driver_version, 32); 25866f00a022SMaxime Bizon strncpy(drvinfo->fw_version, "N/A", 32); 25876f00a022SMaxime Bizon strncpy(drvinfo->bus_info, "bcm63xx", 32); 25886f00a022SMaxime Bizon } 25896f00a022SMaxime Bizon 25906f00a022SMaxime Bizon static void bcm_enetsw_get_ethtool_stats(struct net_device *netdev, 25916f00a022SMaxime Bizon struct ethtool_stats *stats, 25926f00a022SMaxime Bizon u64 *data) 25936f00a022SMaxime Bizon { 25946f00a022SMaxime Bizon struct bcm_enet_priv *priv; 25956f00a022SMaxime Bizon int i; 25966f00a022SMaxime Bizon 25976f00a022SMaxime Bizon priv = netdev_priv(netdev); 25986f00a022SMaxime Bizon 25996f00a022SMaxime Bizon for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) { 26006f00a022SMaxime Bizon const struct bcm_enet_stats *s; 26016f00a022SMaxime Bizon u32 lo, hi; 26026f00a022SMaxime Bizon char *p; 26036f00a022SMaxime Bizon int reg; 26046f00a022SMaxime Bizon 26056f00a022SMaxime Bizon s = &bcm_enetsw_gstrings_stats[i]; 26066f00a022SMaxime Bizon 26076f00a022SMaxime Bizon reg = s->mib_reg; 26086f00a022SMaxime Bizon if (reg == -1) 26096f00a022SMaxime Bizon continue; 26106f00a022SMaxime Bizon 26116f00a022SMaxime Bizon lo = enetsw_readl(priv, ENETSW_MIB_REG(reg)); 26126f00a022SMaxime Bizon p = (char *)priv + s->stat_offset; 26136f00a022SMaxime Bizon 26146f00a022SMaxime Bizon if (s->sizeof_stat == sizeof(u64)) { 26156f00a022SMaxime Bizon hi = enetsw_readl(priv, ENETSW_MIB_REG(reg + 1)); 26166f00a022SMaxime Bizon *(u64 *)p = ((u64)hi << 32 | lo); 26176f00a022SMaxime Bizon } else { 26186f00a022SMaxime Bizon *(u32 *)p = lo; 26196f00a022SMaxime Bizon } 26206f00a022SMaxime Bizon } 26216f00a022SMaxime Bizon 26226f00a022SMaxime Bizon for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) { 26236f00a022SMaxime Bizon const struct bcm_enet_stats *s; 26246f00a022SMaxime Bizon char *p; 26256f00a022SMaxime Bizon 26266f00a022SMaxime Bizon s = &bcm_enetsw_gstrings_stats[i]; 26276f00a022SMaxime Bizon 26286f00a022SMaxime Bizon if (s->mib_reg == -1) 26296f00a022SMaxime Bizon p = (char *)&netdev->stats + s->stat_offset; 26306f00a022SMaxime Bizon else 26316f00a022SMaxime Bizon p = (char *)priv + s->stat_offset; 26326f00a022SMaxime Bizon 26336f00a022SMaxime Bizon data[i] = (s->sizeof_stat == sizeof(u64)) ? 26346f00a022SMaxime Bizon *(u64 *)p : *(u32 *)p; 26356f00a022SMaxime Bizon } 26366f00a022SMaxime Bizon } 26376f00a022SMaxime Bizon 26386f00a022SMaxime Bizon static void bcm_enetsw_get_ringparam(struct net_device *dev, 26396f00a022SMaxime Bizon struct ethtool_ringparam *ering) 26406f00a022SMaxime Bizon { 26416f00a022SMaxime Bizon struct bcm_enet_priv *priv; 26426f00a022SMaxime Bizon 26436f00a022SMaxime Bizon priv = netdev_priv(dev); 26446f00a022SMaxime Bizon 26456f00a022SMaxime Bizon /* rx/tx ring is actually only limited by memory */ 26466f00a022SMaxime Bizon ering->rx_max_pending = 8192; 26476f00a022SMaxime Bizon ering->tx_max_pending = 8192; 26486f00a022SMaxime Bizon ering->rx_mini_max_pending = 0; 26496f00a022SMaxime Bizon ering->rx_jumbo_max_pending = 0; 26506f00a022SMaxime Bizon ering->rx_pending = priv->rx_ring_size; 26516f00a022SMaxime Bizon ering->tx_pending = priv->tx_ring_size; 26526f00a022SMaxime Bizon } 26536f00a022SMaxime Bizon 26546f00a022SMaxime Bizon static int bcm_enetsw_set_ringparam(struct net_device *dev, 26556f00a022SMaxime Bizon struct ethtool_ringparam *ering) 26566f00a022SMaxime Bizon { 26576f00a022SMaxime Bizon struct bcm_enet_priv *priv; 26586f00a022SMaxime Bizon int was_running; 26596f00a022SMaxime Bizon 26606f00a022SMaxime Bizon priv = netdev_priv(dev); 26616f00a022SMaxime Bizon 26626f00a022SMaxime Bizon was_running = 0; 26636f00a022SMaxime Bizon if (netif_running(dev)) { 26646f00a022SMaxime Bizon bcm_enetsw_stop(dev); 26656f00a022SMaxime Bizon was_running = 1; 26666f00a022SMaxime Bizon } 26676f00a022SMaxime Bizon 26686f00a022SMaxime Bizon priv->rx_ring_size = ering->rx_pending; 26696f00a022SMaxime Bizon priv->tx_ring_size = ering->tx_pending; 26706f00a022SMaxime Bizon 26716f00a022SMaxime Bizon if (was_running) { 26726f00a022SMaxime Bizon int err; 26736f00a022SMaxime Bizon 26746f00a022SMaxime Bizon err = bcm_enetsw_open(dev); 26756f00a022SMaxime Bizon if (err) 26766f00a022SMaxime Bizon dev_close(dev); 26776f00a022SMaxime Bizon } 26786f00a022SMaxime Bizon return 0; 26796f00a022SMaxime Bizon } 26806f00a022SMaxime Bizon 2681dc8007e8SBhumika Goyal static const struct ethtool_ops bcm_enetsw_ethtool_ops = { 26826f00a022SMaxime Bizon .get_strings = bcm_enetsw_get_strings, 26836f00a022SMaxime Bizon .get_sset_count = bcm_enetsw_get_sset_count, 26846f00a022SMaxime Bizon .get_ethtool_stats = bcm_enetsw_get_ethtool_stats, 26856f00a022SMaxime Bizon .get_drvinfo = bcm_enetsw_get_drvinfo, 26866f00a022SMaxime Bizon .get_ringparam = bcm_enetsw_get_ringparam, 26876f00a022SMaxime Bizon .set_ringparam = bcm_enetsw_set_ringparam, 26886f00a022SMaxime Bizon }; 26896f00a022SMaxime Bizon 26906f00a022SMaxime Bizon /* allocate netdevice, request register memory and register device. */ 26916f00a022SMaxime Bizon static int bcm_enetsw_probe(struct platform_device *pdev) 26926f00a022SMaxime Bizon { 26936f00a022SMaxime Bizon struct bcm_enet_priv *priv; 26946f00a022SMaxime Bizon struct net_device *dev; 26956f00a022SMaxime Bizon struct bcm63xx_enetsw_platform_data *pd; 26966f00a022SMaxime Bizon struct resource *res_mem; 26976f00a022SMaxime Bizon int ret, irq_rx, irq_tx; 26986f00a022SMaxime Bizon 26996f00a022SMaxime Bizon /* stop if shared driver failed, assume driver->probe will be 27006f00a022SMaxime Bizon * called in the same order we register devices (correct ?) 27016f00a022SMaxime Bizon */ 27026f00a022SMaxime Bizon if (!bcm_enet_shared_base[0]) 27036f00a022SMaxime Bizon return -ENODEV; 27046f00a022SMaxime Bizon 27056f00a022SMaxime Bizon res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 27066f00a022SMaxime Bizon irq_rx = platform_get_irq(pdev, 0); 27076f00a022SMaxime Bizon irq_tx = platform_get_irq(pdev, 1); 27086f00a022SMaxime Bizon if (!res_mem || irq_rx < 0) 27096f00a022SMaxime Bizon return -ENODEV; 27106f00a022SMaxime Bizon 27116f00a022SMaxime Bizon ret = 0; 27126f00a022SMaxime Bizon dev = alloc_etherdev(sizeof(*priv)); 27136f00a022SMaxime Bizon if (!dev) 27146f00a022SMaxime Bizon return -ENOMEM; 27156f00a022SMaxime Bizon priv = netdev_priv(dev); 27166f00a022SMaxime Bizon memset(priv, 0, sizeof(*priv)); 27176f00a022SMaxime Bizon 27186f00a022SMaxime Bizon /* initialize default and fetch platform data */ 27196f00a022SMaxime Bizon priv->enet_is_sw = true; 27206f00a022SMaxime Bizon priv->irq_rx = irq_rx; 27216f00a022SMaxime Bizon priv->irq_tx = irq_tx; 27226f00a022SMaxime Bizon priv->rx_ring_size = BCMENET_DEF_RX_DESC; 27236f00a022SMaxime Bizon priv->tx_ring_size = BCMENET_DEF_TX_DESC; 27246f00a022SMaxime Bizon priv->dma_maxburst = BCMENETSW_DMA_MAXBURST; 27256f00a022SMaxime Bizon 2726cf0e7794SJingoo Han pd = dev_get_platdata(&pdev->dev); 27276f00a022SMaxime Bizon if (pd) { 27286f00a022SMaxime Bizon memcpy(dev->dev_addr, pd->mac_addr, ETH_ALEN); 27296f00a022SMaxime Bizon memcpy(priv->used_ports, pd->used_ports, 27306f00a022SMaxime Bizon sizeof(pd->used_ports)); 27316f00a022SMaxime Bizon priv->num_ports = pd->num_ports; 27323dc6475cSFlorian Fainelli priv->dma_has_sram = pd->dma_has_sram; 27333dc6475cSFlorian Fainelli priv->dma_chan_en_mask = pd->dma_chan_en_mask; 27343dc6475cSFlorian Fainelli priv->dma_chan_int_mask = pd->dma_chan_int_mask; 27353dc6475cSFlorian Fainelli priv->dma_chan_width = pd->dma_chan_width; 27366f00a022SMaxime Bizon } 27376f00a022SMaxime Bizon 2738e1c6dccaSJarod Wilson ret = bcm_enet_change_mtu(dev, dev->mtu); 27396f00a022SMaxime Bizon if (ret) 27406f00a022SMaxime Bizon goto out; 27416f00a022SMaxime Bizon 27426f00a022SMaxime Bizon if (!request_mem_region(res_mem->start, resource_size(res_mem), 27436f00a022SMaxime Bizon "bcm63xx_enetsw")) { 27446f00a022SMaxime Bizon ret = -EBUSY; 27456f00a022SMaxime Bizon goto out; 27466f00a022SMaxime Bizon } 27476f00a022SMaxime Bizon 27486f00a022SMaxime Bizon priv->base = ioremap(res_mem->start, resource_size(res_mem)); 27496f00a022SMaxime Bizon if (priv->base == NULL) { 27506f00a022SMaxime Bizon ret = -ENOMEM; 27516f00a022SMaxime Bizon goto out_release_mem; 27526f00a022SMaxime Bizon } 27536f00a022SMaxime Bizon 27546f00a022SMaxime Bizon priv->mac_clk = clk_get(&pdev->dev, "enetsw"); 27556f00a022SMaxime Bizon if (IS_ERR(priv->mac_clk)) { 27566f00a022SMaxime Bizon ret = PTR_ERR(priv->mac_clk); 27576f00a022SMaxime Bizon goto out_unmap; 27586f00a022SMaxime Bizon } 27599c86b846SJonas Gorski ret = clk_prepare_enable(priv->mac_clk); 27609c86b846SJonas Gorski if (ret) 27619c86b846SJonas Gorski goto out_put_clk; 27626f00a022SMaxime Bizon 27636f00a022SMaxime Bizon priv->rx_chan = 0; 27646f00a022SMaxime Bizon priv->tx_chan = 1; 27656f00a022SMaxime Bizon spin_lock_init(&priv->rx_lock); 27666f00a022SMaxime Bizon 27676f00a022SMaxime Bizon /* init rx timeout (used for oom) */ 27686f00a022SMaxime Bizon init_timer(&priv->rx_timeout); 27696f00a022SMaxime Bizon priv->rx_timeout.function = bcm_enet_refill_rx_timer; 27706f00a022SMaxime Bizon priv->rx_timeout.data = (unsigned long)dev; 27716f00a022SMaxime Bizon 27726f00a022SMaxime Bizon /* register netdevice */ 27736f00a022SMaxime Bizon dev->netdev_ops = &bcm_enetsw_ops; 27746f00a022SMaxime Bizon netif_napi_add(dev, &priv->napi, bcm_enet_poll, 16); 27757ad24ea4SWilfried Klaebe dev->ethtool_ops = &bcm_enetsw_ethtool_ops; 27766f00a022SMaxime Bizon SET_NETDEV_DEV(dev, &pdev->dev); 27776f00a022SMaxime Bizon 27786f00a022SMaxime Bizon spin_lock_init(&priv->enetsw_mdio_lock); 27796f00a022SMaxime Bizon 27806f00a022SMaxime Bizon ret = register_netdev(dev); 27816f00a022SMaxime Bizon if (ret) 27829c86b846SJonas Gorski goto out_disable_clk; 27836f00a022SMaxime Bizon 27846f00a022SMaxime Bizon netif_carrier_off(dev); 27856f00a022SMaxime Bizon platform_set_drvdata(pdev, dev); 27866f00a022SMaxime Bizon priv->pdev = pdev; 27876f00a022SMaxime Bizon priv->net_dev = dev; 27886f00a022SMaxime Bizon 27896f00a022SMaxime Bizon return 0; 27906f00a022SMaxime Bizon 27919c86b846SJonas Gorski out_disable_clk: 27929c86b846SJonas Gorski clk_disable_unprepare(priv->mac_clk); 27939c86b846SJonas Gorski 27946f00a022SMaxime Bizon out_put_clk: 27956f00a022SMaxime Bizon clk_put(priv->mac_clk); 27966f00a022SMaxime Bizon 27976f00a022SMaxime Bizon out_unmap: 27986f00a022SMaxime Bizon iounmap(priv->base); 27996f00a022SMaxime Bizon 28006f00a022SMaxime Bizon out_release_mem: 28016f00a022SMaxime Bizon release_mem_region(res_mem->start, resource_size(res_mem)); 28026f00a022SMaxime Bizon out: 28036f00a022SMaxime Bizon free_netdev(dev); 28046f00a022SMaxime Bizon return ret; 28056f00a022SMaxime Bizon } 28066f00a022SMaxime Bizon 28076f00a022SMaxime Bizon 28086f00a022SMaxime Bizon /* exit func, stops hardware and unregisters netdevice */ 28096f00a022SMaxime Bizon static int bcm_enetsw_remove(struct platform_device *pdev) 28106f00a022SMaxime Bizon { 28116f00a022SMaxime Bizon struct bcm_enet_priv *priv; 28126f00a022SMaxime Bizon struct net_device *dev; 28136f00a022SMaxime Bizon struct resource *res; 28146f00a022SMaxime Bizon 28156f00a022SMaxime Bizon /* stop netdevice */ 28166f00a022SMaxime Bizon dev = platform_get_drvdata(pdev); 28176f00a022SMaxime Bizon priv = netdev_priv(dev); 28186f00a022SMaxime Bizon unregister_netdev(dev); 28196f00a022SMaxime Bizon 28206f00a022SMaxime Bizon /* release device resources */ 28216f00a022SMaxime Bizon iounmap(priv->base); 28226f00a022SMaxime Bizon res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 28236f00a022SMaxime Bizon release_mem_region(res->start, resource_size(res)); 28246f00a022SMaxime Bizon 28259c86b846SJonas Gorski clk_disable_unprepare(priv->mac_clk); 28269c86b846SJonas Gorski clk_put(priv->mac_clk); 28279c86b846SJonas Gorski 28286f00a022SMaxime Bizon free_netdev(dev); 28296f00a022SMaxime Bizon return 0; 28306f00a022SMaxime Bizon } 28316f00a022SMaxime Bizon 28326f00a022SMaxime Bizon struct platform_driver bcm63xx_enetsw_driver = { 28336f00a022SMaxime Bizon .probe = bcm_enetsw_probe, 28346f00a022SMaxime Bizon .remove = bcm_enetsw_remove, 28356f00a022SMaxime Bizon .driver = { 28366f00a022SMaxime Bizon .name = "bcm63xx_enetsw", 28376f00a022SMaxime Bizon .owner = THIS_MODULE, 28386f00a022SMaxime Bizon }, 28396f00a022SMaxime Bizon }; 28406f00a022SMaxime Bizon 28416f00a022SMaxime Bizon /* reserve & remap memory space shared between all macs */ 2842047fc566SBill Pemberton static int bcm_enet_shared_probe(struct platform_device *pdev) 2843adfc5217SJeff Kirsher { 2844adfc5217SJeff Kirsher struct resource *res; 28450ae99b5fSMaxime Bizon void __iomem *p[3]; 28460ae99b5fSMaxime Bizon unsigned int i; 2847adfc5217SJeff Kirsher 28480ae99b5fSMaxime Bizon memset(bcm_enet_shared_base, 0, sizeof(bcm_enet_shared_base)); 2849adfc5217SJeff Kirsher 28500ae99b5fSMaxime Bizon for (i = 0; i < 3; i++) { 28510ae99b5fSMaxime Bizon res = platform_get_resource(pdev, IORESOURCE_MEM, i); 28520ae99b5fSMaxime Bizon p[i] = devm_ioremap_resource(&pdev->dev, res); 2853646093a2SWei Yongjun if (IS_ERR(p[i])) 2854646093a2SWei Yongjun return PTR_ERR(p[i]); 28550ae99b5fSMaxime Bizon } 28560ae99b5fSMaxime Bizon 28570ae99b5fSMaxime Bizon memcpy(bcm_enet_shared_base, p, sizeof(bcm_enet_shared_base)); 28581c03da05SJonas Gorski 2859adfc5217SJeff Kirsher return 0; 2860adfc5217SJeff Kirsher } 2861adfc5217SJeff Kirsher 2862047fc566SBill Pemberton static int bcm_enet_shared_remove(struct platform_device *pdev) 2863adfc5217SJeff Kirsher { 2864adfc5217SJeff Kirsher return 0; 2865adfc5217SJeff Kirsher } 2866adfc5217SJeff Kirsher 28676f00a022SMaxime Bizon /* this "shared" driver is needed because both macs share a single 2868adfc5217SJeff Kirsher * address space 2869adfc5217SJeff Kirsher */ 2870adfc5217SJeff Kirsher struct platform_driver bcm63xx_enet_shared_driver = { 2871adfc5217SJeff Kirsher .probe = bcm_enet_shared_probe, 2872047fc566SBill Pemberton .remove = bcm_enet_shared_remove, 2873adfc5217SJeff Kirsher .driver = { 2874adfc5217SJeff Kirsher .name = "bcm63xx_enet_shared", 2875adfc5217SJeff Kirsher .owner = THIS_MODULE, 2876adfc5217SJeff Kirsher }, 2877adfc5217SJeff Kirsher }; 2878adfc5217SJeff Kirsher 28790d1c744cSThierry Reding static struct platform_driver * const drivers[] = { 28800d1c744cSThierry Reding &bcm63xx_enet_shared_driver, 28810d1c744cSThierry Reding &bcm63xx_enet_driver, 28820d1c744cSThierry Reding &bcm63xx_enetsw_driver, 28830d1c744cSThierry Reding }; 28840d1c744cSThierry Reding 28856f00a022SMaxime Bizon /* entry point */ 2886adfc5217SJeff Kirsher static int __init bcm_enet_init(void) 2887adfc5217SJeff Kirsher { 28880d1c744cSThierry Reding return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 2889adfc5217SJeff Kirsher } 2890adfc5217SJeff Kirsher 2891adfc5217SJeff Kirsher static void __exit bcm_enet_exit(void) 2892adfc5217SJeff Kirsher { 28930d1c744cSThierry Reding platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 2894adfc5217SJeff Kirsher } 2895adfc5217SJeff Kirsher 2896adfc5217SJeff Kirsher 2897adfc5217SJeff Kirsher module_init(bcm_enet_init); 2898adfc5217SJeff Kirsher module_exit(bcm_enet_exit); 2899adfc5217SJeff Kirsher 2900adfc5217SJeff Kirsher MODULE_DESCRIPTION("BCM63xx internal ethernet mac driver"); 2901adfc5217SJeff Kirsher MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>"); 2902adfc5217SJeff Kirsher MODULE_LICENSE("GPL"); 2903