sb1000: update to net_device_ops
[safe/jmp/linux-2.6] / drivers / net / tulip / uli526x.c
index ca2548e..00cbc52 100644 (file)
@@ -34,9 +34,9 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/dma-mapping.h>
+#include <linux/bitops.h>
 
 #include <asm/processor.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
 
 /* Structure/enum declaration ------------------------------- */
 struct tx_desc {
-        u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+        __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
         char *tx_buf_ptr;               /* Data for us */
         struct tx_desc *next_tx_desc;
 } __attribute__(( aligned(32) ));
 
 struct rx_desc {
-       u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
+       __le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
        struct sk_buff *rx_skb_ptr;     /* Data for us */
        struct rx_desc *next_rx_desc;
 } __attribute__(( aligned(32) ));
@@ -225,6 +225,9 @@ static void uli526x_set_filter_mode(struct net_device *);
 static const struct ethtool_ops netdev_ethtool_ops;
 static u16 read_srom_word(long, int);
 static irqreturn_t uli526x_interrupt(int, void *);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void uli526x_poll(struct net_device *dev);
+#endif
 static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
 static void allocate_rx_buffer(struct uli526x_board_info *);
 static void update_cr6(u32, unsigned long);
@@ -268,7 +271,6 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
        dev = alloc_etherdev(sizeof(*db));
        if (dev == NULL)
                return -ENOMEM;
-       SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
@@ -339,12 +341,15 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
        dev->get_stats = &uli526x_get_stats;
        dev->set_multicast_list = &uli526x_set_filter_mode;
        dev->ethtool_ops = &netdev_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = &uli526x_poll;
+#endif
        spin_lock_init(&db->lock);
 
 
        /* read 64 word srom data */
        for (i = 0; i < 64; i++)
-               ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
+               ((__le16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
 
        /* Set Node address */
        if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0)               /* SROM absent, so read MAC address from ID Table */
@@ -373,11 +378,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
        if (err)
                goto err_out_res;
 
-       printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev));
-
-       for (i = 0; i < 6; i++)
-               printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
-       printk(", irq %d.\n", dev->irq);
+       printk(KERN_INFO "%s: ULi M%04lx at pci%s, %pM, irq %d.\n",
+              dev->name,ent->driver_data >> 16,pci_name(pdev),
+              dev->dev_addr, dev->irq);
 
        pci_set_master(pdev);
 
@@ -436,10 +439,6 @@ static int uli526x_open(struct net_device *dev)
 
        ULI526X_DBUG(0, "uli526x_open", 0);
 
-       ret = request_irq(dev->irq, &uli526x_interrupt, IRQF_SHARED, dev->name, dev);
-       if (ret)
-               return ret;
-
        /* system variable init */
        db->cr6_data = CR6_DEFAULT | uli526x_cr6_user_set;
        db->tx_packet_cnt = 0;
@@ -458,6 +457,10 @@ static int uli526x_open(struct net_device *dev)
        /* Initialize ULI526X board */
        uli526x_init(dev);
 
+       ret = request_irq(dev->irq, &uli526x_interrupt, IRQF_SHARED, dev->name, dev);
+       if (ret)
+               return ret;
+
        /* Active System Interface */
        netif_wake_queue(dev);
 
@@ -484,9 +487,11 @@ static void uli526x_init(struct net_device *dev)
        struct uli526x_board_info *db = netdev_priv(dev);
        unsigned long ioaddr = db->ioaddr;
        u8      phy_tmp;
+       u8      timeout;
        u16     phy_value;
        u16 phy_reg_reset;
 
+
        ULI526X_DBUG(0, "uli526x_init()", 0);
 
        /* Reset M526x MAC controller */
@@ -511,11 +516,19 @@ static void uli526x_init(struct net_device *dev)
        /* Parser SROM and media mode */
        db->media_mode = uli526x_media_mode;
 
-       /* Phyxcer capability setting */
+       /* phyxcer capability setting */
        phy_reg_reset = phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id);
        phy_reg_reset = (phy_reg_reset | 0x8000);
        phy_write(db->ioaddr, db->phy_addr, 0, phy_reg_reset, db->chip_id);
