Browse Source

bcm63xx_enet: add support for Broadcom BCM63xx integrated gigabit switch

Newer Broadcom BCM63xx SoCs: 6328, 6362 and 6368 have an integrated switch
which needs to be driven slightly differently from the traditional
external switches. This patch introduces changes in arch/mips/bcm63xx in order
to:

- register a bcm63xx_enetsw driver instead of bcm63xx_enet driver
- update DMA channels configuration & state RAM base addresses
- add a new platform data configuration knob to define the number of
  ports per switch/device and force link on some ports
- define the required switch registers

On the driver side, the following changes are required:

- the switch ports need to be polled to ensure the link is up and
  running and RX/TX can properly work
- basic switch configuration needs to be performed for the switch to
  forward packets to the CPU
- update the MIB counters since the integrated

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Maxime Bizon 12 years ago
parent
commit
6f00a02296

+ 4 - 0
arch/mips/bcm63xx/boards/board_bcm963xx.c

@@ -845,6 +845,10 @@ int __init board_register_devices(void)
 	    !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
 		bcm63xx_enet_register(1, &board.enet1);
 
+	if (board.has_enetsw &&
+	    !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
+		bcm63xx_enetsw_register(&board.enetsw);
+
 	if (board.has_usbd)
 		bcm63xx_usbd_register(&board.usbd);
 

+ 95 - 18
arch/mips/bcm63xx/dev-enet.c

@@ -104,6 +104,64 @@ static struct platform_device bcm63xx_enet1_device = {
 	},
 };
 
+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_6328() || BCMCPU_IS_6362() || 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 unit,
 	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,37 @@ int __init bcm63xx_enet_register(int unit,
 		return ret;
 	return 0;
 }
+
+int __init
+bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd)
+{
+	int ret;
+
+	if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !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);
+	if (!enetsw_res[2].start)
+		enetsw_res[2].start = -1;
+
+	memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));
+
+	if (BCMCPU_IS_6328())
+		enetsw_pd.num_ports = ENETSW_PORTS_6328;
+	else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
+		enetsw_pd.num_ports = ENETSW_PORTS_6368;
+
+	ret = platform_device_register(&bcm63xx_enetsw_device);
+	if (ret)
+		return ret;
+
+	return 0;
+}

+ 28 - 0
arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h

@@ -39,7 +39,35 @@ struct bcm63xx_enet_platform_data {
 					    int phy_id, int reg, int val));
 };
 
+/*
+ * on board ethernet switch platform data
+ */
+#define ENETSW_MAX_PORT	8
+#define ENETSW_PORTS_6328 5 /* 4 FE PHY + 1 RGMII */
+#define ENETSW_PORTS_6368 6 /* 4 FE PHY + 2 RGMII */
+
+#define ENETSW_RGMII_PORT0	4
+
+struct bcm63xx_enetsw_port {
+	int		used;
+	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];
+	int num_ports;
+	struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT];
+};
+
 int __init bcm63xx_enet_register(int unit,
 				 const struct bcm63xx_enet_platform_data *pd);
 
+int bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd);
+
 #endif /* ! BCM63XX_DEV_ENET_H_ */

+ 50 - 0
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h

@@ -830,10 +830,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

+ 2 - 0
arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h

@@ -24,6 +24,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;
@@ -36,6 +37,7 @@ struct board_info {
 	/* ethernet config */
 	struct bcm63xx_enet_platform_data enet0;
 	struct bcm63xx_enet_platform_data enet1;
+	struct bcm63xx_enetsw_platform_data enetsw;
 
 	/* USB config */
 	struct bcm63xx_usbd_platform_data usbd;

File diff suppressed because it is too large
+ 954 - 40
drivers/net/ethernet/broadcom/bcm63xx_enet.c


+ 71 - 0
drivers/net/ethernet/broadcom/bcm63xx_enet.h

@@ -18,6 +18,7 @@
 
 /* maximum burst len for dma (4 bytes unit) */
 #define BCMENET_DMA_MAXBURST	16
+#define BCMENETSW_DMA_MAXBURST	8
 
 /* tx transmit threshold (4 bytes unit), fifo is 256 bytes, the value
  * must be low enough so that a DMA transfer of above burst length can
@@ -84,11 +85,60 @@
 #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;
@@ -97,7 +147,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;
@@ -114,6 +169,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;
@@ -197,6 +253,9 @@ struct bcm_enet_priv {
 	/* number of dma desc in tx ring */
 	int tx_ring_size;
 
+	/* maximum dma burst size */
+	int dma_maxburst;
+
 	/* cpu view of rx dma ring */
 	struct bcm_enet_desc *tx_desc_cpu;
 
@@ -269,6 +328,18 @@ struct bcm_enet_priv {
 
 	/* maximum hardware transmit/receive size */
 	unsigned int hw_mtu;
+
+	bool enet_is_sw;
+
+	/* port mapping for switch devices */
+	int num_ports;
+	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;
 };
 
+
 #endif /* ! BCM63XX_ENET_H_ */

Some files were not shown because too many files changed in this diff