Skip to contentSkip to conversation

Fix system hang when loading mvneta module - take 2

PATCH In review Arnaud Patard (Rtp) 2 participants 4 messages Jul 29, 2013 – Jul 31, 2013

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v2 cover Fix system hang when loading mvneta module - take 2

Hi,

This is a second version of my patchset to fix mvneta as module. I've addressed previous comments. I've also fixed probe error path which was broken in the previous version.

Arnaud

#1 lore raw

PATCH v2 1/2 Fix hang when loading the mvneta driver

When the mvneta driver is compiled, it'll be loaded with clocks disabled. This implies that the clocks should be enabled again before any register access or it'll hang.

To fix it:
- enable clock earlier
- move timer callback after setting timer.data

drivers/net/ethernet/marvell/mvneta.c +9 -10
Index: linux-next/drivers/net/ethernet/marvell/mvneta.c
===================================================================
@@ -2728,20 +2733,10 @@ static int mvneta_probe(struct platform_
 
 	pp = netdev_priv(dev);
 
-	pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
-	init_timer(&pp->tx_done_timer);
-	clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
-
 	pp->weight = MVNETA_RX_POLL_WEIGHT;
 	pp->phy_node = phy_node;
 	pp->phy_interface = phy_mode;
 
-	pp->base = of_iomap(dn, 0);
-	if (pp->base == NULL) {
-		err = -ENOMEM;
-		goto err_free_irq;
-	}
-
 	pp->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(pp->clk)) {
 		err = PTR_ERR(pp->clk);
@@ -2765,7 +2760,16 @@ static int mvneta_probe(struct platform_
 		}
 	}
 
+	pp->base = of_iomap(dn, 0);
+	if (pp->base == NULL) {
+		err = -ENOMEM;
+		goto err_free_irq;
+	}
+
 	pp->tx_done_timer.data = (unsigned long)dev;
+	pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
+	init_timer(&pp->tx_done_timer);
+	clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
 
 	pp->tx_ring_size = MVNETA_MAX_TXD;
 	pp->rx_ring_size = MVNETA_MAX_RXD;
#2 lore raw

PATCH v2 2/2 Try to fix mvneta when compiled as module

In reply to Arnaud Patard (Rtp)

When the mvneta driver is compiled as module, the clock is disabled before it's loading. This will reset the registers values and all configuration made by the bootloader.

This patch sets the "sgmii serdes configuration" register to a magical value found in:
https://github.com/yellowback/ubuntu-precise-armadaxp/blob/master/arch/arm/mach-armadaxp/armada_xp_family/ctrlEnv/mvCtrlEnvLib.c

With this change, the interrupts are working/generated and ethernet is working.

drivers/net/ethernet/marvell/mvneta.c +14 -10
Index: linux-next/drivers/net/ethernet/marvell/mvneta.c
===================================================================
@@ -88,6 +88,8 @@
 #define      MVNETA_TX_IN_PRGRS                  BIT(1)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
+#define MVNETA_SGMII_SERDES_CFG			 0x24A0
+#define      MVNETA_SGMII_SERDES_PROTO		 0x0cc7
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
@@ -655,6 +657,8 @@ static void mvneta_port_sgmii_config(str
 	val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 	val |= MVNETA_GMAC2_PSC_ENABLE;
 	mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
+
+	mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
 }
 
 /* Start the Ethernet port RX and TX activity */
@@ -2735,11 +2739,17 @@ static int mvneta_probe(struct platform_
 	pp->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(pp->clk)) {
 		err = PTR_ERR(pp->clk);
-		goto err_unmap;
+		goto err_free_irq;
 	}
 
 	clk_prepare_enable(pp->clk);
 
+	pp->base = of_iomap(dn, 0);
+	if (pp->base == NULL) {
+		err = -ENOMEM;
+		goto err_clk;
+	}
+
 	dt_mac_addr = of_get_mac_address(dn);
 	if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
 		mac_from = "device tree";
@@ -2755,12 +2765,6 @@ static int mvneta_probe(struct platform_
 		}
 	}
 
-	pp->base = of_iomap(dn, 0);
-	if (pp->base == NULL) {
-		err = -ENOMEM;
-		goto err_free_irq;
-	}
-
 	pp->tx_done_timer.data = (unsigned long)dev;
 	pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
 	init_timer(&pp->tx_done_timer);
@@ -2775,7 +2779,7 @@ static int mvneta_probe(struct platform_
 	err = mvneta_init(pp, phy_addr);
 	if (err < 0) {
 		dev_err(&pdev->dev, "can't init eth hal\n");
-		goto err_clk;
+		goto err_unmap;
 	}
 	mvneta_port_power_up(pp, phy_mode);
 
@@ -2805,10 +2809,10 @@ static int mvneta_probe(struct platform_
 
 err_deinit:
 	mvneta_deinit(pp);
-err_clk:
-	clk_disable_unprepare(pp->clk);
 err_unmap:
 	iounmap(pp->base);
+err_clk:
+	clk_disable_unprepare(pp->clk);
 err_free_irq:
 	irq_dispose_mapping(dev->irq);
 err_free_netdev:
maintainer
#3 lore raw
In reply to Arnaud Patard (Rtp)

From: Arnaud Patard (Rtp) <[email protected]>
Date: Mon, 29 Jul 2013 21:56:46 +0200

Quoted 3 lines

This is a second version of my patchset to fix mvneta as module. I've addressed previous comments. I've also fixed probe error path which was broken in the previous version.

Both applied, thanks.