+
+       /* See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management
+        * functions") or phy data sheet for details on phy reset
+        */
        udelay(500);
+       timeout = 10;
+       while (timeout-- &&
+               phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id) & 0x8000)
+                       udelay(100);
 
        /* Process Phyxcer Media Mode */
        uli526x_set_phyxcer(db);
@@ -666,11 +679,6 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
        unsigned long ioaddr = dev->base_addr;
        unsigned long flags;
 
-       if (!dev) {
-               ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0);
-               return IRQ_NONE;
-       }
-
        spin_lock_irqsave(&db->lock, flags);
        outl(0, ioaddr + DCR7);
 
@@ -678,8 +686,9 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
        db->cr5_data = inl(ioaddr + DCR5);
        outl(db->cr5_data, ioaddr + DCR5);
        if ( !(db->cr5_data & 0x180c1) ) {
-               spin_unlock_irqrestore(&db->lock, flags);
+               /* Restore CR7 to enable interrupt mask */
                outl(db->cr7_data, ioaddr + DCR7);
+               spin_unlock_irqrestore(&db->lock, flags);
                return IRQ_HANDLED;
        }
 
@@ -712,6 +721,13 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void uli526x_poll(struct net_device *dev)
+{
+       /* ISR grabs the irqsave lock, so this should be safe */
+       uli526x_interrupt(dev->irq, dev);
+}
+#endif
 
 /*
  *     Free TX resource after TX complete
@@ -838,7 +854,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
 
                                skb->protocol = eth_type_trans(skb, dev);
                                netif_rx(skb);
-                               dev->last_rx = jiffies;
                                db->stats.rx_packets++;
                                db->stats.rx_bytes += rxlen;
 
@@ -875,7 +890,7 @@ static struct net_device_stats * uli526x_get_stats(struct net_device *dev)
 
 static void uli526x_set_filter_mode(struct net_device * dev)
 {
-       struct uli526x_board_info *db = dev->priv;
+       struct uli526x_board_info *db = netdev_priv(dev);
        unsigned long flags;
 
        ULI526X_DBUG(0, "uli526x_set_filter_mode()", 0);
@@ -1110,19 +1125,15 @@ static void uli526x_timer(unsigned long data)
 
 
 /*
- *     Dynamic reset the ULI526X board
  *     Stop ULI526X board
  *     Free Tx/Rx allocated memory
- *     Reset ULI526X board
- *     Re-initialize ULI526X board
+ *     Init system variable
  */
 
-static void uli526x_dynamic_reset(struct net_device *dev)
+static void uli526x_reset_prepare(struct net_device *dev)
 {
        struct uli526x_board_info *db = netdev_priv(dev);
 
-       ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
-
        /* Sopt MAC controller */
        db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */
        update_cr6(db->cr6_data, dev->base_addr);
@@ -1141,6 +1152,22 @@ static void uli526x_dynamic_reset(struct net_device *dev)
        db->link_failed = 1;
        db->init=1;
        db->wait_reset = 0;
+}
+
+
+/*
+ *     Dynamic reset the ULI526X board
+ *     Stop ULI526X board
+ *     Free Tx/Rx allocated memory
+ *     Reset ULI526X board
+ *     Re-initialize ULI526X board
+ */
+
+static void uli526x_dynamic_reset(struct net_device *dev)
+{
+       ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
+
+       uli526x_reset_prepare(dev);
 
        /* Re-initialize ULI526X board */
        uli526x_init(dev);
@@ -1150,6 +1177,88 @@ static void uli526x_dynamic_reset(struct net_device *dev)
 }
 
 
