aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/typhoon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/typhoon.c')
-rw-r--r--drivers/net/typhoon.c131
1 files changed, 74 insertions, 57 deletions
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index a8e5651f3165..cd3283f766d9 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -129,16 +129,18 @@ static const int multicast_filter_limit = 32;
129#include <asm/uaccess.h> 129#include <asm/uaccess.h>
130#include <linux/in6.h> 130#include <linux/in6.h>
131#include <linux/dma-mapping.h> 131#include <linux/dma-mapping.h>
132#include <linux/firmware.h>
132 133
133#include "typhoon.h" 134#include "typhoon.h"
134#include "typhoon-firmware.h"
135 135
136static char version[] __devinitdata = 136static char version[] __devinitdata =
137 "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 137 "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
138 138
139#define FIRMWARE_NAME "3com/typhoon.bin"
139MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); 140MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
140MODULE_VERSION(DRV_MODULE_VERSION); 141MODULE_VERSION(DRV_MODULE_VERSION);
141MODULE_LICENSE("GPL"); 142MODULE_LICENSE("GPL");
143MODULE_FIRMWARE(FIRMWARE_NAME);
142MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)"); 144MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
143MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and " 145MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and "
144 "the buffer given back to the NIC. Default " 146 "the buffer given back to the NIC. Default "
@@ -1344,45 +1346,61 @@ typhoon_init_rings(struct typhoon *tp)
1344 tp->txHiRing.lastRead = 0; 1346 tp->txHiRing.lastRead = 0;
1345} 1347}
1346 1348
1349static const struct firmware *typhoon_fw;
1350
1351static int
1352typhoon_request_firmware(struct typhoon *tp)
1353{
1354 int err;
1355
1356 if (typhoon_fw)
1357 return 0;
1358
1359 err = request_firmware(&typhoon_fw, FIRMWARE_NAME, &tp->pdev->dev);
1360 if (err) {
1361 printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
1362 tp->name, FIRMWARE_NAME);
1363 return err;
1364 }
1365
1366 if (typhoon_fw->size < sizeof(struct typhoon_file_header) ||
1367 memcmp(typhoon_fw->data, "TYPHOON", 8)) {
1368 printk(KERN_ERR "%s: Invalid firmware image\n",
1369 tp->name);
1370 release_firmware(typhoon_fw);
1371 typhoon_fw = NULL;
1372 return -EINVAL;
1373 }
1374
1375 return 0;
1376}
1377
1347static int 1378static int
1348typhoon_download_firmware(struct typhoon *tp) 1379typhoon_download_firmware(struct typhoon *tp)
1349{ 1380{
1350 void __iomem *ioaddr = tp->ioaddr; 1381 void __iomem *ioaddr = tp->ioaddr;
1351 struct pci_dev *pdev = tp->pdev; 1382 struct pci_dev *pdev = tp->pdev;
1352 struct typhoon_file_header *fHdr; 1383 const struct typhoon_file_header *fHdr;
1353 struct typhoon_section_header *sHdr; 1384 const struct typhoon_section_header *sHdr;
1354 u8 *image_data; 1385 const u8 *image_data;
1355 void *dpage; 1386 dma_addr_t image_dma;
1356 dma_addr_t dpage_dma;
1357 __sum16 csum; 1387 __sum16 csum;
1358 u32 irqEnabled; 1388 u32 irqEnabled;
1359 u32 irqMasked; 1389 u32 irqMasked;
1360 u32 numSections; 1390 u32 numSections;
1361 u32 section_len; 1391 u32 section_len;
1362 u32 len;
1363 u32 load_addr; 1392 u32 load_addr;
1364 u32 hmac; 1393 u32 hmac;
1365 int i; 1394 int i;
1366 int err; 1395 int err;
1367 1396
1368 err = -EINVAL; 1397 image_data = typhoon_fw->data;
1369 fHdr = (struct typhoon_file_header *) typhoon_firmware_image; 1398 fHdr = (struct typhoon_file_header *) image_data;
1370 image_data = (u8 *) fHdr;
1371
1372 if(memcmp(fHdr->tag, "TYPHOON", 8)) {
1373 printk(KERN_ERR "%s: Invalid firmware image!\n", tp->name);
1374 goto err_out;
1375 }
1376 1399
1377 /* Cannot just map the firmware image using pci_map_single() as
1378 * the firmware is part of the kernel/module image, so we allocate
1379 * some consistent memory to copy the sections into, as it is simpler,
1380 * and short-lived. If we ever split out and require a userland
1381 * firmware loader, then we can revisit this.
1382 */
1383 err = -ENOMEM; 1400 err = -ENOMEM;
1384 dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma); 1401 image_dma = pci_map_single(pdev, (u8 *) typhoon_fw->data,
1385 if(!dpage) { 1402 typhoon_fw->size, PCI_DMA_TODEVICE);
1403 if (pci_dma_mapping_error(pdev, image_dma)) {
1386 printk(KERN_ERR "%s: no DMA mem for firmware\n", tp->name); 1404 printk(KERN_ERR "%s: no DMA mem for firmware\n", tp->name);
1387 goto err_out; 1405 goto err_out;
1388 } 1406 }
@@ -1430,41 +1448,34 @@ typhoon_download_firmware(struct typhoon *tp)
1430 load_addr = le32_to_cpu(sHdr->startAddr); 1448 load_addr = le32_to_cpu(sHdr->startAddr);
1431 section_len = le32_to_cpu(sHdr->len); 1449 section_len = le32_to_cpu(sHdr->len);
1432 1450
1433 while(section_len) { 1451 if (typhoon_wait_interrupt(ioaddr) < 0 ||
1434 len = min_t(u32, section_len, PAGE_SIZE); 1452 ioread32(ioaddr + TYPHOON_REG_STATUS) !=
1453 TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
1454 printk(KERN_ERR "%s: segment ready timeout\n",
1455 tp->name);
1456 goto err_out_irq;
1457 }
1435 1458
1436 if(typhoon_wait_interrupt(ioaddr) < 0 || 1459 /* Do an pseudo IPv4 checksum on the data -- first
1437 ioread32(ioaddr + TYPHOON_REG_STATUS) != 1460 * need to convert each u16 to cpu order before
1438 TYPHOON_STATUS_WAITING_FOR_SEGMENT) { 1461 * summing. Fortunately, due to the properties of
1439 printk(KERN_ERR "%s: segment ready timeout\n", 1462 * the checksum, we can do this once, at the end.
1440 tp->name); 1463 */
1441 goto err_out_irq; 1464 csum = csum_fold(csum_partial(image_data, section_len, 0));
1442 } 1465
1466 iowrite32(section_len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
1467 iowrite32(le16_to_cpu((__force __le16)csum),
1468 ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
1469 iowrite32(load_addr,
1470 ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
1471 iowrite32(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI);
1472 iowrite32(image_dma + (image_data - typhoon_fw->data),
1473 ioaddr + TYPHOON_REG_BOOT_DATA_LO);
1474 typhoon_post_pci_writes(ioaddr);
1475 iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
1476 ioaddr + TYPHOON_REG_COMMAND);
1443 1477
1444 /* Do an pseudo IPv4 checksum on the data -- first 1478 image_data += section_len;
1445 * need to convert each u16 to cpu order before
1446 * summing. Fortunately, due to the properties of
1447 * the checksum, we can do this once, at the end.
1448 */
1449 csum = csum_fold(csum_partial_copy_nocheck(image_data,
1450 dpage, len,
1451 0));
1452
1453 iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
1454 iowrite32(le16_to_cpu((__force __le16)csum),
1455 ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
1456 iowrite32(load_addr,
1457 ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
1458 iowrite32(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI);
1459 iowrite32(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
1460 typhoon_post_pci_writes(ioaddr);
1461 iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE,
1462 ioaddr + TYPHOON_REG_COMMAND);
1463
1464 image_data += len;
1465 load_addr += len;
1466 section_len -= len;
1467 }
1468 } 1479 }
1469 1480
1470 if(typhoon_wait_interrupt(ioaddr) < 0 || 1481 if(typhoon_wait_interrupt(ioaddr) < 0 ||
@@ -1488,7 +1499,7 @@ err_out_irq:
1488 iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK); 1499 iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK);
1489 iowrite32(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE); 1500 iowrite32(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE);
1490 1501
1491 pci_free_consistent(pdev, PAGE_SIZE, dpage, dpage_dma); 1502 pci_unmap_single(pdev, image_dma, typhoon_fw->size, PCI_DMA_TODEVICE);
1492 1503
1493err_out: 1504err_out:
1494 return err; 1505 return err;
@@ -2086,6 +2097,10 @@ typhoon_open(struct net_device *dev)
2086 struct typhoon *tp = netdev_priv(dev); 2097 struct typhoon *tp = netdev_priv(dev);
2087 int err; 2098 int err;
2088 2099
2100 err = typhoon_request_firmware(tp);
2101 if (err)
2102 goto out;
2103
2089 err = typhoon_wakeup(tp, WaitSleep); 2104 err = typhoon_wakeup(tp, WaitSleep);
2090 if(err < 0) { 2105 if(err < 0) {
2091 printk(KERN_ERR "%s: unable to wakeup device\n", dev->name); 2106 printk(KERN_ERR "%s: unable to wakeup device\n", dev->name);
@@ -2624,6 +2639,8 @@ typhoon_init(void)
2624static void __exit 2639static void __exit
2625typhoon_cleanup(void) 2640typhoon_cleanup(void)
2626{ 2641{
2642 if (typhoon_fw)
2643 release_firmware(typhoon_fw);
2627 pci_unregister_driver(&typhoon_driver); 2644 pci_unregister_driver(&typhoon_driver);
2628} 2645}
2629 2646