Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / net / ioc3-eth.c
index a93cda6..ae71ed5 100644 (file)
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/dma-mapping.h>
 
 #ifdef CONFIG_SERIAL_8250
-#include <linux/serial.h>
-#include <asm/serial.h>
-#define IOC3_BAUD (22000000 / (3*16))
-#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #endif
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/skbuff.h>
-#include <linux/dp83840.h>
 #include <net/ip.h>
 
 #include <asm/byteorder.h>
@@ -463,6 +461,29 @@ static void ioc3_get_eaddr(struct ioc3_private *ip)
        printk(".\n");
 }
 
+static void __ioc3_set_mac_address(struct net_device *dev)
+{
+       struct ioc3_private *ip = netdev_priv(dev);
+       struct ioc3 *ioc3 = ip->regs;
+
+       ioc3_w_emar_h((dev->dev_addr[5] <<  8) | dev->dev_addr[4]);
+       ioc3_w_emar_l((dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) |
+                     (dev->dev_addr[1] <<  8) | dev->dev_addr[0]);
+}
+
+static int ioc3_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct ioc3_private *ip = netdev_priv(dev);
+       struct sockaddr *sa = addr;
+
+       memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+       spin_lock_irq(&ip->ioc3_lock);
+       __ioc3_set_mac_address(dev);
+       spin_unlock_irq(&ip->ioc3_lock);
+
+       return 0;
+}
 
 /*
  * Caller must hold the ioc3_lock ever for MII readers.  This is also
@@ -477,7 +498,7 @@ static int ioc3_mdio_read(struct net_device *dev, int phy, int reg)
        ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG);
        while (ioc3_r_micr() & MICR_BUSY);
 
-       return ioc3_r_micr() & MIDR_DATA_MASK;
+       return ioc3_r_midr_r() & MIDR_DATA_MASK;
 }
 
 static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data)
@@ -506,7 +527,7 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
 
 static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
 {
-       struct ethhdr *eh = skb->mac.ethernet;
+       struct ethhdr *eh = eth_hdr(skb);
        uint32_t csum, ehsum;
        unsigned int proto;
        struct iphdr *ih;
@@ -1014,9 +1035,7 @@ static void ioc3_init(struct net_device *dev)
        (void) ioc3_r_etcdc();                  /* Clear on read */
        ioc3_w_ercsr(15);                       /* RX low watermark  */
        ioc3_w_ertr(0);                         /* Interrupt immediately */
-       ioc3_w_emar_h((dev->dev_addr[5] <<  8) | dev->dev_addr[4]);
-       ioc3_w_emar_l((dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) |
-                     (dev->dev_addr[1] <<  8) | dev->dev_addr[0]);
+       __ioc3_set_mac_address(dev);
        ioc3_w_ehar_h(ip->ehar_h);
        ioc3_w_ehar_l(ip->ehar_l);
        ioc3_w_ersr(42);                        /* XXX should be random */
@@ -1100,6 +1119,7 @@ static inline int ioc3_is_menet(struct pci_dev *pdev)
               && dev->device == PCI_DEVICE_ID_SGI_IOC3;
 }
 
+#ifdef CONFIG_SERIAL_8250
 /*
  * Note about serial ports and consoles:
  * For console output, everyone uses the IOC3 UARTA (offset 0x178)
@@ -1121,17 +1141,15 @@ static inline int ioc3_is_menet(struct pci_dev *pdev)
  * "device" routine referred to in this console structure
  * (ip27prom_console_dev).
  *
- * Also look in ip27-pci.c:pci_fixuop_ioc3() for some comments on working
+ * Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working
  * around ioc3 oddities in this respect.
  *
  * The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
- * (IOC3_BAUD = (22000000 / (3*16)))
  */
 
-static inline void ioc3_serial_probe(struct pci_dev *pdev,
-                               struct ioc3 *ioc3)
+static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
 {
-       struct serial_struct req;
+       struct uart_port port;
 
        /*
         * We need to recognice and treat the fourth MENET serial as it
@@ -1145,24 +1163,29 @@ static inline void ioc3_serial_probe(struct pci_dev *pdev,
        if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
                return;
 
-       /* Register to interrupt zero because we share the interrupt with
-          the serial driver which we don't properly support yet.  */
-       memset(&req, 0, sizeof(req));
-       req.irq             = 0;
-       req.flags           = IOC3_COM_FLAGS;
-       req.io_type         = SERIAL_IO_MEM;
-       req.iomem_reg_shift = 0;
-       req.baud_base       = IOC3_BAUD;
-
-       req.iomem_base      = (unsigned char *) &ioc3->sregs.uarta;
-       register_serial(&req);
-
-       req.iomem_base      = (unsigned char *) &ioc3->sregs.uartb;
-       register_serial(&req);
+       /*
+        * Register to interrupt zero because we share the interrupt with
+        * the serial driver which we don't properly support yet.
+        *
+        * Can't use UPF_IOREMAP as the whole of IOC3 resources have already
+        * been registered.
+        */
+       memset(&port, 0, sizeof(port));
+       port.irq      = 0;
+       port.flags    = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       port.iotype   = UPIO_MEM;
+       port.regshift = 0;
+       port.uartclk  = 22000000 / 3;
+
+       port.membase  = (unsigned char *) &ioc3->sregs.uarta;
+       serial8250_register_port(&port);
+
+       port.membase  = (unsigned char *) &ioc3->sregs.uartb;
+       serial8250_register_port(&port);
 }
