diff options
| author | Michael Chan <mchan@broadcom.com> | 2006-01-17 02:40:55 -0800 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2006-01-17 02:40:55 -0800 | 
| commit | ec41c7dfd525468decb9da9281dbc9ed82d98c98 (patch) | |
| tree | 02ac7f0b1318c69d53a2405972f8a6880dc8b7c6 | |
| parent | f0daaa654af68c1651add9d21188d81c19672551 (diff) | |
[TG3]: Refine nvram locking
Add nvram lock count so that calls to tg3_nvram_lock()/unlock() can
be nested. Add error checking to all callers of tg3_nvram_lock()
where appropriate. To prevent nvram lock failures after halting the
firmware, it is also necessary to release firmware's nvram lock in
tg3_halt_cpu().
Update version to 3.48.
Based on David Miller's initial patch.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/tg3.c | 82 | ||||
| -rw-r--r-- | drivers/net/tg3.h | 1 | 
2 files changed, 55 insertions, 28 deletions
| diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eb86b059809b..f2d1dafde087 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@  #define DRV_MODULE_NAME		"tg3"  #define PFX DRV_MODULE_NAME	": " -#define DRV_MODULE_VERSION	"3.47" -#define DRV_MODULE_RELDATE	"Dec 28, 2005" +#define DRV_MODULE_VERSION	"3.48" +#define DRV_MODULE_RELDATE	"Jan 16, 2006"  #define TG3_DEF_MAC_MODE	0  #define TG3_DEF_RX_MODE		0 @@ -1325,10 +1325,12 @@ static int tg3_set_power_state(struct tg3 *tp, int state)  		val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);  		tw32(0x7d00, val);  		if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { -			tg3_nvram_lock(tp); +			int err; + +			err = tg3_nvram_lock(tp);  			tg3_halt_cpu(tp, RX_CPU_BASE); -			tw32_f(NVRAM_SWARB, SWARB_REQ_CLR0); -			tg3_nvram_unlock(tp); +			if (!err) +				tg3_nvram_unlock(tp);  		}  	} @@ -4193,14 +4195,19 @@ static int tg3_nvram_lock(struct tg3 *tp)  	if (tp->tg3_flags & TG3_FLAG_NVRAM) {  		int i; -		tw32(NVRAM_SWARB, SWARB_REQ_SET1); -		for (i = 0; i < 8000; i++) { -			if (tr32(NVRAM_SWARB) & SWARB_GNT1) -				break; -			udelay(20); +		if (tp->nvram_lock_cnt == 0) { +			tw32(NVRAM_SWARB, SWARB_REQ_SET1); +			for (i = 0; i < 8000; i++) { +				if (tr32(NVRAM_SWARB) & SWARB_GNT1) +					break; +				udelay(20); +			} +			if (i == 8000) { +				tw32(NVRAM_SWARB, SWARB_REQ_CLR1); +				return -ENODEV; +			}  		} -		if (i == 8000) -			return -ENODEV; +		tp->nvram_lock_cnt++;  	}  	return 0;  } @@ -4208,8 +4215,12 @@ static int tg3_nvram_lock(struct tg3 *tp)  /* tp->lock is held. */  static void tg3_nvram_unlock(struct tg3 *tp)  { -	if (tp->tg3_flags & TG3_FLAG_NVRAM) -		tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1); +	if (tp->tg3_flags & TG3_FLAG_NVRAM) { +		if (tp->nvram_lock_cnt > 0) +			tp->nvram_lock_cnt--; +		if (tp->nvram_lock_cnt == 0) +			tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1); +	}  }  /* tp->lock is held. */ @@ -4320,8 +4331,13 @@ static int tg3_chip_reset(struct tg3 *tp)  	void (*write_op)(struct tg3 *, u32, u32);  	int i; -	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) +	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {  		tg3_nvram_lock(tp); +		/* No matching tg3_nvram_unlock() after this because +		 * chip reset below will undo the nvram lock. +		 */ +		tp->nvram_lock_cnt = 0; +	}  	/*  	 * We must avoid the readl() that normally takes place. @@ -4717,6 +4733,10 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)  		       (offset == RX_CPU_BASE ? "RX" : "TX"));  		return -ENODEV;  	} + +	/* Clear firmware's nvram arbitration. */ +	if (tp->tg3_flags & TG3_FLAG_NVRAM) +		tw32(NVRAM_SWARB, SWARB_REQ_CLR0);  	return 0;  } @@ -4736,7 +4756,7 @@ struct fw_info {  static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base,  				 int cpu_scratch_size, struct fw_info *info)  { -	int err, i; +	int err, lock_err, i;  	void (*write_op)(struct tg3 *, u32, u32);  	if (cpu_base == TX_CPU_BASE && @@ -4755,9 +4775,10 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b  	/* It is possible that bootcode is still loading at this point.  	 * Get the nvram lock first before halting the cpu.  	 */ -	tg3_nvram_lock(tp); +	lock_err = tg3_nvram_lock(tp);  	err = tg3_halt_cpu(tp, cpu_base); -	tg3_nvram_unlock(tp); +	if (!lock_err) +		tg3_nvram_unlock(tp);  	if (err)  		goto out; @@ -8182,7 +8203,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,  		data[1] = 1;  	}  	if (etest->flags & ETH_TEST_FL_OFFLINE) { -		int irq_sync = 0; +		int err, irq_sync = 0;  		if (netif_running(dev)) {  			tg3_netif_stop(tp); @@ -8192,11 +8213,12 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,  		tg3_full_lock(tp, irq_sync);  		tg3_halt(tp, RESET_KIND_SUSPEND, 1); -		tg3_nvram_lock(tp); +		err = tg3_nvram_lock(tp);  		tg3_halt_cpu(tp, RX_CPU_BASE);  		if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))  			tg3_halt_cpu(tp, TX_CPU_BASE); -		tg3_nvram_unlock(tp); +		if (!err) +			tg3_nvram_unlock(tp);  		if (tg3_test_registers(tp) != 0) {  			etest->flags |= ETH_TEST_FL_FAILED; @@ -8588,7 +8610,11 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)  	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {  		tp->tg3_flags |= TG3_FLAG_NVRAM; -		tg3_nvram_lock(tp); +		if (tg3_nvram_lock(tp)) { +			printk(KERN_WARNING PFX "%s: Cannot get nvarm lock, " +			       "tg3_nvram_init failed.\n", tp->dev->name); +			return; +		}  		tg3_enable_nvram_access(tp);  		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) @@ -8686,7 +8712,9 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)  	if (offset > NVRAM_ADDR_MSK)  		return -EINVAL; -	tg3_nvram_lock(tp); +	ret = tg3_nvram_lock(tp); +	if (ret) +		return ret;  	tg3_enable_nvram_access(tp); @@ -8785,10 +8813,6 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,  		offset = offset + (pagesize - page_off); -		/* Nvram lock released by tg3_nvram_read() above, -		 * so need to get it again. -		 */ -		tg3_nvram_lock(tp);  		tg3_enable_nvram_access(tp);  		/* @@ -8925,7 +8949,9 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)  	else {  		u32 grc_mode; -		tg3_nvram_lock(tp); +		ret = tg3_nvram_lock(tp); +		if (ret) +			return ret;  		tg3_enable_nvram_access(tp);  		if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 890e1635996b..e8243305f0e8 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2275,6 +2275,7 @@ struct tg3 {  	dma_addr_t			stats_mapping;  	struct work_struct		reset_task; +	int				nvram_lock_cnt;  	u32				nvram_size;  	u32				nvram_pagesize;  	u32				nvram_jedecnum; | 
