From: Jonas Gorski Date: Wed, 28 Mar 2012 20:42:20 +0000 (+0000) Subject: bcm63xx: add ethernet support for bcm6368 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=a2adca6ee9a731aa2b0ee7ca246db8f941266ed6;p=openwrt%2Fstaging%2Fansuel.git bcm63xx: add ethernet support for bcm6368 Add basic support for the internal ethernet switch on bcm6368. It behaves as a dumb switch for now, but allows basic connectivity. Also drop the ethernet patch for bcm6345 for now, it needs rework. SVN-Revision: 31129 --- diff --git a/target/linux/brcm63xx/patches-3.3/407-bcm6345_enet.patch b/target/linux/brcm63xx/patches-3.3/407-bcm6345_enet.patch deleted file mode 100644 index aac4de63ce..0000000000 --- a/target/linux/brcm63xx/patches-3.3/407-bcm6345_enet.patch +++ /dev/null @@ -1,530 +0,0 @@ ---- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h -+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h -@@ -29,16 +29,15 @@ - CKCTL_6338_SAR_EN | \ - CKCTL_6338_SPI_EN) - --#define CKCTL_6345_CPU_EN (1 << 0) --#define CKCTL_6345_BUS_EN (1 << 1) --#define CKCTL_6345_EBI_EN (1 << 2) --#define CKCTL_6345_UART_EN (1 << 3) --#define CKCTL_6345_ADSLPHY_EN (1 << 4) --#define CKCTL_6345_ENET_EN (1 << 7) --#define CKCTL_6345_USBH_EN (1 << 8) -+#define CKCTL_6345_CPU_EN (1 << 16) -+#define CKCTL_6345_BUS_EN (1 << 17) -+#define CKCTL_6345_EBI_EN (1 << 18) -+#define CKCTL_6345_UART_EN (1 << 19) -+#define CKCTL_6345_ADSLPHY_EN (1 << 20) -+#define CKCTL_6345_ENET_EN (1 << 23) -+#define CKCTL_6345_USBH_EN (1 << 24) - --#define CKCTL_6345_ALL_SAFE_EN (CKCTL_6345_ENET_EN | \ -- CKCTL_6345_USBH_EN | \ -+#define CKCTL_6345_ALL_SAFE_EN (CKCTL_6345_USBH_EN | \ - CKCTL_6345_ADSLPHY_EN) - - #define CKCTL_6348_ADSLPHY_EN (1 << 0) -@@ -702,6 +701,39 @@ - #define ENETSW_MIB_REG_COUNT 47 - - -+/* Broadcom 6345 ENET DMA definitions */ -+#define ENETDMA_6345_CHANCFG_REG(x) (0x00 + (x) * 0x40) -+#define ENETDMA_6345_CHANCFG_EN_SHIFT 0 -+#define ENETDMA_6345_CHANCFG_EN_MASK (1 << ENETDMA_6345_CHANCFG_EN_SHIFT) -+#define ENETDMA_6345_PKTHALT_SHIFT 1 -+#define ENETDMA_6345_PKTHALT_MASK (1 << ENETDMA_6345_PKTHALT_SHIFT) -+#define ENETDMA_6345_CHAINING_SHIFT 2 -+#define ENETDMA_6345_CHAINING_MASK (1 << ENETDMA_6345_CHAINING_SHIFT) -+#define ENETDMA_6345_WRAP_EN_SHIFT 3 -+#define ENETDMA_6345_WRAP_EN_MASK (1 << ENETDMA_6345_WRAP_EN_SHIFT) -+#define ENETDMA_6345_FLOWC_EN_SHIFT 4 -+#define ENETDMA_6345_FLOWC_EN_MASK (1 << ENETDMA_6345_FLOWC_EN_SHIFT) -+ -+#define ENETDMA_6345_MAXBURST_REG(x) (0x04 + (x) * 0x40) -+ -+#define ENETDMA_6345_RSTART_REG(x) (0x08 + (x) * 0x40) -+ -+#define ENETDMA_6345_LEN_REG(x) (0x0C + (x) * 0x40) -+ -+#define ENETDMA_6345_BSTAT_REG(x) (0x10 + (x) * 0x40) -+ -+#define ENETDMA_6345_IR_REG(x) (0x14 + (x) * 0x40) -+#define ENETDMA_6345_IR_BUFDONE_MASK (1 << 0) -+#define ENETDMA_6345_IR_PKTDONE_MASK (1 << 1) -+#define ENETDMA_6345_IR_NOTOWNER_MASK (1 << 2) -+ -+#define ENETDMA_6345_IRMASK_REG(x) (0x18 + (x) * 0x40) -+ -+#define ENETDMA_6345_FC_REG(x) (0x1C + (x) * 0x40) -+ -+#define ENETDMA_6345_BUFALLOC_REG(x) (0x20 + (x) * 0x40) -+ -+ - /************************************************************************* - * _REG relative to RSET_OHCI_PRIV - *************************************************************************/ ---- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c -+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c -@@ -32,6 +32,7 @@ - #include - - #include -+#include - #include "bcm63xx_enet.h" - - static char bcm_enet_driver_name[] = "bcm63xx_enet"; -@@ -178,6 +179,7 @@ static void bcm_enet_mdio_write_mii(stru - static int bcm_enet_refill_rx(struct net_device *dev) - { - struct bcm_enet_priv *priv; -+ unsigned int desc_shift = BCMCPU_IS_6345() ? DMADESC_6345_SHIFT : 0; - - priv = netdev_priv(dev); - -@@ -206,7 +208,7 @@ static int bcm_enet_refill_rx(struct net - len_stat = priv->rx_skb_size << DMADESC_LENGTH_SHIFT; - len_stat |= DMADESC_OWNER_MASK; - if (priv->rx_dirty_desc == priv->rx_ring_size - 1) { -- len_stat |= DMADESC_WRAP_MASK; -+ len_stat |= (DMADESC_WRAP_MASK >> desc_shift); - priv->rx_dirty_desc = 0; - } else { - priv->rx_dirty_desc++; -@@ -217,7 +219,10 @@ static int bcm_enet_refill_rx(struct net - priv->rx_desc_count++; - - /* tell dma engine we allocated one buffer */ -- enet_dma_writel(priv, 1, ENETDMA_BUFALLOC_REG(priv->rx_chan)); -+ if (!BCMCPU_IS_6345()) -+ enet_dma_writel(priv, 1, ENETDMA_BUFALLOC_REG(priv->rx_chan)); -+ else -+ enet_dma_writel(priv, 1, ENETDMA_6345_BUFALLOC_REG(priv->rx_chan)); - } - - /* If rx ring is still empty, set a timer to try allocating -@@ -255,6 +260,7 @@ static int bcm_enet_receive_queue(struct - struct bcm_enet_priv *priv; - struct device *kdev; - int processed; -+ unsigned int desc_shift = BCMCPU_IS_6345() ? DMADESC_6345_SHIFT : 0; - - priv = netdev_priv(dev); - kdev = &priv->pdev->dev; -@@ -293,7 +299,7 @@ static int bcm_enet_receive_queue(struct - - /* if the packet does not have start of packet _and_ - * end of packet flag set, then just recycle it */ -- if ((len_stat & DMADESC_ESOP_MASK) != DMADESC_ESOP_MASK) { -+ if ((len_stat & (DMADESC_ESOP_MASK >> desc_shift)) != (DMADESC_ESOP_MASK >> desc_shift)) { - dev->stats.rx_dropped++; - continue; - } -@@ -353,8 +359,15 @@ static int bcm_enet_receive_queue(struct - bcm_enet_refill_rx(dev); - - /* kick rx dma */ -- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, -- ENETDMA_CHANCFG_REG(priv->rx_chan)); -+ if (!BCMCPU_IS_6345()) -+ enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, -+ ENETDMA_CHANCFG_REG(priv->rx_chan)); -+ else -+ enet_dma_writel(priv, ENETDMA_6345_CHANCFG_EN_MASK | -+ ENETDMA_6345_CHAINING_MASK | -+ ENETDMA_6345_WRAP_EN_MASK | -+ ENETDMA_6345_FLOWC_EN_MASK, -+ ENETDMA_6345_CHANCFG_REG(priv->rx_chan)); - } - - return processed; -@@ -429,10 +442,21 @@ static int bcm_enet_poll(struct napi_str - dev = priv->net_dev; - - /* ack interrupts */ -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IR_REG(priv->rx_chan)); -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IR_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IR_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IR_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IR_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IR_REG(priv->tx_chan)); -+ } - - /* reclaim sent skb */ - tx_work_done = bcm_enet_tx_reclaim(dev, 0); -@@ -451,10 +475,21 @@ static int bcm_enet_poll(struct napi_str - napi_complete(napi); - - /* restore rx/tx interrupt */ -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IRMASK_REG(priv->rx_chan)); -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IRMASK_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IRMASK_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IRMASK_REG(priv->tx_chan)); -+ } - - return rx_work_done; - } -@@ -497,8 +532,13 @@ static irqreturn_t bcm_enet_isr_dma(int - priv = netdev_priv(dev); - - /* mask rx/tx interrupts */ -- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, 0, ENETDMA_6345_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_6345_IRMASK_REG(priv->tx_chan)); -+ } - - napi_schedule(&priv->napi); - -@@ -514,6 +554,7 @@ static int bcm_enet_start_xmit(struct sk - struct bcm_enet_desc *desc; - u32 len_stat; - int ret; -+ unsigned int desc_shift = BCMCPU_IS_6345() ? DMADESC_6345_SHIFT : 0; - - priv = netdev_priv(dev); - -@@ -539,14 +580,13 @@ static int bcm_enet_start_xmit(struct sk - DMA_TO_DEVICE); - - len_stat = (skb->len << DMADESC_LENGTH_SHIFT) & DMADESC_LENGTH_MASK; -- len_stat |= DMADESC_ESOP_MASK | -- DMADESC_APPEND_CRC | -- DMADESC_OWNER_MASK; -+ len_stat |= ((DMADESC_ESOP_MASK >> desc_shift) | -+ DMADESC_APPEND_CRC | DMADESC_OWNER_MASK); - - priv->tx_curr_desc++; - if (priv->tx_curr_desc == priv->tx_ring_size) { - priv->tx_curr_desc = 0; -- len_stat |= DMADESC_WRAP_MASK; -+ len_stat |= (DMADESC_WRAP_MASK >> desc_shift); - } - priv->tx_desc_count--; - -@@ -557,8 +597,15 @@ static int bcm_enet_start_xmit(struct sk - wmb(); - - /* kick tx dma */ -- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, -- ENETDMA_CHANCFG_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) -+ enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, -+ ENETDMA_CHANCFG_REG(priv->tx_chan)); -+ else -+ enet_dma_writel(priv, ENETDMA_6345_CHANCFG_EN_MASK | -+ ENETDMA_6345_CHAINING_MASK | -+ ENETDMA_6345_WRAP_EN_MASK | -+ ENETDMA_6345_FLOWC_EN_MASK, -+ ENETDMA_6345_CHANCFG_REG(priv->tx_chan)); - - /* stop queue if no more desc available */ - if (!priv->tx_desc_count) -@@ -686,6 +733,9 @@ static void bcm_enet_set_flow(struct bcm - val &= ~ENET_RXCFG_ENFLOW_MASK; - enet_writel(priv, val, ENET_RXCFG_REG); - -+ if (BCMCPU_IS_6345()) -+ return; -+ - /* tx flow control (pause frame generation) */ - val = enet_dma_readl(priv, ENETDMA_CFG_REG); - if (tx_en) -@@ -833,8 +883,13 @@ static int bcm_enet_open(struct net_devi - - /* mask all interrupts and request them */ - enet_writel(priv, 0, ENET_IRMASK_REG); -- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, 0, ENETDMA_6345_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_6345_IRMASK_REG(priv->tx_chan)); -+ } - - ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev); - if (ret) -@@ -913,8 +968,12 @@ static int bcm_enet_open(struct net_devi - priv->rx_curr_desc = 0; - - /* initialize flow control buffer allocation */ -- enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, -- ENETDMA_BUFALLOC_REG(priv->rx_chan)); -+ if (!BCMCPU_IS_6345()) -+ enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, -+ ENETDMA_BUFALLOC_REG(priv->rx_chan)); -+ else -+ enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, -+ ENETDMA_6345_BUFALLOC_REG(priv->rx_chan)); - - if (bcm_enet_refill_rx(dev)) { - dev_err(kdev, "cannot allocate rx skb queue\n"); -@@ -923,37 +982,62 @@ static int bcm_enet_open(struct net_devi - } - - /* write rx & tx ring addresses */ -- enet_dma_writel(priv, priv->rx_desc_dma, -- ENETDMA_RSTART_REG(priv->rx_chan)); -- enet_dma_writel(priv, priv->tx_desc_dma, -- ENETDMA_RSTART_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, priv->rx_desc_dma, -+ ENETDMA_RSTART_REG(priv->rx_chan)); -+ enet_dma_writel(priv, priv->tx_desc_dma, -+ ENETDMA_RSTART_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, priv->rx_desc_dma, -+ ENETDMA_6345_RSTART_REG(priv->rx_chan)); -+ enet_dma_writel(priv, priv->tx_desc_dma, -+ ENETDMA_6345_RSTART_REG(priv->tx_chan)); -+ } - - /* clear remaining state ram for rx & tx channel */ -- enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->rx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->tx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->rx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->tx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->rx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->tx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->tx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, 0, ENETDMA_6345_FC_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_6345_FC_REG(priv->tx_chan)); -+ } - - /* set max rx/tx length */ - enet_writel(priv, priv->hw_mtu, ENET_RXMAXLEN_REG); - enet_writel(priv, priv->hw_mtu, ENET_TXMAXLEN_REG); - - /* set dma maximum burst len */ -- enet_dma_writel(priv, BCMENET_DMA_MAXBURST, -- ENETDMA_MAXBURST_REG(priv->rx_chan)); -- enet_dma_writel(priv, BCMENET_DMA_MAXBURST, -- ENETDMA_MAXBURST_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, BCMENET_DMA_MAXBURST, -+ ENETDMA_MAXBURST_REG(priv->rx_chan)); -+ enet_dma_writel(priv, BCMENET_DMA_MAXBURST, -+ ENETDMA_MAXBURST_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, BCMENET_DMA_MAXBURST, -+ ENETDMA_6345_MAXBURST_REG(priv->rx_chan)); -+ enet_dma_writel(priv, BCMENET_DMA_MAXBURST, -+ ENETDMA_6345_MAXBURST_REG(priv->tx_chan)); -+ } - - /* set correct transmit fifo watermark */ - enet_writel(priv, BCMENET_TX_FIFO_TRESH, ENET_TXWMARK_REG); - - /* set flow control low/high threshold to 1/3 / 2/3 */ -- val = priv->rx_ring_size / 3; -- enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan)); -- val = (priv->rx_ring_size * 2) / 3; -- enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ val = priv->rx_ring_size / 3; -+ enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan)); -+ val = (priv->rx_ring_size * 2) / 3; -+ enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan)); -+ } else { -+ enet_dma_writel(priv, 5, ENETDMA_6345_FC_REG(priv->rx_chan)); -+ enet_dma_writel(priv, priv->rx_ring_size, ENETDMA_6345_LEN_REG(priv->rx_chan)); -+ enet_dma_writel(priv, priv->tx_ring_size, ENETDMA_6345_LEN_REG(priv->tx_chan)); -+ } - - /* all set, enable mac and interrupts, start dma engine and - * kick rx dma channel */ -@@ -961,27 +1045,58 @@ static int bcm_enet_open(struct net_devi - val = enet_readl(priv, ENET_CTL_REG); - val |= ENET_CTL_ENABLE_MASK; - enet_writel(priv, val, ENET_CTL_REG); -- enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); -- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, -- ENETDMA_CHANCFG_REG(priv->rx_chan)); -+ -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); -+ enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, -+ ENETDMA_CHANCFG_REG(priv->rx_chan)); -+ } else { -+ enet_dma_writel(priv, ENETDMA_6345_CHANCFG_EN_MASK | -+ ENETDMA_6345_CHAINING_MASK | -+ ENETDMA_6345_WRAP_EN_MASK | -+ ENETDMA_6345_FLOWC_EN_MASK, -+ ENETDMA_6345_CHANCFG_REG(priv->rx_chan)); -+ } - - /* watch "mib counters about to overflow" interrupt */ - enet_writel(priv, ENET_IR_MIB, ENET_IR_REG); - enet_writel(priv, ENET_IR_MIB, ENET_IRMASK_REG); - - /* watch "packet transferred" interrupt in rx and tx */ -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IR_REG(priv->rx_chan)); -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IR_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IR_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IR_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IR_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IR_REG(priv->tx_chan)); -+ } - - /* make sure we enable napi before rx interrupt */ - napi_enable(&priv->napi); - -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IRMASK_REG(priv->rx_chan)); -- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -- ENETDMA_IRMASK_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, -+ ENETDMA_IRMASK_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, ENETDMA_IR_BUFDONE_MASK | -+ ENETDMA_IR_PKTDONE_MASK | -+ ENETDMA_IR_NOTOWNER_MASK, -+ ENETDMA_6345_IRMASK_REG(priv->tx_chan)); -+ } - - if (priv->has_phy) - phy_start(priv->phydev); -@@ -1061,13 +1176,19 @@ static void bcm_enet_disable_dma(struct - { - int limit; - -- enet_dma_writel(priv, 0, ENETDMA_CHANCFG_REG(chan)); -+ if (!BCMCPU_IS_6345()) -+ enet_dma_writel(priv, 0, ENETDMA_CHANCFG_REG(chan)); -+ else -+ enet_dma_writel(priv, 0, ENETDMA_6345_CHANCFG_REG(chan)); - - limit = 1000; - do { - u32 val; - -- val = enet_dma_readl(priv, ENETDMA_CHANCFG_REG(chan)); -+ if (!BCMCPU_IS_6345()) -+ val = enet_dma_readl(priv, ENETDMA_CHANCFG_REG(chan)); -+ else -+ val = enet_dma_readl(priv, ENETDMA_6345_CHANCFG_REG(chan)); - if (!(val & ENETDMA_CHANCFG_EN_MASK)) - break; - udelay(1); -@@ -1094,8 +1215,13 @@ static int bcm_enet_stop(struct net_devi - - /* mask all interrupts */ - enet_writel(priv, 0, ENET_IRMASK_REG); -- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); -- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); -+ if (!BCMCPU_IS_6345()) { -+ enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); -+ } else { -+ enet_dma_writel(priv, 0, ENETDMA_6345_IRMASK_REG(priv->rx_chan)); -+ enet_dma_writel(priv, 0, ENETDMA_6345_IRMASK_REG(priv->tx_chan)); -+ } - - /* make sure no mib update is scheduled */ - cancel_work_sync(&priv->mib_update_task); -@@ -1622,6 +1748,7 @@ static int __devinit bcm_enet_probe(stru - const char *clk_name; - unsigned int iomem_size; - int i, ret; -+ unsigned int chan_offset = 0; - - /* stop if shared driver failed, assume driver->probe will be - * called in the same order we register devices (correct ?) */ -@@ -1661,10 +1788,13 @@ static int __devinit bcm_enet_probe(stru - priv->irq_tx = res_irq_tx->start; - priv->mac_id = pdev->id; - -+ if (BCMCPU_IS_6345()) -+ chan_offset = 1; -+ - /* get rx & tx dma channel id for this mac */ - if (priv->mac_id == 0) { -- priv->rx_chan = 0; -- priv->tx_chan = 1; -+ priv->rx_chan = 0 + chan_offset; -+ priv->tx_chan = 1 + chan_offset; - clk_name = "enet0"; - } else { - priv->rx_chan = 2; ---- a/drivers/net/ethernet/broadcom/bcm63xx_enet.h -+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.h -@@ -46,6 +46,9 @@ struct bcm_enet_desc { - #define DMADESC_ESOP_MASK (DMADESC_EOP_MASK | DMADESC_SOP_MASK) - #define DMADESC_WRAP_MASK (1 << 12) - -+/* Shift down for EOP, SOP and WRAP bits */ -+#define DMADESC_6345_SHIFT (3) -+ - #define DMADESC_UNDER_MASK (1 << 9) - #define DMADESC_APPEND_CRC (1 << 8) - #define DMADESC_OVSIZE_MASK (1 << 4) ---- a/arch/mips/bcm63xx/dev-enet.c -+++ b/arch/mips/bcm63xx/dev-enet.c -@@ -104,7 +104,7 @@ int __init bcm63xx_enet_register(int uni - if (unit > 1) - return -ENODEV; - -- if (unit == 1 && BCMCPU_IS_6338()) -+ if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345())) - return -ENODEV; - - if (!shared_device_registered) { diff --git a/target/linux/brcm63xx/patches-3.3/408-6358-enet1-external-mii-clk.patch b/target/linux/brcm63xx/patches-3.3/408-6358-enet1-external-mii-clk.patch index 205be4beea..96e7ef1bf5 100644 --- a/target/linux/brcm63xx/patches-3.3/408-6358-enet1-external-mii-clk.patch +++ b/target/linux/brcm63xx/patches-3.3/408-6358-enet1-external-mii-clk.patch @@ -11,7 +11,7 @@ bcm_gpio_writel(val, GPIO_MODE_REG); --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h -@@ -467,6 +467,8 @@ +@@ -468,6 +468,8 @@ #define GPIO_MODE_6358_EXTRA_SPI_SS (1 << 7) #define GPIO_MODE_6358_SERIAL_LED (1 << 10) #define GPIO_MODE_6358_UTOPIA (1 << 12) diff --git a/target/linux/brcm63xx/patches-3.3/409-spi.patch b/target/linux/brcm63xx/patches-3.3/409-spi.patch index e8d2dd7465..6fa06749ff 100644 --- a/target/linux/brcm63xx/patches-3.3/409-spi.patch +++ b/target/linux/brcm63xx/patches-3.3/409-spi.patch @@ -145,7 +145,7 @@ #define BCM_6358_DSL_IRQ (IRQ_INTERNAL_BASE + 29) --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h -@@ -1008,4 +1008,116 @@ +@@ -976,4 +976,116 @@ #define M2M_SRCID_REG(x) ((x) * 0x40 + 0x14) #define M2M_DSTID_REG(x) ((x) * 0x40 + 0x18) diff --git a/target/linux/brcm63xx/patches-3.3/410-NET-bcm63xx_enet-move-phy_-dis-connect-into-probe-re.patch b/target/linux/brcm63xx/patches-3.3/410-NET-bcm63xx_enet-move-phy_-dis-connect-into-probe-re.patch new file mode 100644 index 0000000000..2102db35e8 --- /dev/null +++ b/target/linux/brcm63xx/patches-3.3/410-NET-bcm63xx_enet-move-phy_-dis-connect-into-probe-re.patch @@ -0,0 +1,169 @@ +From b11218c750ab92cfab4408a0328f1b36ceec3f33 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Fri, 6 Jan 2012 12:24:18 +0100 +Subject: [PATCH 19/63] NET: bcm63xx_enet: move phy_(dis)connect into probe/remove + +Only connect/disconnect the phy during probe and remove, not during any +open/close. The phy seldom changes during the runtime, and disconnecting +the phy during close will prevent it from keeping any configuration over +a down/up cycle. + +Signed-off-by: Jonas Gorski +--- + drivers/net/ethernet/broadcom/bcm63xx_enet.c | 84 +++++++++++++------------- + 1 files changed, 41 insertions(+), 43 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c ++++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c +@@ -784,10 +784,8 @@ static int bcm_enet_open(struct net_devi + struct bcm_enet_priv *priv; + struct sockaddr addr; + struct device *kdev; +- struct phy_device *phydev; + int i, ret; + unsigned int size; +- char phy_id[MII_BUS_ID_SIZE + 3]; + void *p; + u32 val; + +@@ -795,40 +793,10 @@ static int bcm_enet_open(struct net_devi + kdev = &priv->pdev->dev; + + if (priv->has_phy) { +- /* connect to PHY */ +- snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, +- priv->mii_bus->id, priv->phy_id); +- +- phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, 0, +- PHY_INTERFACE_MODE_MII); +- +- if (IS_ERR(phydev)) { +- dev_err(kdev, "could not attach to PHY\n"); +- return PTR_ERR(phydev); +- } +- +- /* mask with MAC supported features */ +- phydev->supported &= (SUPPORTED_10baseT_Half | +- SUPPORTED_10baseT_Full | +- SUPPORTED_100baseT_Half | +- SUPPORTED_100baseT_Full | +- SUPPORTED_Autoneg | +- SUPPORTED_Pause | +- SUPPORTED_MII); +- phydev->advertising = phydev->supported; +- +- if (priv->pause_auto && priv->pause_rx && priv->pause_tx) +- phydev->advertising |= SUPPORTED_Pause; +- else +- phydev->advertising &= ~SUPPORTED_Pause; +- +- dev_info(kdev, "attached PHY at address %d [%s]\n", +- phydev->addr, phydev->drv->name); +- ++ /* Reset state */ + priv->old_link = 0; + priv->old_duplex = -1; + priv->old_pause = -1; +- priv->phydev = phydev; + } + + /* mask all interrupts and request them */ +@@ -838,7 +806,7 @@ static int bcm_enet_open(struct net_devi + + ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev); + if (ret) +- goto out_phy_disconnect; ++ return ret; + + ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, IRQF_DISABLED, + dev->name, dev); +@@ -1025,9 +993,6 @@ out_freeirq_rx: + out_freeirq: + free_irq(dev->irq, dev); + +-out_phy_disconnect: +- phy_disconnect(priv->phydev); +- + return ret; + } + +@@ -1132,12 +1097,6 @@ static int bcm_enet_stop(struct net_devi + free_irq(priv->irq_rx, dev); + free_irq(dev->irq, dev); + +- /* release phy */ +- if (priv->has_phy) { +- phy_disconnect(priv->phydev); +- priv->phydev = NULL; +- } +- + return 0; + } + +@@ -1714,6 +1673,8 @@ static int __devinit bcm_enet_probe(stru + + /* MII bus registration */ + if (priv->has_phy) { ++ struct phy_device *phydev; ++ char phy_id[MII_BUS_ID_SIZE + 3]; + + priv->mii_bus = mdiobus_alloc(); + if (!priv->mii_bus) { +@@ -1750,6 +1711,38 @@ static int __devinit bcm_enet_probe(stru + dev_err(&pdev->dev, "unable to register mdio bus\n"); + goto out_free_mdio; + } ++ ++ /* connect to PHY */ ++ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, ++ priv->mii_bus->id, priv->phy_id); ++ ++ phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, 0, ++ PHY_INTERFACE_MODE_MII); ++ ++ if (IS_ERR(phydev)) { ++ dev_err(&pdev->dev, "could not attach to PHY\n"); ++ goto out_unregister_mdio; ++ } ++ ++ /* mask with MAC supported features */ ++ phydev->supported &= (SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_100baseT_Half | ++ SUPPORTED_100baseT_Full | ++ SUPPORTED_Autoneg | ++ SUPPORTED_Pause | ++ SUPPORTED_MII); ++ phydev->advertising = phydev->supported; ++ ++ if (priv->pause_auto && priv->pause_rx && priv->pause_tx) ++ phydev->advertising |= SUPPORTED_Pause; ++ else ++ phydev->advertising &= ~SUPPORTED_Pause; ++ ++ dev_info(&pdev->dev, "attached PHY at address %d [%s]\n", ++ phydev->addr, phydev->drv->name); ++ ++ priv->phydev = phydev; + } else { + + /* run platform code to initialize PHY device */ +@@ -1795,6 +1788,9 @@ static int __devinit bcm_enet_probe(stru + return 0; + + out_unregister_mdio: ++ if (priv->phydev) ++ phy_disconnect(priv->phydev); ++ + if (priv->mii_bus) { + mdiobus_unregister(priv->mii_bus); + kfree(priv->mii_bus->irq); +@@ -1845,6 +1841,8 @@ static int __devexit bcm_enet_remove(str + enet_writel(priv, 0, ENET_MIISC_REG); + + if (priv->has_phy) { ++ phy_disconnect(priv->phydev); ++ priv->phydev = NULL; + mdiobus_unregister(priv->mii_bus); + kfree(priv->mii_bus->irq); + mdiobus_free(priv->mii_bus); diff --git a/target/linux/brcm63xx/patches-3.3/411-bcm63xx_enet-implement-reset_autoneg-ethtool.patch b/target/linux/brcm63xx/patches-3.3/411-bcm63xx_enet-implement-reset_autoneg-ethtool.patch new file mode 100644 index 0000000000..d143b473d8 --- /dev/null +++ b/target/linux/brcm63xx/patches-3.3/411-bcm63xx_enet-implement-reset_autoneg-ethtool.patch @@ -0,0 +1,40 @@ +From accc558f334662c8b16c121b4819931c028e8eb0 Mon Sep 17 00:00:00 2001 +From: Maxime Bizon +Date: Mon, 8 Jun 2009 16:12:10 +0200 +Subject: [PATCH 27/63] bcm63xx_enet: implement reset_autoneg ethtool. + +--- + drivers/net/ethernet/broadcom/bcm63xx_enet.c | 15 +++++++++++++++ + 1 files changed, 15 insertions(+), 0 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c ++++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c +@@ -1290,6 +1290,20 @@ static void bcm_enet_get_ethtool_stats(s + mutex_unlock(&priv->mib_update_lock); + } + ++static int bcm_enet_nway_reset(struct net_device *dev) ++{ ++ struct bcm_enet_priv *priv; ++ ++ priv = netdev_priv(dev); ++ if (priv->has_phy) { ++ if (!priv->phydev) ++ return -ENODEV; ++ return genphy_restart_aneg(priv->phydev); ++ } ++ ++ return -EOPNOTSUPP; ++} ++ + static int bcm_enet_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) + { +@@ -1432,6 +1446,7 @@ static const struct ethtool_ops bcm_enet + .get_strings = bcm_enet_get_strings, + .get_sset_count = bcm_enet_get_sset_count, + .get_ethtool_stats = bcm_enet_get_ethtool_stats, ++ .nway_reset = bcm_enet_nway_reset, + .get_settings = bcm_enet_get_settings, + .set_settings = bcm_enet_set_settings, + .get_drvinfo = bcm_enet_get_drvinfo, diff --git a/target/linux/brcm63xx/patches-3.3/412-bcm63xx_enet-use-resource_size.patch b/target/linux/brcm63xx/patches-3.3/412-bcm63xx_enet-use-resource_size.patch new file mode 100644 index 0000000000..11d035dd51 --- /dev/null +++ b/target/linux/brcm63xx/patches-3.3/412-bcm63xx_enet-use-resource_size.patch @@ -0,0 +1,69 @@ +From dbd9b51204aa4114756b8659e180139ef3878032 Mon Sep 17 00:00:00 2001 +From: Maxime Bizon +Date: Thu, 21 Jan 2010 17:28:36 +0100 +Subject: [PATCH 28/63] bcm63xx_enet: use resource_size(). + +--- + drivers/net/ethernet/broadcom/bcm63xx_enet.c | 18 ++++++++---------- + 1 files changed, 8 insertions(+), 10 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c ++++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c +@@ -1594,7 +1594,6 @@ static int __devinit bcm_enet_probe(stru + struct resource *res_mem, *res_irq, *res_irq_rx, *res_irq_tx; + struct mii_bus *bus; + const char *clk_name; +- unsigned int iomem_size; + int i, ret; + + /* stop if shared driver failed, assume driver->probe will be +@@ -1619,13 +1618,13 @@ static int __devinit bcm_enet_probe(stru + if (ret) + goto out; + +- iomem_size = resource_size(res_mem); +- if (!request_mem_region(res_mem->start, iomem_size, "bcm63xx_enet")) { ++ if (!request_mem_region(res_mem->start, resource_size(res_mem), ++ "bcm63xx_enet")) { + ret = -EBUSY; + goto out; + } + +- priv->base = ioremap(res_mem->start, iomem_size); ++ priv->base = ioremap(res_mem->start, resource_size(res_mem)); + if (priv->base == NULL) { + ret = -ENOMEM; + goto out_release_mem; +@@ -1831,7 +1830,7 @@ out_unmap: + iounmap(priv->base); + + out_release_mem: +- release_mem_region(res_mem->start, iomem_size); ++ release_mem_region(res_mem->start, resource_size(res_mem)); + out: + free_netdev(dev); + return ret; +@@ -1903,19 +1902,18 @@ struct platform_driver bcm63xx_enet_driv + static int __devinit bcm_enet_shared_probe(struct platform_device *pdev) + { + struct resource *res; +- unsigned int iomem_size; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + +- iomem_size = resource_size(res); +- if (!request_mem_region(res->start, iomem_size, "bcm63xx_enet_dma")) ++ if (!request_mem_region(res->start, resource_size(res), ++ "bcm63xx_enet_dma")) + return -EBUSY; + +- bcm_enet_shared_base = ioremap(res->start, iomem_size); ++ bcm_enet_shared_base = ioremap(res->start, resource_size(res)); + if (!bcm_enet_shared_base) { +- release_mem_region(res->start, iomem_size); ++ release_mem_region(res->start, resource_size(res)); + return -ENOMEM; + } + return 0; diff --git a/target/linux/brcm63xx/patches-3.3/413-bcm63xx_enet-disable-clock-when-uninitializing-devic.patch b/target/linux/brcm63xx/patches-3.3/413-bcm63xx_enet-disable-clock-when-uninitializing-devic.patch new file mode 100644 index 0000000000..a98bea9001 --- /dev/null +++ b/target/linux/brcm63xx/patches-3.3/413-bcm63xx_enet-disable-clock-when-uninitializing-devic.patch @@ -0,0 +1,20 @@ +From fd15ecd10c95480be5635f8993b781fe3a1527c2 Mon Sep 17 00:00:00 2001 +From: Maxime Bizon +Date: Fri, 29 Apr 2011 16:54:50 +0200 +Subject: [PATCH 29/63] bcm63xx_enet: disable clock when uninitializing device. + +--- + drivers/net/ethernet/broadcom/bcm63xx_enet.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c ++++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c +@@ -1870,6 +1870,8 @@ static int __devexit bcm_enet_remove(str + } + + /* release device resources */ ++ clk_disable(priv->mac_clk); ++ clk_put(priv->mac_clk); + iounmap(priv->base); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); diff --git a/target/linux/brcm63xx/patches-3.3/414-bcm63xx_enet-split-dma-registers-access.patch b/target/linux/brcm63xx/patches-3.3/414-bcm63xx_enet-split-dma-registers-access.patch new file mode 100644 index 0000000000..483ff38140 --- /dev/null +++ b/target/linux/brcm63xx/patches-3.3/414-bcm63xx_enet-split-dma-registers-access.patch @@ -0,0 +1,381 @@ +From 305579c1f946ed1aa6c125252ace21c53d47c11d Mon Sep 17 00:00:00 2001 +From: Maxime Bizon +Date: Thu, 21 Jan 2010 17:50:54 +0100 +Subject: [PATCH 30/63] bcm63xx_enet: split dma registers access. + +--- + arch/mips/bcm63xx/dev-enet.c | 23 +++- + arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 4 +- + drivers/net/ethernet/broadcom/bcm63xx_enet.c | 179 ++++++++++++++-------- + 3 files changed, 138 insertions(+), 68 deletions(-) + +--- a/arch/mips/bcm63xx/dev-enet.c ++++ b/arch/mips/bcm63xx/dev-enet.c +@@ -19,6 +19,16 @@ static struct resource shared_res[] = { + .end = -1, /* filled at runtime */ + .flags = IORESOURCE_MEM, + }, ++ { ++ .start = -1, /* filled at runtime */ ++ .end = -1, /* filled at runtime */ ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = -1, /* filled at runtime */ ++ .end = -1, /* filled at runtime */ ++ .flags = IORESOURCE_MEM, ++ }, + }; + + static struct platform_device bcm63xx_enet_shared_device = { +@@ -110,10 +120,15 @@ int __init bcm63xx_enet_register(int uni + if (!shared_device_registered) { + shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); + shared_res[0].end = shared_res[0].start; +- if (BCMCPU_IS_6338()) +- shared_res[0].end += (RSET_ENETDMA_SIZE / 2) - 1; +- else +- shared_res[0].end += (RSET_ENETDMA_SIZE) - 1; ++ shared_res[0].end += (RSET_ENETDMA_SIZE) - 1; ++ ++ shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC); ++ shared_res[1].end = shared_res[1].start; ++ shared_res[1].end += RSET_ENETDMAC_SIZE(16) - 1; ++ ++ shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS); ++ shared_res[2].end = shared_res[2].start; ++ shared_res[2].end += RSET_ENETDMAS_SIZE(16) - 1; + + ret = platform_device_register(&bcm63xx_enet_shared_device); + if (ret) +--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h ++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +@@ -136,7 +136,9 @@ enum bcm63xx_regs_set { + #define RSET_DSL_SIZE 4096 + #define RSET_WDT_SIZE 12 + #define RSET_ENET_SIZE 2048 +-#define RSET_ENETDMA_SIZE 2048 ++#define RSET_ENETDMA_SIZE 256 ++#define RSET_ENETDMAC_SIZE(chans) (16 * (chans)) ++#define RSET_ENETDMAS_SIZE(chans) (16 * (chans)) + #define RSET_ENETSW_SIZE 65536 + #define RSET_SPI_SIZE 256 + #define RSET_UART_SIZE 24 +--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c ++++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c +@@ -41,8 +41,8 @@ static int copybreak __read_mostly = 128 + module_param(copybreak, int, 0); + MODULE_PARM_DESC(copybreak, "Receive copy threshold"); + +-/* io memory shared between all devices */ +-static void __iomem *bcm_enet_shared_base; ++/* io registers memory shared between all devices */ ++static void __iomem *bcm_enet_shared_base[3]; + + /* + * io helpers to access mac registers +@@ -63,13 +63,35 @@ static inline void enet_writel(struct bc + */ + static inline u32 enet_dma_readl(struct bcm_enet_priv *priv, u32 off) + { +- return bcm_readl(bcm_enet_shared_base + off); ++ return bcm_readl(bcm_enet_shared_base[0] + off); + } + + static inline void enet_dma_writel(struct bcm_enet_priv *priv, + u32 val, u32 off) + { +- bcm_writel(val, bcm_enet_shared_base + off); ++ bcm_writel(val, bcm_enet_shared_base[0] + off); ++} ++ ++static inline u32 enet_dmac_readl(struct bcm_enet_priv *priv, u32 off) ++{ ++ return bcm_readl(bcm_enet_shared_base[1] + off); ++} ++ ++static inline void enet_dmac_writel(struct bcm_enet_priv *priv, ++ u32 val, u32 off) ++{ ++ bcm_writel(val, bcm_enet_shared_base[1] + off); ++} ++ ++static inline u32 enet_dmas_readl(struct bcm_enet_priv *priv, u32 off) ++{ ++ return bcm_readl(bcm_enet_shared_base[2] + off); ++} ++ ++static inline void enet_dmas_writel(struct bcm_enet_priv *priv, ++ u32 val, u32 off) ++{ ++ bcm_writel(val, bcm_enet_shared_base[2] + off); + } + + /* +@@ -353,8 +375,8 @@ static int bcm_enet_receive_queue(struct + bcm_enet_refill_rx(dev); + + /* kick rx dma */ +- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, +- ENETDMA_CHANCFG_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_CHANCFG_EN_MASK, ++ ENETDMAC_CHANCFG_REG(priv->rx_chan)); + } + + return processed; +@@ -429,10 +451,10 @@ static int bcm_enet_poll(struct napi_str + dev = priv->net_dev; + + /* ack interrupts */ +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IR_REG(priv->rx_chan)); +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IR_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IR_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IR_REG(priv->tx_chan)); + + /* reclaim sent skb */ + tx_work_done = bcm_enet_tx_reclaim(dev, 0); +@@ -451,10 +473,10 @@ static int bcm_enet_poll(struct napi_str + napi_complete(napi); + + /* restore rx/tx interrupt */ +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IRMASK_REG(priv->rx_chan)); +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IRMASK_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IRMASK_REG(priv->tx_chan)); + + return rx_work_done; + } +@@ -497,8 +519,8 @@ static irqreturn_t bcm_enet_isr_dma(int + priv = netdev_priv(dev); + + /* mask rx/tx interrupts */ +- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->tx_chan)); + + napi_schedule(&priv->napi); + +@@ -557,8 +579,8 @@ static int bcm_enet_start_xmit(struct sk + wmb(); + + /* kick tx dma */ +- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, +- ENETDMA_CHANCFG_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_CHANCFG_EN_MASK, ++ ENETDMAC_CHANCFG_REG(priv->tx_chan)); + + /* stop queue if no more desc available */ + if (!priv->tx_desc_count) +@@ -801,8 +823,8 @@ static int bcm_enet_open(struct net_devi + + /* mask all interrupts and request them */ + enet_writel(priv, 0, ENET_IRMASK_REG); +- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->tx_chan)); + + ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev); + if (ret) +@@ -891,28 +913,28 @@ static int bcm_enet_open(struct net_devi + } + + /* write rx & tx ring addresses */ +- enet_dma_writel(priv, priv->rx_desc_dma, +- ENETDMA_RSTART_REG(priv->rx_chan)); +- enet_dma_writel(priv, priv->tx_desc_dma, +- ENETDMA_RSTART_REG(priv->tx_chan)); ++ enet_dmas_writel(priv, priv->rx_desc_dma, ++ ENETDMAS_RSTART_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, priv->tx_desc_dma, ++ ENETDMAS_RSTART_REG(priv->tx_chan)); + + /* clear remaining state ram for rx & tx channel */ +- enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->rx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->tx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->rx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->tx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->rx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->tx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG(priv->tx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG(priv->tx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG(priv->tx_chan)); + + /* set max rx/tx length */ + enet_writel(priv, priv->hw_mtu, ENET_RXMAXLEN_REG); + enet_writel(priv, priv->hw_mtu, ENET_TXMAXLEN_REG); + + /* set dma maximum burst len */ +- enet_dma_writel(priv, BCMENET_DMA_MAXBURST, +- ENETDMA_MAXBURST_REG(priv->rx_chan)); +- enet_dma_writel(priv, BCMENET_DMA_MAXBURST, +- ENETDMA_MAXBURST_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, BCMENET_DMA_MAXBURST, ++ ENETDMAC_MAXBURST_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, BCMENET_DMA_MAXBURST, ++ ENETDMAC_MAXBURST_REG(priv->tx_chan)); + + /* set correct transmit fifo watermark */ + enet_writel(priv, BCMENET_TX_FIFO_TRESH, ENET_TXWMARK_REG); +@@ -930,26 +952,26 @@ static int bcm_enet_open(struct net_devi + val |= ENET_CTL_ENABLE_MASK; + enet_writel(priv, val, ENET_CTL_REG); + enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); +- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK, +- ENETDMA_CHANCFG_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_CHANCFG_EN_MASK, ++ ENETDMAC_CHANCFG_REG(priv->rx_chan)); + + /* watch "mib counters about to overflow" interrupt */ + enet_writel(priv, ENET_IR_MIB, ENET_IR_REG); + enet_writel(priv, ENET_IR_MIB, ENET_IRMASK_REG); + + /* watch "packet transferred" interrupt in rx and tx */ +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IR_REG(priv->rx_chan)); +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IR_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IR_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IR_REG(priv->tx_chan)); + + /* make sure we enable napi before rx interrupt */ + napi_enable(&priv->napi); + +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IRMASK_REG(priv->rx_chan)); +- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +- ENETDMA_IRMASK_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IRMASK_REG(priv->tx_chan)); + + if (priv->has_phy) + phy_start(priv->phydev); +@@ -1026,14 +1048,14 @@ static void bcm_enet_disable_dma(struct + { + int limit; + +- enet_dma_writel(priv, 0, ENETDMA_CHANCFG_REG(chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_CHANCFG_REG(chan)); + + limit = 1000; + do { + u32 val; + +- val = enet_dma_readl(priv, ENETDMA_CHANCFG_REG(chan)); +- if (!(val & ENETDMA_CHANCFG_EN_MASK)) ++ val = enet_dmac_readl(priv, ENETDMAC_CHANCFG_REG(chan)); ++ if (!(val & ENETDMAC_CHANCFG_EN_MASK)) + break; + udelay(1); + } while (limit--); +@@ -1059,8 +1081,8 @@ static int bcm_enet_stop(struct net_devi + + /* mask all interrupts */ + enet_writel(priv, 0, ENET_IRMASK_REG); +- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); +- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->tx_chan)); + + /* make sure no mib update is scheduled */ + cancel_work_sync(&priv->mib_update_task); +@@ -1598,7 +1620,7 @@ static int __devinit bcm_enet_probe(stru + + /* stop if shared driver failed, assume driver->probe will be + * called in the same order we register devices (correct ?) */ +- if (!bcm_enet_shared_base) ++ if (!bcm_enet_shared_base[0]) + return -ENODEV; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -1904,30 +1926,61 @@ struct platform_driver bcm63xx_enet_driv + static int __devinit bcm_enet_shared_probe(struct platform_device *pdev) + { + struct resource *res; ++ int ret, i, requested[3]; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) +- return -ENODEV; ++ memset(bcm_enet_shared_base, 0, sizeof (bcm_enet_shared_base)); ++ memset(requested, 0, sizeof (requested)); + +- if (!request_mem_region(res->start, resource_size(res), +- "bcm63xx_enet_dma")) +- return -EBUSY; ++ for (i = 0; i < 3; i++) { ++ void __iomem *p; + +- bcm_enet_shared_base = ioremap(res->start, resource_size(res)); +- if (!bcm_enet_shared_base) { +- release_mem_region(res->start, resource_size(res)); +- return -ENOMEM; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ if (!res) { ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ if (!request_mem_region(res->start, resource_size(res), ++ "bcm63xx_enet_dma")) { ++ ret = -EBUSY; ++ goto fail; ++ } ++ requested[i] = 0; ++ ++ p = ioremap(res->start, resource_size(res)); ++ if (!p) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ bcm_enet_shared_base[i] = p; + } ++ + return 0; ++ ++fail: ++ for (i = 0; i < 3; i++) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ if (!res) ++ continue; ++ if (bcm_enet_shared_base[i]) ++ iounmap(bcm_enet_shared_base[i]); ++ if (requested[i]) ++ release_mem_region(res->start, resource_size(res)); ++ } ++ return ret; + } + + static int __devexit bcm_enet_shared_remove(struct platform_device *pdev) + { + struct resource *res; ++ int i; + +- iounmap(bcm_enet_shared_base); +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- release_mem_region(res->start, resource_size(res)); ++ for (i = 0; i < 3; i++) { ++ iounmap(bcm_enet_shared_base[i]); ++ res = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ release_mem_region(res->start, resource_size(res)); ++ } + return 0; + } + diff --git a/target/linux/brcm63xx/patches-3.3/415-bcm63xx_enet-add-support-for-bcm6368-internal-ethern.patch b/target/linux/brcm63xx/patches-3.3/415-bcm63xx_enet-add-support-for-bcm6368-internal-ethern.patch new file mode 100644 index 0000000000..7043df6f8e --- /dev/null +++ b/target/linux/brcm63xx/patches-3.3/415-bcm63xx_enet-add-support-for-bcm6368-internal-ethern.patch @@ -0,0 +1,1490 @@ +From 1324bb5db6815d19b09c1b7bcac3cc2804412205 Mon Sep 17 00:00:00 2001 +From: Maxime Bizon +Date: Sat, 23 Jan 2010 03:01:02 +0100 +Subject: [PATCH 31/63] bcm63xx_enet: add support for bcm6368 internal ethernet switch. + +--- + arch/mips/bcm63xx/dev-enet.c | 106 ++- + .../include/asm/mach-bcm63xx/bcm63xx_dev_enet.h | 25 + + arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 50 + + drivers/net/ethernet/broadcom/bcm63xx_enet.c | 1054 ++++++++++++++++++-- + drivers/net/ethernet/broadcom/bcm63xx_enet.h | 71 ++ + 5 files changed, 1221 insertions(+), 85 deletions(-) + +--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c ++++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c +@@ -945,6 +945,10 @@ int __init board_register_devices(void) + !board_get_mac_address(board.enet1.mac_addr)) + bcm63xx_enet_register(1, &board.enet1); + ++ if (board.has_enetsw && ++ !board_get_mac_address(board.enetsw.mac_addr)) ++ bcm63xx_enetsw_register(&board.enetsw); ++ + if (board.has_ehci0) + bcm63xx_ehci_register(); + +--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h ++++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h +@@ -41,6 +41,7 @@ struct board_info { + /* enabled feature/device */ + unsigned int has_enet0:1; + unsigned int has_enet1:1; ++ unsigned int has_enetsw:1; + unsigned int has_pci:1; + unsigned int has_pccard:1; + unsigned int has_ohci0:1; +@@ -52,6 +53,7 @@ struct board_info { + /* ethernet config */ + struct bcm63xx_enet_platform_data enet0; + struct bcm63xx_enet_platform_data enet1; ++ struct bcm63xx_enetsw_platform_data enetsw; + + /* DSP config */ + struct bcm63xx_dsp_platform_data dsp; +--- a/arch/mips/bcm63xx/dev-enet.c ++++ b/arch/mips/bcm63xx/dev-enet.c +@@ -104,6 +104,64 @@ static struct platform_device bcm63xx_en + }, + }; + ++static struct resource enetsw_res[] = { ++ { ++ /* start & end filled at runtime */ ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ /* start filled at runtime */ ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ /* start filled at runtime */ ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct bcm63xx_enetsw_platform_data enetsw_pd; ++ ++static struct platform_device bcm63xx_enetsw_device = { ++ .name = "bcm63xx_enetsw", ++ .num_resources = ARRAY_SIZE(enetsw_res), ++ .resource = enetsw_res, ++ .dev = { ++ .platform_data = &enetsw_pd, ++ }, ++}; ++ ++static int __init register_shared(void) ++{ ++ int ret, chan_count; ++ ++ if (shared_device_registered) ++ return 0; ++ ++ shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); ++ shared_res[0].end = shared_res[0].start; ++ shared_res[0].end += (RSET_ENETDMA_SIZE) - 1; ++ ++ if (BCMCPU_IS_6368()) ++ chan_count = 32; ++ else ++ chan_count = 16; ++ ++ shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC); ++ shared_res[1].end = shared_res[1].start; ++ shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count) - 1; ++ ++ shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS); ++ shared_res[2].end = shared_res[2].start; ++ shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count) - 1; ++ ++ ret = platform_device_register(&bcm63xx_enet_shared_device); ++ if (ret) ++ return ret; ++ shared_device_registered = 1; ++ ++ return 0; ++} ++ + int __init bcm63xx_enet_register(int unit, + const struct bcm63xx_enet_platform_data *pd) + { +@@ -117,24 +175,9 @@ int __init bcm63xx_enet_register(int uni + if (unit == 1 && BCMCPU_IS_6338()) + return -ENODEV; + +- if (!shared_device_registered) { +- shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); +- shared_res[0].end = shared_res[0].start; +- shared_res[0].end += (RSET_ENETDMA_SIZE) - 1; +- +- shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC); +- shared_res[1].end = shared_res[1].start; +- shared_res[1].end += RSET_ENETDMAC_SIZE(16) - 1; +- +- shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS); +- shared_res[2].end = shared_res[2].start; +- shared_res[2].end += RSET_ENETDMAS_SIZE(16) - 1; +- +- ret = platform_device_register(&bcm63xx_enet_shared_device); +- if (ret) +- return ret; +- shared_device_registered = 1; +- } ++ ret = register_shared(); ++ if (ret) ++ return ret; + + if (unit == 0) { + enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0); +@@ -175,3 +218,30 @@ int __init bcm63xx_enet_register(int uni + return ret; + return 0; + } ++ ++int __init ++bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd) ++{ ++ int ret; ++ ++ if (!BCMCPU_IS_6368()) ++ return -ENODEV; ++ ++ ret = register_shared(); ++ if (ret) ++ return ret; ++ ++ enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW); ++ enetsw_res[0].end = enetsw_res[0].start; ++ enetsw_res[0].end += RSET_ENETSW_SIZE - 1; ++ enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0); ++ enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0); ++ ++ memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof (*pd)); ++ ++ ret = platform_device_register(&bcm63xx_enetsw_device); ++ if (ret) ++ return ret; ++ ++ return 0; ++} +--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h ++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h +@@ -39,7 +39,32 @@ struct bcm63xx_enet_platform_data { + int phy_id, int reg, int val)); + }; + ++/* ++ * on board ethernet switch platform data ++ */ ++#define ENETSW_MAX_PORT 6 ++ ++struct bcm63xx_enetsw_port { ++ int used; ++ int external_phy; ++ int phy_id; ++ ++ int bypass_link; ++ int force_speed; ++ int force_duplex_full; ++ ++ const char *name; ++}; ++ ++struct bcm63xx_enetsw_platform_data { ++ char mac_addr[ETH_ALEN]; ++ struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT]; ++}; ++ + int __init bcm63xx_enet_register(int unit, + const struct bcm63xx_enet_platform_data *pd); + ++int __init ++bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd); ++ + #endif /* ! BCM63XX_DEV_ENET_H_ */ +--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h ++++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +@@ -699,10 +699,60 @@ + * _REG relative to RSET_ENETSW + *************************************************************************/ + ++/* Port traffic control */ ++#define ENETSW_PTCTRL_REG(x) (0x0 + (x)) ++#define ENETSW_PTCTRL_RXDIS_MASK (1 << 0) ++#define ENETSW_PTCTRL_TXDIS_MASK (1 << 1) ++ ++/* Switch mode register */ ++#define ENETSW_SWMODE_REG (0xb) ++#define ENETSW_SWMODE_FWD_EN_MASK (1 << 1) ++ ++/* IMP override Register */ ++#define ENETSW_IMPOV_REG (0xe) ++#define ENETSW_IMPOV_FORCE_MASK (1 << 7) ++#define ENETSW_IMPOV_TXFLOW_MASK (1 << 5) ++#define ENETSW_IMPOV_RXFLOW_MASK (1 << 4) ++#define ENETSW_IMPOV_1000_MASK (1 << 3) ++#define ENETSW_IMPOV_100_MASK (1 << 2) ++#define ENETSW_IMPOV_FDX_MASK (1 << 1) ++#define ENETSW_IMPOV_LINKUP_MASK (1 << 0) ++ ++/* Port override Register */ ++#define ENETSW_PORTOV_REG(x) (0x58 + (x)) ++#define ENETSW_PORTOV_ENABLE_MASK (1 << 6) ++#define ENETSW_PORTOV_TXFLOW_MASK (1 << 5) ++#define ENETSW_PORTOV_RXFLOW_MASK (1 << 4) ++#define ENETSW_PORTOV_1000_MASK (1 << 3) ++#define ENETSW_PORTOV_100_MASK (1 << 2) ++#define ENETSW_PORTOV_FDX_MASK (1 << 1) ++#define ENETSW_PORTOV_LINKUP_MASK (1 << 0) ++ ++/* MDIO control register */ ++#define ENETSW_MDIOC_REG (0xb0) ++#define ENETSW_MDIOC_EXT_MASK (1 << 16) ++#define ENETSW_MDIOC_REG_SHIFT 20 ++#define ENETSW_MDIOC_PHYID_SHIFT 25 ++#define ENETSW_MDIOC_RD_MASK (1 << 30) ++#define ENETSW_MDIOC_WR_MASK (1 << 31) ++ ++/* MDIO data register */ ++#define ENETSW_MDIOD_REG (0xb4) ++ ++/* Global Management Configuration Register */ ++#define ENETSW_GMCR_REG (0x200) ++#define ENETSW_GMCR_RST_MIB_MASK (1 << 0) ++ + /* MIB register */ + #define ENETSW_MIB_REG(x) (0x2800 + (x) * 4) + #define ENETSW_MIB_REG_COUNT 47 + ++/* Jumbo control register port mask register */ ++#define ENETSW_JMBCTL_PORT_REG (0x4004) ++ ++/* Jumbo control mib good frame register */ ++#define ENETSW_JMBCTL_MAXSIZE_REG (0x4008) ++ + + /************************************************************************* + * _REG relative to RSET_OHCI_PRIV +--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c ++++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c +@@ -59,6 +59,49 @@ static inline void enet_writel(struct bc + } + + /* ++ * io helpers to access switch registers ++ */ ++static inline u32 enetsw_readl(struct bcm_enet_priv *priv, u32 off) ++{ ++ /* printk("enetsw_readl at %p\n", priv->base + off); */ ++ return bcm_readl(priv->base + off); ++} ++ ++static inline void enetsw_writel(struct bcm_enet_priv *priv, ++ u32 val, u32 off) ++{ ++ /* printk("enetsw_writel %08x at %p\n", val, priv->base + off); */ ++ bcm_writel(val, priv->base + off); ++} ++ ++static inline u16 enetsw_readw(struct bcm_enet_priv *priv, u32 off) ++{ ++ /* printk("enetsw_readw at %p\n", priv->base + off); */ ++ return bcm_readw(priv->base + off); ++} ++ ++static inline void enetsw_writew(struct bcm_enet_priv *priv, ++ u16 val, u32 off) ++{ ++ /* printk("enetsw_writew %04x at %p\n", val, priv->base + off); */ ++ bcm_writew(val, priv->base + off); ++} ++ ++static inline u8 enetsw_readb(struct bcm_enet_priv *priv, u32 off) ++{ ++ /* printk("enetsw_readb at %p\n", priv->base + off); */ ++ return bcm_readb(priv->base + off); ++} ++ ++static inline void enetsw_writeb(struct bcm_enet_priv *priv, ++ u8 val, u32 off) ++{ ++ /* printk("enetsw_writeb %02x at %p\n", val, priv->base + off); */ ++ bcm_writeb(val, priv->base + off); ++} ++ ++ ++/* + * io helpers to access shared registers + */ + static inline u32 enet_dma_readl(struct bcm_enet_priv *priv, u32 off) +@@ -321,7 +364,8 @@ static int bcm_enet_receive_queue(struct + } + + /* recycle packet if it's marked as bad */ +- if (unlikely(len_stat & DMADESC_ERR_MASK)) { ++ if (!bcm_enet_is_sw(priv) && ++ unlikely(len_stat & DMADESC_ERR_MASK)) { + dev->stats.rx_errors++; + + if (len_stat & DMADESC_OVSIZE_MASK) +@@ -552,6 +596,26 @@ static int bcm_enet_start_xmit(struct sk + goto out_unlock; + } + ++ /* pad small packets sent on a switch device */ ++ if (bcm_enet_is_sw(priv) && skb->len < 64) { ++ int needed = 64 - skb->len; ++ char *data; ++ ++ if (unlikely(skb_tailroom(skb) < needed)) { ++ struct sk_buff *nskb; ++ ++ nskb = skb_copy_expand(skb, 0, needed, GFP_ATOMIC); ++ if (!nskb) { ++ ret = NETDEV_TX_BUSY; ++ goto out_unlock; ++ } ++ dev_kfree_skb(skb); ++ skb = nskb; ++ } ++ data = skb_put(skb, needed); ++ memset(data, 0, needed); ++ } ++ + /* point to the next available desc */ + desc = &priv->tx_desc_cpu[priv->tx_curr_desc]; + priv->tx_skb[priv->tx_curr_desc] = skb; +@@ -1921,96 +1985,951 @@ struct platform_driver bcm63xx_enet_driv + }; + + /* +- * reserve & remap memory space shared between all macs ++ * switch mii access callbacks + */ +-static int __devinit bcm_enet_shared_probe(struct platform_device *pdev) ++static int bcmenet_sw_mdio_read(struct bcm_enet_priv *priv, ++ int ext, int phy_id, int location) + { +- struct resource *res; +- int ret, i, requested[3]; ++ u32 reg; ++ int ret; + +- memset(bcm_enet_shared_base, 0, sizeof (bcm_enet_shared_base)); +- memset(requested, 0, sizeof (requested)); ++ spin_lock_bh(&priv->enetsw_mdio_lock); ++ enetsw_writel(priv, 0, ENETSW_MDIOC_REG); + +- for (i = 0; i < 3; i++) { +- void __iomem *p; ++ reg = ENETSW_MDIOC_RD_MASK | ++ (phy_id << ENETSW_MDIOC_PHYID_SHIFT) | ++ (location << ENETSW_MDIOC_REG_SHIFT); ++ ++ if (ext) ++ reg |= ENETSW_MDIOC_EXT_MASK; ++ ++ enetsw_writel(priv, reg, ENETSW_MDIOC_REG); ++ udelay(50); ++ ret = enetsw_readw(priv, ENETSW_MDIOD_REG); ++ spin_unlock_bh(&priv->enetsw_mdio_lock); ++ return ret; ++} + +- res = platform_get_resource(pdev, IORESOURCE_MEM, i); +- if (!res) { +- ret = -EINVAL; +- goto fail; +- } ++static void bcmenet_sw_mdio_write(struct bcm_enet_priv *priv, ++ int ext, int phy_id, int location, ++ uint16_t data) ++{ ++ u32 reg; + +- if (!request_mem_region(res->start, resource_size(res), +- "bcm63xx_enet_dma")) { +- ret = -EBUSY; +- goto fail; +- } +- requested[i] = 0; ++ spin_lock_bh(&priv->enetsw_mdio_lock); ++ enetsw_writel(priv, 0, ENETSW_MDIOC_REG); + +- p = ioremap(res->start, resource_size(res)); +- if (!p) { +- ret = -ENOMEM; +- goto fail; +- } ++ reg = ENETSW_MDIOC_WR_MASK | ++ (phy_id << ENETSW_MDIOC_PHYID_SHIFT) | ++ (location << ENETSW_MDIOC_REG_SHIFT); + +- bcm_enet_shared_base[i] = p; +- } ++ if (ext) ++ reg |= ENETSW_MDIOC_EXT_MASK; + +- return 0; ++ reg |= data; + +-fail: +- for (i = 0; i < 3; i++) { +- res = platform_get_resource(pdev, IORESOURCE_MEM, i); +- if (!res) +- continue; +- if (bcm_enet_shared_base[i]) +- iounmap(bcm_enet_shared_base[i]); +- if (requested[i]) +- release_mem_region(res->start, resource_size(res)); +- } +- return ret; ++ enetsw_writel(priv, reg, ENETSW_MDIOC_REG); ++ udelay(50); ++ spin_unlock_bh(&priv->enetsw_mdio_lock); + } + +-static int __devexit bcm_enet_shared_remove(struct platform_device *pdev) ++/* ++ * enet sw PHY polling ++ */ ++static void swphy_poll_timer(unsigned long data) + { +- struct resource *res; +- int i; ++ struct bcm_enet_priv *priv = (struct bcm_enet_priv *)data; ++ unsigned int i; + +- for (i = 0; i < 3; i++) { +- iounmap(bcm_enet_shared_base[i]); +- res = platform_get_resource(pdev, IORESOURCE_MEM, i); +- release_mem_region(res->start, resource_size(res)); ++ for (i = 0; i < ARRAY_SIZE(priv->used_ports); i++) { ++ struct bcm63xx_enetsw_port *port; ++ int val, j, up, advertise, lpa, lpa2, speed, duplex, media; ++ u8 override; ++ ++ port = &priv->used_ports[i]; ++ if (!port->used) ++ continue; ++ ++ if (port->bypass_link) ++ continue; ++ ++ /* dummy read to clear */ ++ for (j = 0; j < 2; j++) ++ val = bcmenet_sw_mdio_read(priv, port->external_phy, ++ port->phy_id, MII_BMSR); ++ ++ if (val == 0xffff) ++ continue; ++ ++ up = (val & BMSR_LSTATUS) ? 1 : 0; ++ if (!(up ^ priv->sw_port_link[i])) ++ continue; ++ ++ priv->sw_port_link[i] = up; ++ ++ /* link changed */ ++ if (!up) { ++ dev_info(&priv->pdev->dev, "link DOWN on %s\n", ++ port->name); ++ enetsw_writeb(priv, ENETSW_PORTOV_ENABLE_MASK, ++ ENETSW_PORTOV_REG(i)); ++ enetsw_writeb(priv, ENETSW_PTCTRL_RXDIS_MASK | ++ ENETSW_PTCTRL_TXDIS_MASK, ++ ENETSW_PTCTRL_REG(i)); ++ continue; ++ } ++ ++ advertise = bcmenet_sw_mdio_read(priv, port->external_phy, ++ port->phy_id, MII_ADVERTISE); ++ ++ lpa = bcmenet_sw_mdio_read(priv, port->external_phy, ++ port->phy_id, MII_LPA); ++ ++ lpa2 = bcmenet_sw_mdio_read(priv, port->external_phy, ++ port->phy_id, MII_STAT1000); ++ ++ /* figure out media and duplex from advertise and LPA values */ ++ media = mii_nway_result(lpa & advertise); ++ duplex = (media & ADVERTISE_FULL) ? 1 : 0; ++ if (lpa2 & LPA_1000FULL) ++ duplex = 1; ++ ++ if (lpa2 & (LPA_1000FULL | LPA_1000HALF)) ++ speed = 1000; ++ else { ++ if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ++ speed = 100; ++ else ++ speed = 10; ++ } ++ ++ dev_info(&priv->pdev->dev, ++ "link UP on %s, %dMbps, %s-duplex\n", ++ port->name, speed, duplex ? "full" : "half"); ++ ++ override = ENETSW_PORTOV_ENABLE_MASK | ++ ENETSW_PORTOV_LINKUP_MASK; ++ ++ if (speed == 1000) ++ override |= ENETSW_IMPOV_1000_MASK; ++ else if (speed == 100) ++ override |= ENETSW_IMPOV_100_MASK; ++ if (duplex) ++ override |= ENETSW_IMPOV_FDX_MASK; ++ ++ enetsw_writeb(priv, override, ENETSW_PORTOV_REG(i)); ++ enetsw_writeb(priv, 0, ENETSW_PTCTRL_REG(i)); + } +- return 0; +-} + +-/* +- * this "shared" driver is needed because both macs share a single +- * address space +- */ +-struct platform_driver bcm63xx_enet_shared_driver = { +- .probe = bcm_enet_shared_probe, +- .remove = __devexit_p(bcm_enet_shared_remove), +- .driver = { +- .name = "bcm63xx_enet_shared", +- .owner = THIS_MODULE, +- }, +-}; ++ priv->swphy_poll.expires = jiffies + HZ; ++ add_timer(&priv->swphy_poll); ++} + + /* +- * entry point ++ * open callback, allocate dma rings & buffers and start rx operation + */ +-static int __init bcm_enet_init(void) ++static int bcm_enetsw_open(struct net_device *dev) + { +- int ret; ++ struct bcm_enet_priv *priv; ++ struct device *kdev; ++ int i, ret; ++ unsigned int size; ++ void *p; ++ u32 val; + +- ret = platform_driver_register(&bcm63xx_enet_shared_driver); ++ priv = netdev_priv(dev); ++ kdev = &priv->pdev->dev; ++ ++ /* mask all interrupts and request them */ ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->tx_chan)); ++ ++ ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, ++ IRQF_DISABLED, dev->name, dev); + if (ret) +- return ret; ++ goto out_freeirq; + +- ret = platform_driver_register(&bcm63xx_enet_driver); ++ ret = request_irq(priv->irq_tx, bcm_enet_isr_dma, ++ IRQF_DISABLED, dev->name, dev); + if (ret) +- platform_driver_unregister(&bcm63xx_enet_shared_driver); ++ goto out_freeirq_rx; ++ ++ /* allocate rx dma ring */ ++ size = priv->rx_ring_size * sizeof(struct bcm_enet_desc); ++ p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); ++ if (!p) { ++ dev_err(kdev, "cannot allocate rx ring %u\n", size); ++ ret = -ENOMEM; ++ goto out_freeirq_tx; ++ } ++ ++ memset(p, 0, size); ++ priv->rx_desc_alloc_size = size; ++ priv->rx_desc_cpu = p; ++ ++ /* allocate tx dma ring */ ++ size = priv->tx_ring_size * sizeof(struct bcm_enet_desc); ++ p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); ++ if (!p) { ++ dev_err(kdev, "cannot allocate tx ring\n"); ++ ret = -ENOMEM; ++ goto out_free_rx_ring; ++ } ++ ++ memset(p, 0, size); ++ priv->tx_desc_alloc_size = size; ++ priv->tx_desc_cpu = p; ++ ++ priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size, ++ GFP_KERNEL); ++ if (!priv->tx_skb) { ++ dev_err(kdev, "cannot allocate rx skb queue\n"); ++ ret = -ENOMEM; ++ goto out_free_tx_ring; ++ } ++ ++ priv->tx_desc_count = priv->tx_ring_size; ++ priv->tx_dirty_desc = 0; ++ priv->tx_curr_desc = 0; ++ spin_lock_init(&priv->tx_lock); ++ ++ /* init & fill rx ring with skbs */ ++ priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size, ++ GFP_KERNEL); ++ if (!priv->rx_skb) { ++ dev_err(kdev, "cannot allocate rx skb queue\n"); ++ ret = -ENOMEM; ++ goto out_free_tx_skb; ++ } ++ ++ priv->rx_desc_count = 0; ++ priv->rx_dirty_desc = 0; ++ priv->rx_curr_desc = 0; ++ ++ /* disable all ports */ ++ for (i = 0; i < 6; i++) { ++ enetsw_writeb(priv, ENETSW_PORTOV_ENABLE_MASK, ++ ENETSW_PORTOV_REG(i)); ++ enetsw_writeb(priv, ENETSW_PTCTRL_RXDIS_MASK | ++ ENETSW_PTCTRL_TXDIS_MASK, ++ ENETSW_PTCTRL_REG(i)); ++ } ++ ++ /* reset mib */ ++ val = enetsw_readb(priv, ENETSW_GMCR_REG); ++ val |= ENETSW_GMCR_RST_MIB_MASK; ++ enetsw_writeb(priv, val, ENETSW_GMCR_REG); ++ mdelay(1); ++ val &= ~ENETSW_GMCR_RST_MIB_MASK; ++ enetsw_writeb(priv, val, ENETSW_GMCR_REG); ++ mdelay(1); ++ ++ /* force CPU port state */ ++ val = enetsw_readb(priv, ENETSW_IMPOV_REG); ++ val |= ENETSW_IMPOV_FORCE_MASK | ENETSW_IMPOV_LINKUP_MASK; ++ enetsw_writeb(priv, val, ENETSW_IMPOV_REG); ++ ++ /* enable switch forward engine */ ++ val = enetsw_readb(priv, ENETSW_SWMODE_REG); ++ val |= ENETSW_SWMODE_FWD_EN_MASK; ++ enetsw_writeb(priv, val, ENETSW_SWMODE_REG); ++ ++ /* enable jumbo on all ports */ ++ enetsw_writel(priv, 0x1ff, ENETSW_JMBCTL_PORT_REG); ++ enetsw_writew(priv, 9728, ENETSW_JMBCTL_MAXSIZE_REG); ++ ++ /* initialize flow control buffer allocation */ ++ enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, ++ ENETDMA_BUFALLOC_REG(priv->rx_chan)); ++ ++ if (bcm_enet_refill_rx(dev)) { ++ dev_err(kdev, "cannot allocate rx skb queue\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* write rx & tx ring addresses */ ++ enet_dmas_writel(priv, priv->rx_desc_dma, ++ ENETDMAS_RSTART_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, priv->tx_desc_dma, ++ ENETDMAS_RSTART_REG(priv->tx_chan)); ++ ++ /* clear remaining state ram for rx & tx channel */ ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG(priv->tx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG(priv->tx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG(priv->rx_chan)); ++ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG(priv->tx_chan)); ++ ++ /* set dma maximum burst len */ ++ enet_dmac_writel(priv, BCMENET_DMA_MAXBURST, ++ ENETDMAC_MAXBURST_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, BCMENET_DMA_MAXBURST, ++ ENETDMAC_MAXBURST_REG(priv->tx_chan)); ++ ++ /* set flow control low/high threshold to 1/3 / 2/3 */ ++ val = priv->rx_ring_size / 3; ++ enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan)); ++ val = (priv->rx_ring_size * 2) / 3; ++ enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan)); ++ ++ /* all set, enable mac and interrupts, start dma engine and ++ * kick rx dma channel */ ++ wmb(); ++ enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); ++ enet_dmac_writel(priv, ENETDMAC_CHANCFG_EN_MASK, ++ ENETDMAC_CHANCFG_REG(priv->rx_chan)); ++ ++ /* watch "packet transferred" interrupt in rx and tx */ ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IR_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IR_REG(priv->tx_chan)); ++ ++ /* make sure we enable napi before rx interrupt */ ++ napi_enable(&priv->napi); ++ ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK, ++ ENETDMAC_IRMASK_REG(priv->tx_chan)); ++ ++ netif_carrier_on(dev); ++ netif_start_queue(dev); ++ ++ /* ++ * apply override config for bypass_link ports here. ++ */ ++ for (i = 0; i < ARRAY_SIZE(priv->used_ports); i++) { ++ struct bcm63xx_enetsw_port *port; ++ u8 override; ++ port = &priv->used_ports[i]; ++ if (!port->used) ++ continue; ++ ++ if (!port->bypass_link) ++ continue; ++ ++ override = ENETSW_PORTOV_ENABLE_MASK | ++ ENETSW_PORTOV_LINKUP_MASK; ++ ++ switch (port->force_speed) { ++ case 1000: ++ override |= ENETSW_IMPOV_1000_MASK; ++ break; ++ case 100: ++ override |= ENETSW_IMPOV_100_MASK; ++ break; ++ case 10: ++ break; ++ default: ++ printk(KERN_WARNING "invalid forced speed on port %s: " ++ "assume 10\n", ++ port->name); ++ break; ++ } ++ ++ if (port->force_duplex_full) ++ override = ENETSW_IMPOV_FDX_MASK; ++ ++ ++ enetsw_writeb(priv, override, ENETSW_PORTOV_REG(i)); ++ enetsw_writeb(priv, 0, ENETSW_PTCTRL_REG(i)); ++ } ++ ++ /* start phy polling timer */ ++ init_timer(&priv->swphy_poll); ++ priv->swphy_poll.function = swphy_poll_timer; ++ priv->swphy_poll.data = (unsigned long)priv; ++ priv->swphy_poll.expires = jiffies; ++ add_timer(&priv->swphy_poll); ++ return 0; ++ ++out: ++ for (i = 0; i < priv->rx_ring_size; i++) { ++ struct bcm_enet_desc *desc; ++ ++ if (!priv->rx_skb[i]) ++ continue; ++ ++ desc = &priv->rx_desc_cpu[i]; ++ dma_unmap_single(kdev, desc->address, priv->rx_skb_size, ++ DMA_FROM_DEVICE); ++ kfree_skb(priv->rx_skb[i]); ++ } ++ kfree(priv->rx_skb); ++ ++out_free_tx_skb: ++ kfree(priv->tx_skb); ++ ++out_free_tx_ring: ++ dma_free_coherent(kdev, priv->tx_desc_alloc_size, ++ priv->tx_desc_cpu, priv->tx_desc_dma); ++ ++out_free_rx_ring: ++ dma_free_coherent(kdev, priv->rx_desc_alloc_size, ++ priv->rx_desc_cpu, priv->rx_desc_dma); ++ ++out_freeirq_tx: ++ free_irq(priv->irq_tx, dev); ++ ++out_freeirq_rx: ++ free_irq(priv->irq_rx, dev); ++ ++out_freeirq: ++ return ret; ++} ++ ++/* ++ * stop callback ++ */ ++static int bcm_enetsw_stop(struct net_device *dev) ++{ ++ struct bcm_enet_priv *priv; ++ struct device *kdev; ++ int i; ++ ++ priv = netdev_priv(dev); ++ kdev = &priv->pdev->dev; ++ ++ del_timer_sync(&priv->swphy_poll); ++ netif_stop_queue(dev); ++ napi_disable(&priv->napi); ++ del_timer_sync(&priv->rx_timeout); ++ ++ /* mask all interrupts */ ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->rx_chan)); ++ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK_REG(priv->tx_chan)); ++ ++ /* disable dma & mac */ ++ bcm_enet_disable_dma(priv, priv->tx_chan); ++ bcm_enet_disable_dma(priv, priv->rx_chan); ++ ++ /* force reclaim of all tx buffers */ ++ bcm_enet_tx_reclaim(dev, 1); ++ ++ /* free the rx skb ring */ ++ for (i = 0; i < priv->rx_ring_size; i++) { ++ struct bcm_enet_desc *desc; ++ ++ if (!priv->rx_skb[i]) ++ continue; ++ ++ desc = &priv->rx_desc_cpu[i]; ++ dma_unmap_single(kdev, desc->address, priv->rx_skb_size, ++ DMA_FROM_DEVICE); ++ kfree_skb(priv->rx_skb[i]); ++ } ++ ++ /* free remaining allocated memory */ ++ kfree(priv->rx_skb); ++ kfree(priv->tx_skb); ++ dma_free_coherent(kdev, priv->rx_desc_alloc_size, ++ priv->rx_desc_cpu, priv->rx_desc_dma); ++ dma_free_coherent(kdev, priv->tx_desc_alloc_size, ++ priv->tx_desc_cpu, priv->tx_desc_dma); ++ free_irq(priv->irq_tx, dev); ++ free_irq(priv->irq_rx, dev); ++ ++ return 0; ++} ++ ++/* ++ * try to sort out phy external status by walking the used_port field ++ * in the bcm_enet_priv structure. in case the phy address is not ++ * assigned to any physical port on the switch, assume it is external ++ * (and yell at the user). ++ */ ++static int bcm_enetsw_phy_is_external(struct bcm_enet_priv *priv, int phy_id) ++{ ++ int i; ++ ++ for (i = 0; i < (int)ARRAY_SIZE(priv->used_ports); ++i) { ++ if (!priv->used_ports[i].used) ++ continue; ++ if (priv->used_ports[i].phy_id == phy_id) ++ return priv->used_ports[i].external_phy; ++ } ++ ++ printk_once(KERN_WARNING "bcm63xx_enet: could not find a used port " ++ "with phy_id %i, assuming phy is external\n", phy_id); ++ return 1; ++} ++ ++/* ++ * can't use bcmenet_sw_mdio_read directly as we need to sort out ++ * external/internal status of the given phy_id first. ++ */ ++static int bcm_enetsw_mii_mdio_read(struct net_device *dev, int phy_id, ++ int location) ++{ ++ struct bcm_enet_priv *priv; ++ ++ priv = netdev_priv(dev); ++ return bcmenet_sw_mdio_read(priv, ++ bcm_enetsw_phy_is_external(priv, phy_id), ++ phy_id, location); ++} ++ ++/* ++ * can't use bcmenet_sw_mdio_write directly as we need to sort out ++ * external/internal status of the given phy_id first. ++ */ ++static void bcm_enetsw_mii_mdio_write(struct net_device *dev, int phy_id, ++ int location, ++ int val) ++{ ++ struct bcm_enet_priv *priv; ++ ++ priv = netdev_priv(dev); ++ bcmenet_sw_mdio_write(priv, bcm_enetsw_phy_is_external(priv, phy_id), ++ phy_id, location, val); ++} ++ ++static int bcm_enetsw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct mii_if_info mii; ++ ++ mii.dev = dev; ++ mii.mdio_read = bcm_enetsw_mii_mdio_read; ++ mii.mdio_write = bcm_enetsw_mii_mdio_write; ++ mii.phy_id = 0; ++ mii.phy_id_mask = 0x3f; ++ mii.reg_num_mask = 0x1f; ++ return generic_mii_ioctl(&mii, if_mii(rq), cmd, NULL); ++ ++} ++ ++static const struct net_device_ops bcm_enetsw_ops = { ++ .ndo_open = bcm_enetsw_open, ++ .ndo_stop = bcm_enetsw_stop, ++ .ndo_start_xmit = bcm_enet_start_xmit, ++ .ndo_change_mtu = bcm_enet_change_mtu, ++ .ndo_do_ioctl = bcm_enetsw_ioctl, ++}; ++ ++ ++static const struct bcm_enet_stats bcm_enetsw_gstrings_stats[] = { ++ { "rx_packets", DEV_STAT(rx_packets), -1 }, ++ { "tx_packets", DEV_STAT(tx_packets), -1 }, ++ { "rx_bytes", DEV_STAT(rx_bytes), -1 }, ++ { "tx_bytes", DEV_STAT(tx_bytes), -1 }, ++ { "rx_errors", DEV_STAT(rx_errors), -1 }, ++ { "tx_errors", DEV_STAT(tx_errors), -1 }, ++ { "rx_dropped", DEV_STAT(rx_dropped), -1 }, ++ { "tx_dropped", DEV_STAT(tx_dropped), -1 }, ++ ++ { "tx_good_octets", GEN_STAT(mib.tx_gd_octets), ETHSW_MIB_RX_GD_OCT }, ++ { "tx_unicast", GEN_STAT(mib.tx_unicast), ETHSW_MIB_RX_BRDCAST }, ++ { "tx_broadcast", GEN_STAT(mib.tx_brdcast), ETHSW_MIB_RX_BRDCAST }, ++ { "tx_multicast", GEN_STAT(mib.tx_mult), ETHSW_MIB_RX_MULT }, ++ { "tx_64_octets", GEN_STAT(mib.tx_64), ETHSW_MIB_RX_64 }, ++ { "tx_65_127_oct", GEN_STAT(mib.tx_65_127), ETHSW_MIB_RX_65_127 }, ++ { "tx_128_255_oct", GEN_STAT(mib.tx_128_255), ETHSW_MIB_RX_128_255 }, ++ { "tx_256_511_oct", GEN_STAT(mib.tx_256_511), ETHSW_MIB_RX_256_511 }, ++ { "tx_512_1023_oct", GEN_STAT(mib.tx_512_1023), ETHSW_MIB_RX_512_1023}, ++ { "tx_1024_1522_oct", GEN_STAT(mib.tx_1024_max), ++ ETHSW_MIB_RX_1024_1522 }, ++ { "tx_1523_2047_oct", GEN_STAT(mib.tx_1523_2047), ++ ETHSW_MIB_RX_1523_2047 }, ++ { "tx_2048_4095_oct", GEN_STAT(mib.tx_2048_4095), ++ ETHSW_MIB_RX_2048_4095 }, ++ { "tx_4096_8191_oct", GEN_STAT(mib.tx_4096_8191), ++ ETHSW_MIB_RX_4096_8191 }, ++ { "tx_8192_9728_oct", GEN_STAT(mib.tx_8192_9728), ++ ETHSW_MIB_RX_8192_9728 }, ++ { "tx_oversize", GEN_STAT(mib.tx_ovr), ETHSW_MIB_RX_OVR }, ++ { "tx_oversize_drop", GEN_STAT(mib.tx_ovr), ETHSW_MIB_RX_OVR_DISC }, ++ { "tx_dropped", GEN_STAT(mib.tx_drop), ETHSW_MIB_RX_DROP }, ++ { "tx_undersize", GEN_STAT(mib.tx_underrun), ETHSW_MIB_RX_UND }, ++ { "tx_pause", GEN_STAT(mib.tx_pause), ETHSW_MIB_RX_PAUSE }, ++ ++ { "rx_good_octets", GEN_STAT(mib.rx_gd_octets), ETHSW_MIB_TX_ALL_OCT }, ++ { "rx_broadcast", GEN_STAT(mib.rx_brdcast), ETHSW_MIB_TX_BRDCAST }, ++ { "rx_multicast", GEN_STAT(mib.rx_mult), ETHSW_MIB_TX_MULT }, ++ { "rx_unicast", GEN_STAT(mib.rx_unicast), ETHSW_MIB_TX_MULT }, ++ { "rx_pause", GEN_STAT(mib.rx_pause), ETHSW_MIB_TX_PAUSE }, ++ { "rx_dropped", GEN_STAT(mib.rx_drop), ETHSW_MIB_TX_DROP_PKTS }, ++ ++}; ++ ++#define BCM_ENETSW_STATS_LEN \ ++ (sizeof(bcm_enetsw_gstrings_stats) / sizeof(struct bcm_enet_stats)) ++ ++static void bcm_enetsw_get_strings(struct net_device *netdev, ++ u32 stringset, u8 *data) ++{ ++ int i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) { ++ memcpy(data + i * ETH_GSTRING_LEN, ++ bcm_enetsw_gstrings_stats[i].stat_string, ++ ETH_GSTRING_LEN); ++ } ++ break; ++ } ++} ++ ++static int bcm_enetsw_get_sset_count(struct net_device *netdev, ++ int string_set) ++{ ++ switch (string_set) { ++ case ETH_SS_STATS: ++ return BCM_ENETSW_STATS_LEN; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static void bcm_enetsw_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ strncpy(drvinfo->driver, bcm_enet_driver_name, 32); ++ strncpy(drvinfo->version, bcm_enet_driver_version, 32); ++ strncpy(drvinfo->fw_version, "N/A", 32); ++ strncpy(drvinfo->bus_info, "bcm63xx", 32); ++ drvinfo->n_stats = BCM_ENETSW_STATS_LEN; ++} ++ ++static void bcm_enetsw_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ struct bcm_enet_priv *priv; ++ int i; ++ ++ priv = netdev_priv(netdev); ++ ++ for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) { ++ const struct bcm_enet_stats *s; ++ u32 lo, hi; ++ char *p; ++ int reg; ++ ++ s = &bcm_enetsw_gstrings_stats[i]; ++ ++ reg = s->mib_reg; ++ if (reg == -1) ++ continue; ++ ++ lo = enetsw_readl(priv, ENETSW_MIB_REG(reg)); ++ p = (char *)priv + s->stat_offset; ++ ++ if (s->sizeof_stat == sizeof(u64)) { ++ hi = enetsw_readl(priv, ENETSW_MIB_REG(reg + 1)); ++ *(u64 *)p = ((u64)hi << 32 | lo); ++ } else ++ *(u32 *)p = lo; ++ } ++ ++ for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) { ++ const struct bcm_enet_stats *s; ++ char *p; ++ ++ s = &bcm_enetsw_gstrings_stats[i]; ++ ++ if (s->mib_reg == -1) ++ p = (char *)&netdev->stats + s->stat_offset; ++ else ++ p = (char *)priv + s->stat_offset; ++ ++ data[i] = (s->sizeof_stat == sizeof(u64)) ? ++ *(u64 *)p : *(u32 *)p; ++ } ++} ++ ++static void bcm_enetsw_get_ringparam(struct net_device *dev, ++ struct ethtool_ringparam *ering) ++{ ++ struct bcm_enet_priv *priv; ++ ++ priv = netdev_priv(dev); ++ ++ /* rx/tx ring is actually only limited by memory */ ++ ering->rx_max_pending = 8192; ++ ering->tx_max_pending = 8192; ++ ering->rx_mini_max_pending = 0; ++ ering->rx_jumbo_max_pending = 0; ++ ering->rx_pending = priv->rx_ring_size; ++ ering->tx_pending = priv->tx_ring_size; ++} ++ ++static int bcm_enetsw_set_ringparam(struct net_device *dev, ++ struct ethtool_ringparam *ering) ++{ ++ struct bcm_enet_priv *priv; ++ int was_running; ++ ++ priv = netdev_priv(dev); ++ ++ was_running = 0; ++ if (netif_running(dev)) { ++ bcm_enetsw_stop(dev); ++ was_running = 1; ++ } ++ ++ priv->rx_ring_size = ering->rx_pending; ++ priv->tx_ring_size = ering->tx_pending; ++ ++ if (was_running) { ++ int err; ++ ++ err = bcm_enetsw_open(dev); ++ if (err) ++ dev_close(dev); ++ } ++ return 0; ++} ++ ++static struct ethtool_ops bcm_enetsw_ethtool_ops = { ++ .get_strings = bcm_enetsw_get_strings, ++ .get_sset_count = bcm_enetsw_get_sset_count, ++ .get_ethtool_stats = bcm_enetsw_get_ethtool_stats, ++ .get_drvinfo = bcm_enetsw_get_drvinfo, ++ .get_ringparam = bcm_enetsw_get_ringparam, ++ .set_ringparam = bcm_enetsw_set_ringparam, ++}; ++ ++/* ++ * allocate netdevice, request register memory and register device. ++ */ ++static int __devinit bcm_enetsw_probe(struct platform_device *pdev) ++{ ++ struct bcm_enet_priv *priv; ++ struct net_device *dev; ++ struct bcm63xx_enetsw_platform_data *pd; ++ struct resource *res_mem; ++ int ret, irq_rx, irq_tx; ++ ++ /* stop if shared driver failed, assume driver->probe will be ++ * called in the same order we register devices (correct ?) */ ++ if (!bcm_enet_shared_base[0]) ++ return -ENODEV; ++ ++ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq_rx = platform_get_irq(pdev, 0); ++ irq_tx = platform_get_irq(pdev, 1); ++ if (!res_mem || irq_rx < 0 || irq_tx < 0) ++ return -ENODEV; ++ ++ ret = 0; ++ dev = alloc_etherdev(sizeof(*priv)); ++ if (!dev) ++ return -ENOMEM; ++ priv = netdev_priv(dev); ++ memset(priv, 0, sizeof(*priv)); ++ ++ /* initialize default and fetch platform data */ ++ priv->irq_rx = irq_rx; ++ priv->irq_tx = irq_tx; ++ priv->rx_ring_size = BCMENET_DEF_RX_DESC; ++ priv->tx_ring_size = BCMENET_DEF_TX_DESC; ++ ++ pd = pdev->dev.platform_data; ++ if (pd) { ++ memcpy(dev->dev_addr, pd->mac_addr, ETH_ALEN); ++ memcpy(priv->used_ports, pd->used_ports, ++ sizeof (pd->used_ports)); ++ } ++ ++ ret = compute_hw_mtu(priv, dev->mtu); ++ if (ret) ++ goto out; ++ ++ if (!request_mem_region(res_mem->start, resource_size(res_mem), ++ "bcm63xx_enetsw")) { ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ priv->base = ioremap(res_mem->start, resource_size(res_mem)); ++ if (priv->base == NULL) { ++ ret = -ENOMEM; ++ goto out_release_mem; ++ } ++ ++ priv->mac_clk = clk_get(&pdev->dev, "enetsw"); ++ if (IS_ERR(priv->mac_clk)) { ++ ret = PTR_ERR(priv->mac_clk); ++ goto out_unmap; ++ } ++ clk_enable(priv->mac_clk); ++ ++ priv->rx_chan = 0; ++ priv->tx_chan = 1; ++ spin_lock_init(&priv->rx_lock); ++ ++ /* init rx timeout (used for oom) */ ++ init_timer(&priv->rx_timeout); ++ priv->rx_timeout.function = bcm_enet_refill_rx_timer; ++ priv->rx_timeout.data = (unsigned long)dev; ++ ++ /* register netdevice */ ++ dev->netdev_ops = &bcm_enetsw_ops; ++ netif_napi_add(dev, &priv->napi, bcm_enet_poll, 16); ++ SET_ETHTOOL_OPS(dev, &bcm_enetsw_ethtool_ops); ++ SET_NETDEV_DEV(dev, &pdev->dev); ++ ++ spin_lock_init(&priv->enetsw_mdio_lock); ++ ++ ret = register_netdev(dev); ++ if (ret) ++ goto out_put_clk; ++ ++ netif_carrier_off(dev); ++ platform_set_drvdata(pdev, dev); ++ priv->pdev = pdev; ++ priv->net_dev = dev; ++ ++ return 0; ++ ++out_put_clk: ++ clk_put(priv->mac_clk); ++ ++out_unmap: ++ iounmap(priv->base); ++ ++out_release_mem: ++ release_mem_region(res_mem->start, resource_size(res_mem)); ++out: ++ free_netdev(dev); ++ return ret; ++} ++ ++ ++/* ++ * exit func, stops hardware and unregisters netdevice ++ */ ++static int __devexit bcm_enetsw_remove(struct platform_device *pdev) ++{ ++ struct bcm_enet_priv *priv; ++ struct net_device *dev; ++ struct resource *res; ++ ++ /* stop netdevice */ ++ dev = platform_get_drvdata(pdev); ++ priv = netdev_priv(dev); ++ unregister_netdev(dev); ++ ++ /* release device resources */ ++ iounmap(priv->base); ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(res->start, resource_size(res)); ++ ++ platform_set_drvdata(pdev, NULL); ++ free_netdev(dev); ++ return 0; ++} ++ ++struct platform_driver bcm63xx_enetsw_driver = { ++ .probe = bcm_enetsw_probe, ++ .remove = __devexit_p(bcm_enetsw_remove), ++ .driver = { ++ .name = "bcm63xx_enetsw", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++/* ++ * reserve & remap memory space shared between all macs ++ */ ++static int __devinit bcm_enet_shared_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int ret, i, requested[3]; ++ ++ memset(bcm_enet_shared_base, 0, sizeof (bcm_enet_shared_base)); ++ memset(requested, 0, sizeof (requested)); ++ ++ for (i = 0; i < 3; i++) { ++ void __iomem *p; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ if (!res) { ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ if (!request_mem_region(res->start, resource_size(res), ++ "bcm63xx_enet_dma")) { ++ ret = -EBUSY; ++ goto fail; ++ } ++ requested[i] = 0; ++ ++ p = ioremap(res->start, resource_size(res)); ++ if (!p) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ bcm_enet_shared_base[i] = p; ++ } ++ ++ return 0; ++ ++fail: ++ for (i = 0; i < 3; i++) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ if (!res) ++ continue; ++ if (bcm_enet_shared_base[i]) ++ iounmap(bcm_enet_shared_base[i]); ++ if (requested[i]) ++ release_mem_region(res->start, resource_size(res)); ++ } ++ return ret; ++} ++ ++static int __devexit bcm_enet_shared_remove(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int i; ++ ++ for (i = 0; i < 3; i++) { ++ iounmap(bcm_enet_shared_base[i]); ++ res = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ release_mem_region(res->start, resource_size(res)); ++ } ++ return 0; ++} ++ ++/* ++ * this "shared" driver is needed because both macs share a single ++ * address space ++ */ ++struct platform_driver bcm63xx_enet_shared_driver = { ++ .probe = bcm_enet_shared_probe, ++ .remove = __devexit_p(bcm_enet_shared_remove), ++ .driver = { ++ .name = "bcm63xx_enet_shared", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++/* ++ * entry point ++ */ ++static int __init bcm_enet_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&bcm63xx_enet_shared_driver); ++ if (ret) ++ return ret; ++ ++ ret = platform_driver_register(&bcm63xx_enet_driver); ++ if (ret) ++ platform_driver_unregister(&bcm63xx_enet_shared_driver); ++ ++ ret = platform_driver_register(&bcm63xx_enetsw_driver); ++ if (ret) { ++ platform_driver_unregister(&bcm63xx_enet_driver); ++ platform_driver_unregister(&bcm63xx_enet_shared_driver); ++ } + + return ret; + } +@@ -2018,6 +2937,7 @@ static int __init bcm_enet_init(void) + static void __exit bcm_enet_exit(void) + { + platform_driver_unregister(&bcm63xx_enet_driver); ++ platform_driver_unregister(&bcm63xx_enetsw_driver); + platform_driver_unregister(&bcm63xx_enet_shared_driver); + } + +--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.h ++++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.h +@@ -112,11 +112,60 @@ struct bcm_enet_desc { + #define ETH_MIB_RX_CNTRL 54 + + ++/* ++ * SW MIB Counters register definitions ++*/ ++#define ETHSW_MIB_TX_ALL_OCT 0 ++#define ETHSW_MIB_TX_DROP_PKTS 2 ++#define ETHSW_MIB_TX_QOS_PKTS 3 ++#define ETHSW_MIB_TX_BRDCAST 4 ++#define ETHSW_MIB_TX_MULT 5 ++#define ETHSW_MIB_TX_UNI 6 ++#define ETHSW_MIB_TX_COL 7 ++#define ETHSW_MIB_TX_1_COL 8 ++#define ETHSW_MIB_TX_M_COL 9 ++#define ETHSW_MIB_TX_DEF 10 ++#define ETHSW_MIB_TX_LATE 11 ++#define ETHSW_MIB_TX_EX_COL 12 ++#define ETHSW_MIB_TX_PAUSE 14 ++#define ETHSW_MIB_TX_QOS_OCT 15 ++ ++#define ETHSW_MIB_RX_ALL_OCT 17 ++#define ETHSW_MIB_RX_UND 19 ++#define ETHSW_MIB_RX_PAUSE 20 ++#define ETHSW_MIB_RX_64 21 ++#define ETHSW_MIB_RX_65_127 22 ++#define ETHSW_MIB_RX_128_255 23 ++#define ETHSW_MIB_RX_256_511 24 ++#define ETHSW_MIB_RX_512_1023 25 ++#define ETHSW_MIB_RX_1024_1522 26 ++#define ETHSW_MIB_RX_OVR 27 ++#define ETHSW_MIB_RX_JAB 28 ++#define ETHSW_MIB_RX_ALIGN 29 ++#define ETHSW_MIB_RX_CRC 30 ++#define ETHSW_MIB_RX_GD_OCT 31 ++#define ETHSW_MIB_RX_DROP 33 ++#define ETHSW_MIB_RX_UNI 34 ++#define ETHSW_MIB_RX_MULT 35 ++#define ETHSW_MIB_RX_BRDCAST 36 ++#define ETHSW_MIB_RX_SA_CHANGE 37 ++#define ETHSW_MIB_RX_FRAG 38 ++#define ETHSW_MIB_RX_OVR_DISC 39 ++#define ETHSW_MIB_RX_SYM 40 ++#define ETHSW_MIB_RX_QOS_PKTS 41 ++#define ETHSW_MIB_RX_QOS_OCT 42 ++#define ETHSW_MIB_RX_1523_2047 44 ++#define ETHSW_MIB_RX_2048_4095 45 ++#define ETHSW_MIB_RX_4096_8191 46 ++#define ETHSW_MIB_RX_8192_9728 47 ++ ++ + struct bcm_enet_mib_counters { + u64 tx_gd_octets; + u32 tx_gd_pkts; + u32 tx_all_octets; + u32 tx_all_pkts; ++ u32 tx_unicast; + u32 tx_brdcast; + u32 tx_mult; + u32 tx_64; +@@ -125,7 +174,12 @@ struct bcm_enet_mib_counters { + u32 tx_256_511; + u32 tx_512_1023; + u32 tx_1024_max; ++ u32 tx_1523_2047; ++ u32 tx_2048_4095; ++ u32 tx_4096_8191; ++ u32 tx_8192_9728; + u32 tx_jab; ++ u32 tx_drop; + u32 tx_ovr; + u32 tx_frag; + u32 tx_underrun; +@@ -142,6 +196,7 @@ struct bcm_enet_mib_counters { + u32 rx_all_octets; + u32 rx_all_pkts; + u32 rx_brdcast; ++ u32 rx_unicast; + u32 rx_mult; + u32 rx_64; + u32 rx_65_127; +@@ -297,6 +352,22 @@ struct bcm_enet_priv { + + /* maximum hardware transmit/receive size */ + unsigned int hw_mtu; ++ ++ /* port mapping for switch devices */ ++ struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT]; ++ int sw_port_link[ENETSW_MAX_PORT]; ++ ++ /* used to poll switch port state */ ++ struct timer_list swphy_poll; ++ spinlock_t enetsw_mdio_lock; + }; + ++static inline int bcm_enet_is_sw(struct bcm_enet_priv *priv) ++{ ++ if (BCMCPU_IS_6368()) ++ return 1; ++ else ++ return 0; ++} ++ + #endif /* ! BCM63XX_ENET_H_ */ diff --git a/target/linux/brcm63xx/patches-3.3/511-board_V2500V.patch b/target/linux/brcm63xx/patches-3.3/511-board_V2500V.patch index 37886892e1..bc9ea8b17b 100644 --- a/target/linux/brcm63xx/patches-3.3/511-board_V2500V.patch +++ b/target/linux/brcm63xx/patches-3.3/511-board_V2500V.patch @@ -95,7 +95,7 @@ /* dump cfe version */ cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET; -@@ -2154,6 +2228,13 @@ int __init board_register_devices(void) +@@ -2158,6 +2232,13 @@ int __init board_register_devices(void) val = bcm_mpi_readl(MPI_CSBASE_REG(0)); val &= MPI_CSBASE_BASE_MASK; diff --git a/target/linux/brcm63xx/patches-3.3/550-alice_gate2_leds.patch b/target/linux/brcm63xx/patches-3.3/550-alice_gate2_leds.patch index f0e23b7ab1..82d0385f94 100644 --- a/target/linux/brcm63xx/patches-3.3/550-alice_gate2_leds.patch +++ b/target/linux/brcm63xx/patches-3.3/550-alice_gate2_leds.patch @@ -102,7 +102,7 @@ static struct board_info __initdata board_DWVS0 = { --- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h +++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h -@@ -57,7 +57,7 @@ struct board_info { +@@ -59,7 +59,7 @@ struct board_info { struct bcm63xx_dsp_platform_data dsp; /* GPIO LEDs */