177 lines
5.2 KiB
Diff
177 lines
5.2 KiB
Diff
commit 3185588805914cbaedae010d9c7f238f119a4ed3
|
|
Author: Ben Hutchings <ben@decadent.org.uk>
|
|
Date: Sun Feb 22 19:25:27 2009 +0000
|
|
|
|
typhoon: Use request_firmware()
|
|
|
|
Based on a patch by Jaswinder Singh <jaswinder@infradead.org> and
|
|
fixes for my bugs by David Dillow <dave@thedillows.org>.
|
|
|
|
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
|
|
index 05f99fd..6134136 100644
|
|
--- a/drivers/net/Kconfig
|
|
+++ b/drivers/net/Kconfig
|
|
@@ -733,7 +733,7 @@ config VORTEX
|
|
config TYPHOON
|
|
tristate "3cr990 series \"Typhoon\" support"
|
|
depends on NET_VENDOR_3COM && PCI
|
|
- depends on BROKEN
|
|
+ select FW_LOADER
|
|
select CRC32
|
|
---help---
|
|
This option enables driver support for the 3cr990 series of cards:
|
|
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
|
|
index 3af9a95..e907e86 100644
|
|
--- a/drivers/net/typhoon.c
|
|
+++ b/drivers/net/typhoon.c
|
|
@@ -104,6 +104,7 @@ static const int multicast_filter_limit = 32;
|
|
#define DRV_MODULE_RELDATE "06/11/09"
|
|
#define PFX DRV_MODULE_NAME ": "
|
|
#define ERR_PFX KERN_ERR PFX
|
|
+#define FIRMWARE_NAME "3com/typhoon.bin"
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
@@ -129,9 +130,9 @@ static const int multicast_filter_limit = 32;
|
|
#include <asm/uaccess.h>
|
|
#include <linux/in6.h>
|
|
#include <linux/dma-mapping.h>
|
|
+#include <linux/firmware.h>
|
|
|
|
#include "typhoon.h"
|
|
-#include "typhoon-firmware.h"
|
|
|
|
static char version[] __devinitdata =
|
|
"typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
|
|
@@ -139,6 +140,7 @@ static char version[] __devinitdata =
|
|
MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
|
|
MODULE_VERSION(DRV_MODULE_VERSION);
|
|
MODULE_LICENSE("GPL");
|
|
+MODULE_FIRMWARE(FIRMWARE_NAME);
|
|
MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
|
|
MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and "
|
|
"the buffer given back to the NIC. Default "
|
|
@@ -1344,14 +1346,74 @@ typhoon_init_rings(struct typhoon *tp)
|
|
tp->txHiRing.lastRead = 0;
|
|
}
|
|
|
|
+static const struct firmware *typhoon_fw;
|
|
+
|
|
+static int
|
|
+typhoon_request_firmware(struct typhoon *tp)
|
|
+{
|
|
+ const struct typhoon_file_header *fHdr;
|
|
+ const struct typhoon_section_header *sHdr;
|
|
+ const u8 *image_data;
|
|
+ u32 numSections;
|
|
+ u32 section_len;
|
|
+ u32 remaining;
|
|
+ int err;
|
|
+
|
|
+ if (typhoon_fw)
|
|
+ return 0;
|
|
+
|
|
+ err = request_firmware(&typhoon_fw, FIRMWARE_NAME, &tp->pdev->dev);
|
|
+ if (err) {
|
|
+ printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
|
|
+ tp->name, FIRMWARE_NAME);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ image_data = (u8 *) typhoon_fw->data;
|
|
+ remaining = typhoon_fw->size;
|
|
+ if (remaining < sizeof(struct typhoon_file_header))
|
|
+ goto invalid_fw;
|
|
+
|
|
+ fHdr = (struct typhoon_file_header *) image_data;
|
|
+ if (memcmp(fHdr->tag, "TYPHOON", 8))
|
|
+ goto invalid_fw;
|
|
+
|
|
+ numSections = le32_to_cpu(fHdr->numSections);
|
|
+ image_data += sizeof(struct typhoon_file_header);
|
|
+ remaining -= sizeof(struct typhoon_file_header);
|
|
+
|
|
+ while (numSections--) {
|
|
+ if (remaining < sizeof(struct typhoon_section_header))
|
|
+ goto invalid_fw;
|
|
+
|
|
+ sHdr = (struct typhoon_section_header *) image_data;
|
|
+ image_data += sizeof(struct typhoon_section_header);
|
|
+ section_len = le32_to_cpu(sHdr->len);
|
|
+
|
|
+ if (remaining < section_len)
|
|
+ goto invalid_fw;
|
|
+
|
|
+ image_data += section_len;
|
|
+ remaining -= section_len;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+invalid_fw:
|
|
+ printk(KERN_ERR "%s: Invalid firmware image\n", tp->name);
|
|
+ release_firmware(typhoon_fw);
|
|
+ typhoon_fw = NULL;
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
static int
|
|
typhoon_download_firmware(struct typhoon *tp)
|
|
{
|
|
void __iomem *ioaddr = tp->ioaddr;
|
|
struct pci_dev *pdev = tp->pdev;
|
|
- struct typhoon_file_header *fHdr;
|
|
- struct typhoon_section_header *sHdr;
|
|
- u8 *image_data;
|
|
+ const struct typhoon_file_header *fHdr;
|
|
+ const struct typhoon_section_header *sHdr;
|
|
+ const u8 *image_data;
|
|
void *dpage;
|
|
dma_addr_t dpage_dma;
|
|
__sum16 csum;
|
|
@@ -1365,20 +1427,12 @@ typhoon_download_firmware(struct typhoon *tp)
|
|
int i;
|
|
int err;
|
|
|
|
- err = -EINVAL;
|
|
- fHdr = (struct typhoon_file_header *) typhoon_firmware_image;
|
|
- image_data = (u8 *) fHdr;
|
|
-
|
|
- if(memcmp(fHdr->tag, "TYPHOON", 8)) {
|
|
- printk(KERN_ERR "%s: Invalid firmware image!\n", tp->name);
|
|
- goto err_out;
|
|
- }
|
|
+ image_data = (u8 *) typhoon_fw->data;
|
|
+ fHdr = (struct typhoon_file_header *) image_data;
|
|
|
|
/* Cannot just map the firmware image using pci_map_single() as
|
|
- * the firmware is part of the kernel/module image, so we allocate
|
|
- * some consistent memory to copy the sections into, as it is simpler,
|
|
- * and short-lived. If we ever split out and require a userland
|
|
- * firmware loader, then we can revisit this.
|
|
+ * the firmware is vmalloc()'d and may not be physically contiguous,
|
|
+ * so we allocate some consistent memory to copy the sections into.
|
|
*/
|
|
err = -ENOMEM;
|
|
dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma);
|
|
@@ -2086,6 +2140,10 @@ typhoon_open(struct net_device *dev)
|
|
struct typhoon *tp = netdev_priv(dev);
|
|
int err;
|
|
|
|
+ err = typhoon_request_firmware(tp);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
err = typhoon_wakeup(tp, WaitSleep);
|
|
if(err < 0) {
|
|
printk(KERN_ERR "%s: unable to wakeup device\n", dev->name);
|
|
@@ -2624,6 +2682,8 @@ typhoon_init(void)
|
|
static void __exit
|
|
typhoon_cleanup(void)
|
|
{
|
|
+ if (typhoon_fw)
|
|
+ release_firmware(typhoon_fw);
|
|
pci_unregister_driver(&typhoon_driver);
|
|
}
|
|
|