[PATCH] Add adm8211 802.11b wireless driver
[pandora-kernel.git] / drivers / net / gianfar.c
index 6822bf1..bd2de32 100644 (file)
@@ -130,8 +130,11 @@ static int gfar_remove(struct platform_device *pdev);
 static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
+static void gfar_configure_serdes(struct net_device *dev);
+extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
+extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
 #ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget);
+static int gfar_poll(struct napi_struct *napi, int budget);
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void gfar_netpoll(struct net_device *dev);
@@ -185,6 +188,7 @@ static int gfar_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv = netdev_priv(dev);
+       priv->dev = dev;
 
        /* Set the info in the priv to the current info */
        priv->einfo = einfo;
@@ -258,10 +262,7 @@ static int gfar_probe(struct platform_device *pdev)
        dev->hard_start_xmit = gfar_start_xmit;
        dev->tx_timeout = gfar_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_GFAR_NAPI
-       dev->poll = gfar_poll;
-       dev->weight = GFAR_DEV_WEIGHT;
-#endif
+       netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = gfar_netpoll;
 #endif
@@ -417,8 +418,18 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)
        if (ecntrl & ECNTRL_REDUCED_MODE) {
                if (ecntrl & ECNTRL_REDUCED_MII_MODE)
                        return PHY_INTERFACE_MODE_RMII;
-               else
+               else {
+                       phy_interface_t interface = priv->einfo->interface;
+
+                       /*
+                        * This isn't autodetected right now, so it must
+                        * be set by the device tree or platform code.
+                        */
+                       if (interface == PHY_INTERFACE_MODE_RGMII_ID)
+                               return PHY_INTERFACE_MODE_RGMII_ID;
+
                        return PHY_INTERFACE_MODE_RGMII;
+               }
        }
 
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
@@ -451,6 +462,9 @@ static int init_phy(struct net_device *dev)
 
        phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface);
 
+       if (interface == PHY_INTERFACE_MODE_SGMII)
+               gfar_configure_serdes(dev);
+
        if (IS_ERR(phydev)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
                return PTR_ERR(phydev);
@@ -465,6 +479,27 @@ static int init_phy(struct net_device *dev)
        return 0;
 }
 
+static void gfar_configure_serdes(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       struct gfar_mii __iomem *regs =
+                       (void __iomem *)&priv->regs->gfar_mii_regs;
+
+       /* Initialise TBI i/f to communicate with serdes (lynx phy) */
+
+       /* Single clk mode, mii mode off(for aerdes communication) */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
+
+       /* Supported pause and full-duplex, no half-duplex */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+                       ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
+                       ADVERTISE_1000XPSE_ASYM);
+
+       /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
+       gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+                       BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
+}
+
 static void init_registers(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
@@ -902,6 +937,8 @@ static int gfar_enet_open(struct net_device *dev)
 {
        int err;
 
+       napi_enable(&priv->napi);
+
        /* Initialize a bunch of registers */
        init_registers(dev);
 
@@ -909,10 +946,14 @@ static int gfar_enet_open(struct net_device *dev)
 
        err = init_phy(dev);
 
-       if(err)
+       if(err) {
+               napi_disable(&priv->napi);
                return err;
+       }
 
        err = startup_gfar(dev);
+       if (err)
+               napi_disable(&priv->napi);
 
        netif_start_queue(dev);
 
@@ -944,7 +985,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
                flags |= TXFCB_UDP;
                fcb->phcs = udp_hdr(skb)->check;
        } else
-               fcb->phcs = udp_hdr(skb)->check;
+               fcb->phcs = tcp_hdr(skb)->check;
 
        /* l3os is the distance between the start of the
         * frame (skb->data) and the start of the IP hdr.
@@ -1065,6 +1106,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static int gfar_close(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
+
+       napi_disable(&priv->napi);
+
        stop_gfar(dev);
 
        /* Disconnect from the PHY */
@@ -1281,7 +1325,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
                return NULL;
 
        alignamount = RXBUF_ALIGNMENT -
-               (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1));
+               (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1));
 
        /* We need the data buffer to be aligned properly.  We will reserve
         * as many bytes as needed to align the data properly
@@ -1353,12 +1397,12 @@ irqreturn_t gfar_receive(int irq, void *dev_id)
 
        /* support NAPI */
 #ifdef CONFIG_GFAR_NAPI
-       if (netif_rx_schedule_prep(dev)) {
+       if (netif_rx_schedule_prep(dev, &priv->napi)) {
                tempval = gfar_read(&priv->regs->imask);
                tempval &= IMASK_RX_DISABLED;
                gfar_write(&priv->regs->imask, tempval);
 
-               __netif_rx_schedule(dev);
+               __netif_rx_schedule(dev, &priv->napi);
        } else {
                if (netif_msg_rx_err(priv))
                        printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
@@ -1532,23 +1576,16 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 }
 
 #ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget)
+static int gfar_poll(struct napi_struct *napi, int budget)
 {
+       struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
+       struct net_device *dev = priv->dev;
        int howmany;
-       struct gfar_private *priv = netdev_priv(dev);
-       int rx_work_limit = *budget;
 
-       if (rx_work_limit > dev->quota)
-               rx_work_limit = dev->quota;
+       howmany = gfar_clean_rx_ring(dev, budget);
 
-       howmany = gfar_clean_rx_ring(dev, rx_work_limit);
-
-       dev->quota -= howmany;
-       rx_work_limit -= howmany;
-       *budget -= howmany;
-
-       if (rx_work_limit > 0) {
-               netif_rx_complete(dev);
+       if (howmany < budget) {
+               netif_rx_complete(dev, napi);
 
                /* Clear the halt bit in RSTAT */
                gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
@@ -1564,8 +1601,7 @@ static int gfar_poll(struct net_device *dev, int *budget)
                        gfar_write(&priv->regs->rxic, 0);
        }
 
-       /* Return 1 if there's more work to do */
-       return (rx_work_limit > 0) ? 0 : 1;
+       return howmany;
 }
 #endif