Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b775a750 authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller
Browse files

typhoon: Use request_firmware()



Based on a patch by Jaswinder Singh <jaswinder@infradead.org>.

Compile-tested only.

Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 06e1f9ff
Loading
Loading
Loading
Loading

drivers/net/typhoon-firmware.h

deleted100644 → 0
+0 −3778

File deleted.

File size exceeds preview limit.

+74 −57
Original line number Diff line number Diff line
@@ -129,16 +129,18 @@ 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";

#define FIRMWARE_NAME		"3com/typhoon.bin"
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,45 +1346,61 @@ typhoon_init_rings(struct typhoon *tp)
	tp->txHiRing.lastRead = 0;
}

static const struct firmware *typhoon_fw;

static int
typhoon_request_firmware(struct typhoon *tp)
{
	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;
	}

	if (typhoon_fw->size < sizeof(struct typhoon_file_header) ||
	    memcmp(typhoon_fw->data, "TYPHOON", 8)) {
		printk(KERN_ERR "%s: Invalid firmware image\n",
		       tp->name);
		release_firmware(typhoon_fw);
		typhoon_fw = NULL;
		return -EINVAL;
	}

	return 0;
}

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;
	void *dpage;
	dma_addr_t dpage_dma;
	const struct typhoon_file_header *fHdr;
	const struct typhoon_section_header *sHdr;
	const u8 *image_data;
	dma_addr_t image_dma;
	__sum16 csum;
	u32 irqEnabled;
	u32 irqMasked;
	u32 numSections;
	u32 section_len;
	u32 len;
	u32 load_addr;
	u32 hmac;
	int i;
	int err;

	err = -EINVAL;
	fHdr = (struct typhoon_file_header *) typhoon_firmware_image;
	image_data = (u8 *) fHdr;
	image_data = typhoon_fw->data;
	fHdr = (struct typhoon_file_header *) image_data;

	if(memcmp(fHdr->tag, "TYPHOON", 8)) {
		printk(KERN_ERR "%s: Invalid firmware image!\n", tp->name);
		goto err_out;
	}

	/* 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.
	 */
	err = -ENOMEM;
	dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma);
	if(!dpage) {
	image_dma = pci_map_single(pdev, (u8 *) typhoon_fw->data,
				   typhoon_fw->size, PCI_DMA_TODEVICE);
	if (pci_dma_mapping_error(pdev, image_dma)) {
		printk(KERN_ERR "%s: no DMA mem for firmware\n", tp->name);
		goto err_out;
	}
@@ -1430,9 +1448,6 @@ typhoon_download_firmware(struct typhoon *tp)
		load_addr = le32_to_cpu(sHdr->startAddr);
		section_len = le32_to_cpu(sHdr->len);

		while(section_len) {
			len = min_t(u32, section_len, PAGE_SIZE);

		if (typhoon_wait_interrupt(ioaddr) < 0 ||
		    ioread32(ioaddr + TYPHOON_REG_STATUS) !=
		    TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
@@ -1446,25 +1461,21 @@ typhoon_download_firmware(struct typhoon *tp)
		 * summing. Fortunately, due to the properties of
		 * the checksum, we can do this once, at the end.
		 */
			csum = csum_fold(csum_partial_copy_nocheck(image_data,
								  dpage, len,
								  0));
		csum = csum_fold(csum_partial(image_data, section_len, 0));

			iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
		iowrite32(section_len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
		iowrite32(le16_to_cpu((__force __le16)csum),
			  ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
		iowrite32(load_addr,
			  ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
		iowrite32(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI);
			iowrite32(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
		iowrite32(image_dma + (image_data - typhoon_fw->data),
			  ioaddr + TYPHOON_REG_BOOT_DATA_LO);
		typhoon_post_pci_writes(ioaddr);
		iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
			  ioaddr + TYPHOON_REG_COMMAND);

			image_data += len;
			load_addr += len;
			section_len -= len;
		}
		image_data += section_len;
	}

	if(typhoon_wait_interrupt(ioaddr) < 0 ||
@@ -1488,7 +1499,7 @@ typhoon_download_firmware(struct typhoon *tp)
	iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK);
	iowrite32(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE);

	pci_free_consistent(pdev, PAGE_SIZE, dpage, dpage_dma);
	pci_unmap_single(pdev, image_dma,  typhoon_fw->size, PCI_DMA_TODEVICE);

err_out:
	return err;
@@ -2086,6 +2097,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 +2639,8 @@ typhoon_init(void)
static void __exit
typhoon_cleanup(void)
{
	if (typhoon_fw)
		release_firmware(typhoon_fw);
	pci_unregister_driver(&typhoon_driver);
}