Merge branch 'fixes-jgarzik' of git://git.kernel.org/pub/scm/linux/kernel/git/linvill...
[safe/jmp/linux-2.6] / drivers / net / tc35815.c
index 1a1b74c..ec41469 100644 (file)
  *
  * (C) Copyright TOSHIBA CORPORATION 2004-2005
  * All Rights Reserved.
- *
- *  Revision History:
- *     1.13    64-bit proof.
- *     1.14    Do not round-up transmit length.
- *     1.15    Define TC35815_DMA_SYNC_ONDEMAND, cleanup.
- *     1.16    Fix free_page bug introduced in 1.15
- *     1.17    Add mii/ethtool ioctl support.
- *             Remove workaround for early TX4938.  Cleanup.
- *     1.20    Kernel 2.6.
- *     1.21    Fix receive packet length (omit CRC).
- *             Call netif_carrier_on/netif_carrier_off.
- *             Add kernel/module options (speed, duplex, doforce).
- *             Do not try "force link mode" by default.
- *             Reconfigure CAM on restarting.
- *             Reset PHY on restarting.
- *             Add workaround for 100MHalf HUB.
- *     1.22    Minor fix.
- *     1.23    Minor cleanup.
- *     1.24    Remove tc35815_setup since new stype option
- *             ("tc35815.speed=10", etc.) can be used for 2.6 kernel.
- *     1.25    TX4939 support.
- *     1.26    Minor cleanup.
- *     1.27    Move TX4939 PCFG.SPEEDn control code out from this driver.
- *             Cleanup init_dev_addr. (NETDEV_REGISTER event notifier
- *             can overwrite dev_addr)
- *             support ETHTOOL_GPERMADDR.
- *     1.28    Minor cleanup.
- *     1.29    support netpoll.
- *     1.30    Minor cleanup.
- *     1.31    NAPI support. (disabled by default)
- *             Use DMA_RxAlign_2 if possible.
- *             Do not use PackedBuffer.
- *             Cleanup.
- *     1.32    Fix free buffer management on non-PackedBuffer mode.
- *     1.33    Fix netpoll build.
- *     1.34    Fix netpoll locking.  "BH rule" for NAPI is not enough with
- *             netpoll, hard_start_xmit might be called from irq context.
- *             PM support.
  */
 
 #ifdef TC35815_NAPI
-#define DRV_VERSION    "1.34-NAPI"
+#define DRV_VERSION    "1.36-NAPI"
 #else
-#define DRV_VERSION    "1.34"
+#define DRV_VERSION    "1.36"
 #endif
 static const char *version = "tc35815.c:v" DRV_VERSION "\n";
 #define MODNAME                        "tc35815"
@@ -87,6 +49,7 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n";
 #include <linux/pci.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/platform_device.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
@@ -578,7 +541,6 @@ static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
        skb = dev_alloc_skb(RX_BUF_SIZE);
        if (!skb)
                return NULL;
-       skb->dev = dev;
        *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
                                     PCI_DMA_FROMDEVICE);
        if (pci_dma_mapping_error(*dma_handle)) {
@@ -636,13 +598,46 @@ static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
 static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
                          int val);
 
-static void __devinit tc35815_init_dev_addr (struct net_device *dev)
+#ifdef CONFIG_CPU_TX49XX
+/*
+ * Find a platform_device providing a MAC address.  The platform code
+ * should provide a "tc35815-mac" device with a MAC address in its
+ * platform_data.
+ */
+static int __devinit tc35815_mac_match(struct device *dev, void *data)
+{
+       struct platform_device *plat_dev = to_platform_device(dev);
+       struct pci_dev *pci_dev = data;
+       unsigned int id = (pci_dev->bus->number << 8) | pci_dev->devfn;
+       return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;
+}
+
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
+{
+       struct tc35815_local *lp = dev->priv;
+       struct device *pd = bus_find_device(&platform_bus_type, NULL,
+                                           lp->pci_dev, tc35815_mac_match);
+       if (pd) {
+               if (pd->platform_data)
+                       memcpy(dev->dev_addr, pd->platform_data, ETH_ALEN);
+               put_device(pd);
+               return is_valid_ether_addr(dev->dev_addr) ? 0 : -ENODEV;
+       }
+       return -ENODEV;
+}
+#else
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
+{
+       return -ENODEV;
+}
+#endif
+
+static int __devinit tc35815_init_dev_addr (struct net_device *dev)
 {
        struct tc35815_regs __iomem *tr =
                (struct tc35815_regs __iomem *)dev->base_addr;
        int i;
 
-       /* dev_addr will be overwritten on NETDEV_REGISTER event */
        while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
                ;
        for (i = 0; i < 6; i += 2) {
@@ -654,6 +649,9 @@ static void __devinit tc35815_init_dev_addr (struct net_device *dev)
                dev->dev_addr[i] = data & 0xff;
                dev->dev_addr[i+1] = data >> 8;
        }
+       if (!is_valid_ether_addr(dev->dev_addr))
+               return tc35815_read_plat_dev_addr(dev);
+       return 0;
 }
 
 static int __devinit tc35815_init_one (struct pci_dev *pdev,
@@ -763,7 +761,10 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev,
        tc35815_chip_reset(dev);
 
        /* Retrieve the ethernet address. */
-       tc35815_init_dev_addr(dev);
+       if (tc35815_init_dev_addr(dev)) {
+               dev_warn(&pdev->dev, "not valid ether addr\n");
+               random_ether_addr(dev->dev_addr);
+       }
 
        rc = register_netdev (dev);
        if (rc)
@@ -1550,6 +1551,11 @@ tc35815_rx(struct net_device *dev)
                                                            PCI_DMA_FROMDEVICE);
 #endif
                                memcpy(data + offset, rxbuf, len);
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+                               pci_dma_sync_single_for_device(lp->pci_dev,
+                                                              dma, len,
+                                                              PCI_DMA_FROMDEVICE);
+#endif
                                offset += len;
                                cur_bd++;
                        }
@@ -2192,7 +2198,6 @@ static const struct ethtool_ops tc35815_ethtool_ops = {
        .get_strings            = tc35815_get_strings,
        .get_stats_count        = tc35815_get_stats_count,
        .get_ethtool_stats      = tc35815_get_ethtool_stats,
-       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)