diff options
Diffstat (limited to 'drivers/net/acenic.c')
| -rw-r--r-- | drivers/net/acenic.c | 117 | 
1 files changed, 71 insertions, 46 deletions
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 517fce48d94..5b396ff6c83 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -66,6 +66,7 @@  #include <linux/mm.h>  #include <linux/highmem.h>  #include <linux/sockios.h> +#include <linux/firmware.h>  #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)  #include <linux/if_vlan.h> @@ -186,8 +187,6 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);  #define MAX_RODATA_LEN	8*1024  #define MAX_DATA_LEN	2*1024 -#include "acenic_firmware.h" -  #ifndef tigon2FwReleaseLocal  #define tigon2FwReleaseLocal 0  #endif @@ -417,6 +416,10 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};  MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");  MODULE_LICENSE("GPL");  MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); +#ifndef CONFIG_ACENIC_OMIT_TIGON_I +MODULE_FIRMWARE("acenic/tg1.bin"); +#endif +MODULE_FIRMWARE("acenic/tg2.bin");  module_param_array_named(link, link_state, int, NULL, 0);  module_param_array(trace, int, NULL, 0); @@ -943,8 +946,8 @@ static int __devinit ace_init(struct net_device *dev)  	case 4:  	case 5:  		printk(KERN_INFO "  Tigon I  (Rev. %i), Firmware: %i.%i.%i, ", -		       tig_ver, tigonFwReleaseMajor, tigonFwReleaseMinor, -		       tigonFwReleaseFix); +		       tig_ver, ap->firmware_major, ap->firmware_minor, +		       ap->firmware_fix);  		writel(0, ®s->LocalCtrl);  		ap->version = 1;  		ap->tx_ring_entries = TIGON_I_TX_RING_ENTRIES; @@ -952,8 +955,8 @@ static int __devinit ace_init(struct net_device *dev)  #endif  	case 6:  		printk(KERN_INFO "  Tigon II (Rev. %i), Firmware: %i.%i.%i, ", -		       tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor, -		       tigon2FwReleaseFix); +		       tig_ver, ap->firmware_major, ap->firmware_minor, +		       ap->firmware_fix);  		writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl);  		readl(®s->CpuBCtrl);		/* PCI write posting */  		/* @@ -1205,7 +1208,9 @@ static int __devinit ace_init(struct net_device *dev)  	memset(ap->info, 0, sizeof(struct ace_info));  	memset(ap->skb, 0, sizeof(struct ace_skb)); -	ace_load_firmware(dev); +	if (ace_load_firmware(dev)) +		goto init_error; +  	ap->fw_running = 0;  	tmp_ptr = ap->info_dma; @@ -1441,10 +1446,7 @@ static int __devinit ace_init(struct net_device *dev)  	if (ap->version >= 2)  		writel(tmp, ®s->TuneFastLink); -	if (ACE_IS_TIGON_I(ap)) -		writel(tigonFwStartAddr, ®s->Pc); -	if (ap->version == 2) -		writel(tigon2FwStartAddr, ®s->Pc); +	writel(ap->firmware_start, ®s->Pc);  	writel(0, ®s->Mb0Lo); @@ -2761,8 +2763,8 @@ static void ace_get_drvinfo(struct net_device *dev,  	strlcpy(info->driver, "acenic", sizeof(info->driver));  	snprintf(info->version, sizeof(info->version), "%i.%i.%i", -		tigonFwReleaseMajor, tigonFwReleaseMinor, -		tigonFwReleaseFix); +		 ap->firmware_major, ap->firmware_minor, +		 ap->firmware_fix);  	if (ap->pdev)  		strlcpy(info->bus_info, pci_name(ap->pdev), @@ -2869,11 +2871,10 @@ static struct net_device_stats *ace_get_stats(struct net_device *dev)  } -static void __devinit ace_copy(struct ace_regs __iomem *regs, void *src, -			    u32 dest, int size) +static void __devinit ace_copy(struct ace_regs __iomem *regs, const __be32 *src, +			       u32 dest, int size)  {  	void __iomem *tdest; -	u32 *wsrc;  	short tsize, i;  	if (size <= 0) @@ -2885,20 +2886,15 @@ static void __devinit ace_copy(struct ace_regs __iomem *regs, void *src,  		tdest = (void __iomem *) ®s->Window +  			(dest & (ACE_WINDOW_SIZE - 1));  		writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase); -		/* -		 * This requires byte swapping on big endian, however -		 * writel does that for us -		 */ -		wsrc = src;  		for (i = 0; i < (tsize / 4); i++) { -			writel(wsrc[i], tdest + i*4); +			/* Firmware is big-endian */ +			writel(be32_to_cpup(src), tdest); +			src++; +			tdest += 4; +			dest += 4; +			size -= 4;  		} -		dest += tsize; -		src += tsize; -		size -= tsize;  	} - -	return;  } @@ -2937,8 +2933,13 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz   */  static int __devinit ace_load_firmware(struct net_device *dev)  { +	const struct firmware *fw; +	const char *fw_name = "acenic/tg2.bin";  	struct ace_private *ap = netdev_priv(dev);  	struct ace_regs __iomem *regs = ap->regs; +	const __be32 *fw_data; +	u32 load_addr; +	int ret;  	if (!(readl(®s->CpuCtrl) & CPU_HALTED)) {  		printk(KERN_ERR "%s: trying to download firmware while the " @@ -2946,28 +2947,52 @@ static int __devinit ace_load_firmware(struct net_device *dev)  		return -EFAULT;  	} +	if (ACE_IS_TIGON_I(ap)) +		fw_name = "acenic/tg1.bin"; + +	ret = request_firmware(&fw, fw_name, &ap->pdev->dev); +	if (ret) { +		printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n", +		       ap->name, fw_name); +		return ret; +	} + +	fw_data = (void *)fw->data; + +	/* Firmware blob starts with version numbers, followed by +	   load and start address. Remainder is the blob to be loaded +	   contiguously from load address. We don't bother to represent +	   the BSS/SBSS sections any more, since we were clearing the +	   whole thing anyway. */ +	ap->firmware_major = fw->data[0]; +	ap->firmware_minor = fw->data[1]; +	ap->firmware_fix = fw->data[2]; + +	ap->firmware_start = be32_to_cpu(fw_data[1]); +	if (ap->firmware_start < 0x4000 || ap->firmware_start >= 0x80000) { +		printk(KERN_ERR "%s: bogus load address %08x in \"%s\"\n", +		       ap->name, ap->firmware_start, fw_name); +		ret = -EINVAL; +		goto out; +	} + +	load_addr = be32_to_cpu(fw_data[2]); +	if (load_addr < 0x4000 || load_addr >= 0x80000) { +		printk(KERN_ERR "%s: bogus load address %08x in \"%s\"\n", +		       ap->name, load_addr, fw_name); +		ret = -EINVAL; +		goto out; +	} +  	/* -	 * Do not try to clear more than 512KB or we end up seeing -	 * funny things on NICs with only 512KB SRAM +	 * Do not try to clear more than 512KiB or we end up seeing +	 * funny things on NICs with only 512KiB SRAM  	 */  	ace_clear(regs, 0x2000, 0x80000-0x2000); -	if (ACE_IS_TIGON_I(ap)) { -		ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen); -		ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen); -		ace_copy(regs, tigonFwRodata, tigonFwRodataAddr, -			 tigonFwRodataLen); -		ace_clear(regs, tigonFwBssAddr, tigonFwBssLen); -		ace_clear(regs, tigonFwSbssAddr, tigonFwSbssLen); -	}else if (ap->version == 2) { -		ace_clear(regs, tigon2FwBssAddr, tigon2FwBssLen); -		ace_clear(regs, tigon2FwSbssAddr, tigon2FwSbssLen); -		ace_copy(regs, tigon2FwText, tigon2FwTextAddr,tigon2FwTextLen); -		ace_copy(regs, tigon2FwRodata, tigon2FwRodataAddr, -			 tigon2FwRodataLen); -		ace_copy(regs, tigon2FwData, tigon2FwDataAddr,tigon2FwDataLen); -	} - -	return 0; +	ace_copy(regs, &fw_data[3], load_addr, fw->size-12); + out: +	release_firmware(fw); +	return ret;  }  | 
