]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/b44.c
[PATCH] fix wrong error code on interrupted close syscalls
[mv-sheeva.git] / drivers / net / b44.c
index 12fc67a740eaefb4eb3a0c58cab330ce6df861e5..e891ea2ecc3c0464c4ed008181d528386be98edd 100644 (file)
@@ -29,8 +29,8 @@
 
 #define DRV_MODULE_NAME                "b44"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.00"
-#define DRV_MODULE_RELDATE     "Apr 7, 2006"
+#define DRV_MODULE_VERSION     "1.01"
+#define DRV_MODULE_RELDATE     "Jun 16, 2006"
 
 #define B44_DEF_MSG_ENABLE       \
        (NETIF_MSG_DRV          | \
 /* minimum number of free TX descriptors required to wake up TX process */
 #define B44_TX_WAKEUP_THRESH           (B44_TX_RING_SIZE / 4)
 
+/* b44 internal pattern match filter info */
+#define B44_PATTERN_BASE       0x400
+#define B44_PATTERN_SIZE       0x80
+#define B44_PMASK_BASE         0x600
+#define B44_PMASK_SIZE         0x10
+#define B44_MAX_PATTERNS       16
+#define B44_ETHIPV6UDP_HLEN    62
+#define B44_ETHIPV4UDP_HLEN    42
+
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
@@ -1412,7 +1421,7 @@ static int b44_open(struct net_device *dev)
 
        b44_check_phy(bp);
 
-       err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
+       err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
        if (unlikely(err < 0)) {
                b44_chip_reset(bp);
                b44_free_rings(bp);
@@ -1457,6 +1466,103 @@ static void b44_poll_controller(struct net_device *dev)
 }
 #endif
 
+static void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset)
+{
+       u32 i;
+       u32 *pattern = (u32 *) pp;
+
+       for (i = 0; i < bytes; i += sizeof(u32)) {
+               bw32(bp, B44_FILT_ADDR, table_offset + i);
+               bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]);
+       }
+}
+
+static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
+{
+       int magicsync = 6;
+       int k, j, len = offset;
+       int ethaddr_bytes = ETH_ALEN;
+
+       memset(ppattern + offset, 0xff, magicsync);
+       for (j = 0; j < magicsync; j++)
+               set_bit(len++, (unsigned long *) pmask);
+
+       for (j = 0; j < B44_MAX_PATTERNS; j++) {
+               if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
+                       ethaddr_bytes = ETH_ALEN;
+               else
+                       ethaddr_bytes = B44_PATTERN_SIZE - len;
+               if (ethaddr_bytes <=0)
+                       break;
+               for (k = 0; k< ethaddr_bytes; k++) {
+                       ppattern[offset + magicsync +
+                               (j * ETH_ALEN) + k] = macaddr[k];
+                       len++;
+                       set_bit(len, (unsigned long *) pmask);
+               }
+       }
+       return len - 1;
+}
+
+/* Setup magic packet patterns in the b44 WOL
+ * pattern matching filter.
+ */
+static void b44_setup_pseudo_magicp(struct b44 *bp)
+{
+
+       u32 val;
+       int plen0, plen1, plen2;
+       u8 *pwol_pattern;
+       u8 pwol_mask[B44_PMASK_SIZE];
+
+       pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
+       if (!pwol_pattern) {
+               printk(KERN_ERR PFX "Memory not available for WOL\n");
+               return;
+       }
+
+       /* Ipv4 magic packet pattern - pattern 0.*/
+       memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+       memset(pwol_mask, 0, B44_PMASK_SIZE);
+       plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+                                 B44_ETHIPV4UDP_HLEN);
+
+       bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
+       bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
+
+       /* Raw ethernet II magic packet pattern - pattern 1 */
+       memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+       memset(pwol_mask, 0, B44_PMASK_SIZE);
+       plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+                                 ETH_HLEN);
+
+       bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+                      B44_PATTERN_BASE + B44_PATTERN_SIZE);
+       bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+                      B44_PMASK_BASE + B44_PMASK_SIZE);
+
+       /* Ipv6 magic packet pattern - pattern 2 */
+       memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+       memset(pwol_mask, 0, B44_PMASK_SIZE);
+       plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+                                 B44_ETHIPV6UDP_HLEN);
+
+       bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+                      B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
+       bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+                      B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
+
+       kfree(pwol_pattern);
+
+       /* set these pattern's lengths: one less than each real length */
+       val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE;
+       bw32(bp, B44_WKUP_LEN, val);
+
+       /* enable wakeup pattern matching */
+       val = br32(bp, B44_DEVCTRL);
+       bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE);
+
+}
 
 static void b44_setup_wol(struct b44 *bp)
 {
@@ -1482,7 +1588,9 @@ static void b44_setup_wol(struct b44 *bp)
                val = br32(bp, B44_DEVCTRL);
                bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
 
-       }
+       } else {
+               b44_setup_pseudo_magicp(bp);
+       }
 
        val = br32(bp, B44_SBTMSLOW);
        bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