+#ifdef CONFIG_PM
+
+/*
+ *     Suspend the interface.
+ */
+
+static int uli526x_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       pci_power_t power_state;
+       int err;
+
+       ULI526X_DBUG(0, "uli526x_suspend", 0);
+
+       if (!netdev_priv(dev))
+               return 0;
+
+       pci_save_state(pdev);
+
+       if (!netif_running(dev))
+               return 0;
+
+       netif_device_detach(dev);
+       uli526x_reset_prepare(dev);
+
+       power_state = pci_choose_state(pdev, state);
+       pci_enable_wake(pdev, power_state, 0);
+       err = pci_set_power_state(pdev, power_state);
+       if (err) {
+               netif_device_attach(dev);
+               /* Re-initialize ULI526X board */
+               uli526x_init(dev);
+               /* Restart upper layer interface */
+               netif_wake_queue(dev);
+       }
+
+       return err;
+}
+
+/*
+ *     Resume the interface.
+ */
+
+static int uli526x_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       int err;
+
+       ULI526X_DBUG(0, "uli526x_resume", 0);
+
+       if (!netdev_priv(dev))
+               return 0;
+
+       pci_restore_state(pdev);
+
+       if (!netif_running(dev))
+               return 0;
+
+       err = pci_set_power_state(pdev, PCI_D0);
+       if (err) {
+               printk(KERN_WARNING "%s: Could not put device into D0\n",
+                       dev->name);
+               return err;
+       }
+
+       netif_device_attach(dev);
+       /* Re-initialize ULI526X board */
+       uli526x_init(dev);
+       /* Restart upper layer interface */
+       netif_wake_queue(dev);
+
+       return 0;
+}
+
+#else /* !CONFIG_PM */
+
+#define uli526x_suspend        NULL
+#define uli526x_resume NULL
+
+#endif /* !CONFIG_PM */
+
+
 /*
  *     free all allocated rx buffer
  */
@@ -1271,6 +1380,12 @@ static void update_cr6(u32 cr6_data, unsigned long ioaddr)
  *     This setup frame initialize ULI526X address filter mode
  */
 
+#ifdef __BIG_ENDIAN
+#define FLT_SHIFT 16
+#else
+#define FLT_SHIFT 0
+#endif
+
 static void send_filter_frame(struct net_device *dev, int mc_cnt)
 {
        struct uli526x_board_info *db = netdev_priv(dev);
@@ -1287,27 +1402,27 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
 
        /* Node address */
        addrptr = (u16 *) dev->dev_addr;
-       *suptr++ = addrptr[0];
-       *suptr++ = addrptr[1];
-       *suptr++ = addrptr[2];
+       *suptr++ = addrptr[0] << FLT_SHIFT;
+       *suptr++ = addrptr[1] << FLT_SHIFT;
+       *suptr++ = addrptr[2] << FLT_SHIFT;
 
        /* broadcast address */
-       *suptr++ = 0xffff;
-       *suptr++ = 0xffff;
-       *suptr++ = 0xffff;
+       *suptr++ = 0xffff << FLT_SHIFT;
+       *suptr++ = 0xffff << FLT_SHIFT;
+       *suptr++ = 0xffff << FLT_SHIFT;
 
        /* fit the multicast address */
        for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
                addrptr = (u16 *) mcptr->dmi_addr;
-               *suptr++ = addrptr[0];
-               *suptr++ = addrptr[1];
-               *suptr++ = addrptr[2];
+               *suptr++ = addrptr[0] << FLT_SHIFT;
+               *suptr++ = addrptr[1] << FLT_SHIFT;
+               *suptr++ = addrptr[2] << FLT_SHIFT;
        }
 
        for (; i<14; i++) {
-               *suptr++ = 0xffff;
-               *suptr++ = 0xffff;
-               *suptr++ = 0xffff;
+               *suptr++ = 0xffff << FLT_SHIFT;
+               *suptr++ = 0xffff << FLT_SHIFT;
+               *suptr++ = 0xffff << FLT_SHIFT;
        }
 
        /* prepare the setup frame */
@@ -1512,7 +1627,6 @@ static void uli526x_process_mode(struct uli526x_board_info *db)
                        case ULI526X_100MFD: phy_reg = 0x2100; break;
                        }
                        phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
-                               phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
                }
        }
 }
@@ -1689,6 +1803,8 @@ static struct pci_driver uli526x_driver = {
        .id_table       = uli526x_pci_tbl,
        .probe          = uli526x_init_one,
        .remove         = __devexit_p(uli526x_remove_one),
+       .suspend        = uli526x_suspend,
+       .resume         = uli526x_resume,
 };
 
 MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw");