Переглянути джерело

tg3: Create critical section around GPIO toggling

The code that performs the power source switching will need to consider
the status of the other devices before making any switches.  The status
updates and power source switching will need to be an atomic operation,
so a critical section will be needed.  This patch establishes the
critical section through a CPMU mutex.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Matt Carlson 14 роки тому
батько
коміт
6f5c8f8317
2 змінених файлів з 53 додано та 11 видалено
  1. 52 11
      drivers/net/tg3.c
  2. 1 0
      drivers/net/tg3.h

+ 52 - 11
drivers/net/tg3.c

@@ -608,7 +608,7 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
 static void tg3_ape_lock_init(struct tg3 *tp)
 static void tg3_ape_lock_init(struct tg3 *tp)
 {
 {
 	int i;
 	int i;
-	u32 regbase;
+	u32 regbase, bit;
 
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
 		regbase = TG3_APE_LOCK_GRANT;
 		regbase = TG3_APE_LOCK_GRANT;
@@ -616,20 +616,34 @@ static void tg3_ape_lock_init(struct tg3 *tp)
 		regbase = TG3_APE_PER_LOCK_GRANT;
 		regbase = TG3_APE_PER_LOCK_GRANT;
 
 
 	/* Make sure the driver hasn't any stale locks. */
 	/* Make sure the driver hasn't any stale locks. */
-	for (i = 0; i < 8; i++)
+	for (i = 0; i < 8; i++) {
+		if (i == TG3_APE_LOCK_GPIO)
+			continue;
 		tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER);
 		tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER);
+	}
+
+	/* Clear the correct bit of the GPIO lock too. */
+	if (!tp->pci_fn)
+		bit = APE_LOCK_GRANT_DRIVER;
+	else
+		bit = 1 << tp->pci_fn;
+
+	tg3_ape_write32(tp, regbase + 4 * TG3_APE_LOCK_GPIO, bit);
 }
 }
 
 
 static int tg3_ape_lock(struct tg3 *tp, int locknum)
 static int tg3_ape_lock(struct tg3 *tp, int locknum)
 {
 {
 	int i, off;
 	int i, off;
 	int ret = 0;
 	int ret = 0;
-	u32 status, req, gnt;
+	u32 status, req, gnt, bit;
 
 
 	if (!tg3_flag(tp, ENABLE_APE))
 	if (!tg3_flag(tp, ENABLE_APE))
 		return 0;
 		return 0;
 
 
 	switch (locknum) {
 	switch (locknum) {
+	case TG3_APE_LOCK_GPIO:
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+			return 0;
 	case TG3_APE_LOCK_GRC:
 	case TG3_APE_LOCK_GRC:
 	case TG3_APE_LOCK_MEM:
 	case TG3_APE_LOCK_MEM:
 		break;
 		break;
@@ -647,21 +661,24 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
 
 
 	off = 4 * locknum;
 	off = 4 * locknum;
 
 
-	tg3_ape_write32(tp, req + off, APE_LOCK_REQ_DRIVER);
+	if (locknum != TG3_APE_LOCK_GPIO || !tp->pci_fn)
+		bit = APE_LOCK_REQ_DRIVER;
+	else
+		bit = 1 << tp->pci_fn;
+
+	tg3_ape_write32(tp, req + off, bit);
 
 
 	/* Wait for up to 1 millisecond to acquire lock. */
 	/* Wait for up to 1 millisecond to acquire lock. */
 	for (i = 0; i < 100; i++) {
 	for (i = 0; i < 100; i++) {
 		status = tg3_ape_read32(tp, gnt + off);
 		status = tg3_ape_read32(tp, gnt + off);
-		if (status == APE_LOCK_GRANT_DRIVER)
+		if (status == bit)
 			break;
 			break;
 		udelay(10);
 		udelay(10);
 	}
 	}
 
 
-	if (status != APE_LOCK_GRANT_DRIVER) {
+	if (status != bit) {
 		/* Revoke the lock request. */
 		/* Revoke the lock request. */
-		tg3_ape_write32(tp, gnt + off,
-				APE_LOCK_GRANT_DRIVER);
-
+		tg3_ape_write32(tp, gnt + off, bit);
 		ret = -EBUSY;
 		ret = -EBUSY;
 	}
 	}
 
 
@@ -670,12 +687,15 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
 
 
 static void tg3_ape_unlock(struct tg3 *tp, int locknum)
 static void tg3_ape_unlock(struct tg3 *tp, int locknum)
 {
 {
-	u32 gnt;
+	u32 gnt, bit;
 
 
 	if (!tg3_flag(tp, ENABLE_APE))
 	if (!tg3_flag(tp, ENABLE_APE))
 		return;
 		return;
 
 
 	switch (locknum) {
 	switch (locknum) {
+	case TG3_APE_LOCK_GPIO:
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+			return;
 	case TG3_APE_LOCK_GRC:
 	case TG3_APE_LOCK_GRC:
 	case TG3_APE_LOCK_MEM:
 	case TG3_APE_LOCK_MEM:
 		break;
 		break;
@@ -688,7 +708,12 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
 	else
 	else
 		gnt = TG3_APE_PER_LOCK_GRANT;
 		gnt = TG3_APE_PER_LOCK_GRANT;
 
 
-	tg3_ape_write32(tp, gnt + 4 * locknum, APE_LOCK_GRANT_DRIVER);
+	if (locknum != TG3_APE_LOCK_GPIO || !tp->pci_fn)
+		bit = APE_LOCK_GRANT_DRIVER;
+	else
+		bit = 1 << tp->pci_fn;
+
+	tg3_ape_write32(tp, gnt + 4 * locknum, bit);
 }
 }
 
 
 static void tg3_disable_ints(struct tg3 *tp)
 static void tg3_disable_ints(struct tg3 *tp)
@@ -2170,11 +2195,16 @@ out:
 static inline int tg3_pwrsrc_switch_to_vmain(struct tg3 *tp)
 static inline int tg3_pwrsrc_switch_to_vmain(struct tg3 *tp)
 {
 {
 	if (!tg3_flag(tp, IS_NIC))
 	if (!tg3_flag(tp, IS_NIC))
+		return;
+
+	if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
 		return 0;
 		return 0;
 
 
 	tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl,
 	tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl,
 		    TG3_GRC_LCLCTL_PWRSW_DELAY);
 		    TG3_GRC_LCLCTL_PWRSW_DELAY);
 
 
+	tg3_ape_unlock(tp, TG3_APE_LOCK_GPIO);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2187,6 +2217,10 @@ static void tg3_pwrsrc_die_with_vmain(struct tg3 *tp)
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
 		return;
 		return;
 
 
+
+	if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
+		return;
+
 	grc_local_ctrl = tp->grc_local_ctrl | GRC_LCLCTRL_GPIO_OE1;
 	grc_local_ctrl = tp->grc_local_ctrl | GRC_LCLCTRL_GPIO_OE1;
 
 
 	tw32_wait_f(GRC_LOCAL_CTRL,
 	tw32_wait_f(GRC_LOCAL_CTRL,
@@ -2200,6 +2234,8 @@ static void tg3_pwrsrc_die_with_vmain(struct tg3 *tp)
 	tw32_wait_f(GRC_LOCAL_CTRL,
 	tw32_wait_f(GRC_LOCAL_CTRL,
 		    grc_local_ctrl | GRC_LCLCTRL_GPIO_OUTPUT1,
 		    grc_local_ctrl | GRC_LCLCTRL_GPIO_OUTPUT1,
 		    TG3_GRC_LCLCTL_PWRSW_DELAY);
 		    TG3_GRC_LCLCTL_PWRSW_DELAY);
+
+	tg3_ape_unlock(tp, TG3_APE_LOCK_GPIO);
 }
 }
 
 
 static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
 static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
@@ -2207,6 +2243,9 @@ static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
 	if (!tg3_flag(tp, IS_NIC))
 	if (!tg3_flag(tp, IS_NIC))
 		return;
 		return;
 
 
+	if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
+		return;
+
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
 		tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
 		tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
@@ -2277,6 +2316,8 @@ static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
 				    TG3_GRC_LCLCTL_PWRSW_DELAY);
 				    TG3_GRC_LCLCTL_PWRSW_DELAY);
 		}
 		}
 	}
 	}
+
+	tg3_ape_unlock(tp, TG3_APE_LOCK_GPIO);
 }
 }
 
 
 static void tg3_frob_aux_power(struct tg3 *tp)
 static void tg3_frob_aux_power(struct tg3 *tp)

+ 1 - 0
drivers/net/tg3.h

@@ -2339,6 +2339,7 @@
 /* APE convenience enumerations. */
 /* APE convenience enumerations. */
 #define TG3_APE_LOCK_GRC                1
 #define TG3_APE_LOCK_GRC                1
 #define TG3_APE_LOCK_MEM                4
 #define TG3_APE_LOCK_MEM                4
+#define TG3_APE_LOCK_GPIO               7
 
 
 #define TG3_EEPROM_SB_F1R2_MBA_OFF	0x10
 #define TG3_EEPROM_SB_F1R2_MBA_OFF	0x10