+#endif
 
-static int __devinit ioc3_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned int sw_physid1, sw_physid2;
        struct net_device *dev = NULL;
@@ -1170,11 +1193,39 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
        struct ioc3 *ioc3;
        unsigned long ioc3_base, ioc3_size;
        u32 vendor, model, rev;
-       int err;
+       int err, pci_using_dac;
+
+       /* Configure DMA attributes. */
+       err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+       if (!err) {
+               pci_using_dac = 1;
+               err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+               if (err < 0) {
+                       printk(KERN_ERR "%s: Unable to obtain 64 bit DMA "
+                              "for consistent allocations\n", pci_name(pdev));
+                       goto out;
+               }
+       } else {
+               err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (err) {
+                       printk(KERN_ERR "%s: No usable DMA configuration, "
+                              "aborting.\n", pci_name(pdev));
+                       goto out;
+               }
+               pci_using_dac = 0;
+       }
+
+       if (pci_enable_device(pdev))
+               return -ENODEV;
 
        dev = alloc_etherdev(sizeof(struct ioc3_private));
-       if (!dev)
-               return -ENOMEM;
+       if (!dev) {
+               err = -ENOMEM;
+               goto out_disable;
+       }
+
+       if (pci_using_dac)
+               dev->features |= NETIF_F_HIGHDMA;
 
        err = pci_request_regions(pdev, "ioc3");
        if (err)
@@ -1237,12 +1288,12 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
        dev->get_stats          = ioc3_get_stats;
        dev->do_ioctl           = ioc3_ioctl;
        dev->set_multicast_list = ioc3_set_multicast_list;
+       dev->set_mac_address    = ioc3_set_mac_address;
        dev->ethtool_ops        = &ioc3_ethtool_ops;
 #ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
        dev->features           = NETIF_F_IP_CSUM;
 #endif
 
-       ioc3_setup_duplex(ip);
        sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
        sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
 
@@ -1251,6 +1302,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
                goto out_stop;
 
        mii_check_media(&ip->mii, 1, 1);
+       ioc3_setup_duplex(ip);
 
        vendor = (sw_physid1 << 12) | (sw_physid2 >> 4);
        model  = (sw_physid2 >> 4) & 0x3f;
@@ -1269,6 +1321,12 @@ out_res:
        pci_release_regions(pdev);
 out_free:
        free_netdev(dev);
+out_disable:
+       /*
+        * We should call pci_disable_device(pdev); here if the IOC3 wasn't
+        * such a weird device ...
+        */
+out:
        return err;
 }
 
@@ -1282,6 +1340,10 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev)
        iounmap(ioc3);
        pci_release_regions(pdev);
        free_netdev(dev);
+       /*
+        * We should call pci_disable_device(pdev); here if the IOC3 wasn't
+        * such a weird device ...
+        */
 }
 
 static struct pci_device_id ioc3_pci_tbl[] = {
@@ -1299,7 +1361,7 @@ static struct pci_driver ioc3_driver = {
 
 static int __init ioc3_init_module(void)
 {
-       return pci_module_init(&ioc3_driver);
+       return pci_register_driver(&ioc3_driver);
 }
 
 static void __exit ioc3_cleanup_module(void)
@@ -1333,7 +1395,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                uint32_t csum, ehsum;
                uint16_t *eh;
 
-               /* The MAC header.  skb->mac.ethernet seem the logic approach
+               /* The MAC header.  skb->mac seem the logic approach
                   to find the MAC header - except it's a NULL pointer ...  */
                eh = (uint16_t *) skb->data;
 
@@ -1465,7 +1527,7 @@ static void ioc3_get_drvinfo (struct net_device *dev,
        struct ethtool_drvinfo *info)
 {
        struct ioc3_private *ip = netdev_priv(dev);
-                                                                                
+
         strcpy (info->driver, IOC3_NAME);
         strcpy (info->version, IOC3_VERSION);
         strcpy (info->bus_info, pci_name(ip->pdev));
@@ -1491,7 +1553,7 @@ static int ioc3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        spin_lock_irq(&ip->ioc3_lock);
        rc = mii_ethtool_sset(&ip->mii, cmd);
        spin_unlock_irq(&ip->ioc3_lock);
-                                                                        
+
        return rc;
 }