@@ -1904,7 +2012,7 @@ static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        return 0;
 }
 
-static struct ethtool_ops b44_ethtool_ops = {
+static const struct ethtool_ops b44_ethtool_ops = {
        .get_drvinfo            = b44_get_drvinfo,
        .get_settings           = b44_get_settings,
        .set_settings           = b44_set_settings,
@@ -2012,13 +2120,14 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot enable PCI device, "
+               dev_err(&pdev->dev, "Cannot enable PCI device, "
                       "aborting.\n");
                return err;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX "Cannot find proper PCI device "
+               dev_err(&pdev->dev,
+                       "Cannot find proper PCI device "
                       "base address, aborting.\n");
                err = -ENODEV;
                goto err_out_disable_pdev;
@@ -2026,8 +2135,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = pci_request_regions(pdev, DRV_MODULE_NAME);
        if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources, "
-                      "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Cannot obtain PCI resources, aborting.\n");
                goto err_out_disable_pdev;
        }
 
@@ -2035,15 +2144,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
        if (err) {
-               printk(KERN_ERR PFX "No usable DMA configuration, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
                goto err_out_free_res;
        }
 
        err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
        if (err) {
-               printk(KERN_ERR PFX "No usable DMA configuration, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
                goto err_out_free_res;
        }
 
@@ -2052,7 +2159,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        dev = alloc_etherdev(sizeof(*bp));
        if (!dev) {
-               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+               dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
                err = -ENOMEM;
                goto err_out_free_res;
        }
@@ -2073,8 +2180,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        bp->regs = ioremap(b44reg_base, b44reg_len);
        if (bp->regs == 0UL) {
-               printk(KERN_ERR PFX "Cannot map device registers, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
                err = -ENOMEM;
                goto err_out_free_dev;
        }
@@ -2104,8 +2210,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = b44_get_invariants(bp);
        if (err) {
-               printk(KERN_ERR PFX "Problem fetching invariants of chip, "
-                      "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Problem fetching invariants of chip, aborting.\n");
                goto err_out_iounmap;
        }
 
@@ -2125,8 +2231,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = register_netdev(dev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register net device, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
                goto err_out_iounmap;
        }
 
@@ -2214,7 +2319,7 @@ static int b44_resume(struct pci_dev *pdev)
        if (!netif_running(dev))
                return 0;
 
-       if (request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev))
+       if (request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev))
                printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
 
        spin_lock_irq(&bp->lock);
@@ -2249,7 +2354,7 @@ static int __init b44_init(void)
        dma_desc_align_mask = ~(dma_desc_align_size - 1);
        dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
 
-       return pci_module_init(&b44_driver);
+       return pci_register_driver(&b44_driver);
 }
 
 static void __exit b44_cleanup(void)