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

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
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -129,16 +129,18 @@ static const int multicast_filter_limit = 32; ...@@ -129,16 +129,18 @@ static const int multicast_filter_limit = 32;
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/firmware.h>
#include "typhoon.h" #include "typhoon.h"
#include "typhoon-firmware.h"
static char version[] __devinitdata = static char version[] __devinitdata =
"typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
#define FIRMWARE_NAME "3com/typhoon.bin"
MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
MODULE_VERSION(DRV_MODULE_VERSION); MODULE_VERSION(DRV_MODULE_VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE_NAME);
MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)"); MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and " MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and "
"the buffer given back to the NIC. Default " "the buffer given back to the NIC. Default "
...@@ -1344,45 +1346,61 @@ typhoon_init_rings(struct typhoon *tp) ...@@ -1344,45 +1346,61 @@ typhoon_init_rings(struct typhoon *tp)
tp->txHiRing.lastRead = 0; 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 static int
typhoon_download_firmware(struct typhoon *tp) typhoon_download_firmware(struct typhoon *tp)
{ {
void __iomem *ioaddr = tp->ioaddr; void __iomem *ioaddr = tp->ioaddr;
struct pci_dev *pdev = tp->pdev; struct pci_dev *pdev = tp->pdev;
struct typhoon_file_header *fHdr; const struct typhoon_file_header *fHdr;
struct typhoon_section_header *sHdr; const struct typhoon_section_header *sHdr;
u8 *image_data; const u8 *image_data;
void *dpage; dma_addr_t image_dma;
dma_addr_t dpage_dma;
__sum16 csum; __sum16 csum;
u32 irqEnabled; u32 irqEnabled;
u32 irqMasked; u32 irqMasked;
u32 numSections; u32 numSections;
u32 section_len; u32 section_len;
u32 len;
u32 load_addr; u32 load_addr;
u32 hmac; u32 hmac;
int i; int i;
int err; int err;
err = -EINVAL; image_data = typhoon_fw->data;
fHdr = (struct typhoon_file_header *) typhoon_firmware_image; fHdr = (struct typhoon_file_header *) image_data;
image_data = (u8 *) fHdr;
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; err = -ENOMEM;
dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma); image_dma = pci_map_single(pdev, (u8 *) typhoon_fw->data,
if(!dpage) { 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); printk(KERN_ERR "%s: no DMA mem for firmware\n", tp->name);
goto err_out; goto err_out;
} }
...@@ -1430,10 +1448,7 @@ typhoon_download_firmware(struct typhoon *tp) ...@@ -1430,10 +1448,7 @@ typhoon_download_firmware(struct typhoon *tp)
load_addr = le32_to_cpu(sHdr->startAddr); load_addr = le32_to_cpu(sHdr->startAddr);
section_len = le32_to_cpu(sHdr->len); section_len = le32_to_cpu(sHdr->len);
while(section_len) { if (typhoon_wait_interrupt(ioaddr) < 0 ||
len = min_t(u32, section_len, PAGE_SIZE);
if(typhoon_wait_interrupt(ioaddr) < 0 ||
ioread32(ioaddr + TYPHOON_REG_STATUS) != ioread32(ioaddr + TYPHOON_REG_STATUS) !=
TYPHOON_STATUS_WAITING_FOR_SEGMENT) { TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
printk(KERN_ERR "%s: segment ready timeout\n", printk(KERN_ERR "%s: segment ready timeout\n",
...@@ -1446,25 +1461,21 @@ typhoon_download_firmware(struct typhoon *tp) ...@@ -1446,25 +1461,21 @@ typhoon_download_firmware(struct typhoon *tp)
* summing. Fortunately, due to the properties of * summing. Fortunately, due to the properties of
* the checksum, we can do this once, at the end. * the checksum, we can do this once, at the end.
*/ */
csum = csum_fold(csum_partial_copy_nocheck(image_data, csum = csum_fold(csum_partial(image_data, section_len, 0));
dpage, len,
0));
iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH); iowrite32(section_len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
iowrite32(le16_to_cpu((__force __le16)csum), iowrite32(le16_to_cpu((__force __le16)csum),
ioaddr + TYPHOON_REG_BOOT_CHECKSUM); ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
iowrite32(load_addr, iowrite32(load_addr,
ioaddr + TYPHOON_REG_BOOT_DEST_ADDR); ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
iowrite32(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI); 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); typhoon_post_pci_writes(ioaddr);
iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE, iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
ioaddr + TYPHOON_REG_COMMAND); ioaddr + TYPHOON_REG_COMMAND);
image_data += len; image_data += section_len;
load_addr += len;
section_len -= len;
}
} }
if(typhoon_wait_interrupt(ioaddr) < 0 || if(typhoon_wait_interrupt(ioaddr) < 0 ||
...@@ -1488,7 +1499,7 @@ typhoon_download_firmware(struct typhoon *tp) ...@@ -1488,7 +1499,7 @@ typhoon_download_firmware(struct typhoon *tp)
iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK); iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK);
iowrite32(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE); 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: err_out:
return err; return err;
...@@ -2086,6 +2097,10 @@ typhoon_open(struct net_device *dev) ...@@ -2086,6 +2097,10 @@ typhoon_open(struct net_device *dev)
struct typhoon *tp = netdev_priv(dev); struct typhoon *tp = netdev_priv(dev);
int err; int err;
err = typhoon_request_firmware(tp);
if (err)
goto out;
err = typhoon_wakeup(tp, WaitSleep); err = typhoon_wakeup(tp, WaitSleep);
if(err < 0) { if(err < 0) {
printk(KERN_ERR "%s: unable to wakeup device\n", dev->name); printk(KERN_ERR "%s: unable to wakeup device\n", dev->name);
...@@ -2624,6 +2639,8 @@ typhoon_init(void) ...@@ -2624,6 +2639,8 @@ typhoon_init(void)
static void __exit static void __exit
typhoon_cleanup(void) typhoon_cleanup(void)
{ {
if (typhoon_fw)
release_firmware(typhoon_fw);
pci_unregister_driver(&typhoon_driver); pci_unregister_driver(&typhoon_driver);
} }
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -52,6 +52,7 @@ fw-shipped-$(CONFIG_SND_YMFPCI) += yamaha/ds1_ctrl.fw yamaha/ds1_dsp.fw \ ...@@ -52,6 +52,7 @@ fw-shipped-$(CONFIG_SND_YMFPCI) += yamaha/ds1_ctrl.fw yamaha/ds1_dsp.fw \
fw-shipped-$(CONFIG_TEHUTI) += tehuti/bdx.bin fw-shipped-$(CONFIG_TEHUTI) += tehuti/bdx.bin
fw-shipped-$(CONFIG_TIGON3) += tigon/tg3.bin tigon/tg3_tso.bin \ fw-shipped-$(CONFIG_TIGON3) += tigon/tg3.bin tigon/tg3_tso.bin \
tigon/tg3_tso5.bin tigon/tg3_tso5.bin
fw-shipped-$(CONFIG_TYPHOON) += 3com/typhoon.bin
fw-shipped-$(CONFIG_USB_DABUSB) += dabusb/firmware.fw dabusb/bitstream.bin fw-shipped-$(CONFIG_USB_DABUSB) += dabusb/firmware.fw dabusb/bitstream.bin
fw-shipped-$(CONFIG_USB_EMI26) += emi26/loader.fw emi26/firmware.fw \ fw-shipped-$(CONFIG_USB_EMI26) += emi26/loader.fw emi26/firmware.fw \
emi26/bitstream.fw emi26/bitstream.fw
......
...@@ -451,3 +451,45 @@ Licence: ...@@ -451,3 +451,45 @@ Licence:
Found in hex form in kernel source. Found in hex form in kernel source.
-------------------------------------------------------------------------- --------------------------------------------------------------------------
Driver: TYPHOON - 3cr990 series Typhoon
File: 3com/typhoon.bin
Licence:
/*
* Copyright 1999-2004 3Com Corporation. All Rights Reserved.
*
* Redistribution and use in source and binary forms of the 3c990img.h
* microcode software are permitted provided that the following conditions
* are met:
* 1. Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of 3Com may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY 3COM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* USER ACKNOWLEDGES AND AGREES THAT PURCHASE OR USE OF THE 3c990img.h
* MICROCODE SOFTWARE WILL NOT CREATE OR GIVE GROUNDS FOR A LICENSE BY
* IMPLICATION, ESTOPPEL, OR OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS
* (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT)
* EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN
* COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE
*/
Found in hex form in kernel source.
--------------------------------------------------------------------------
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment