]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/gianfar.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/avi/kvm
[linux-2.6-omap-h63xx.git] / drivers / net / gianfar.c
index d981d4c41dd3b1ef6faa49fcdcf21bc4bc88c9c0..d7a1a58de7669b3bfefbf062ccb0fd8d98ec60b9 100644 (file)
@@ -130,6 +130,9 @@ 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);
 #endif
@@ -140,7 +143,6 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
 static void gfar_vlan_rx_register(struct net_device *netdev,
                                struct vlan_group *grp);
-static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 void gfar_halt(struct net_device *dev);
 void gfar_start(struct net_device *dev);
 static void gfar_clear_exact_match(struct net_device *dev);
@@ -284,7 +286,6 @@ static int gfar_probe(struct platform_device *pdev)
 
        if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
                dev->vlan_rx_register = gfar_vlan_rx_register;
-               dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
 
                dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 
@@ -453,6 +454,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);
@@ -467,6 +471,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);
@@ -942,18 +967,18 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
 
        /* Tell the controller what the protocol is */
        /* And provide the already calculated phcs */
-       if (skb->nh.iph->protocol == IPPROTO_UDP) {
+       if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
                flags |= TXFCB_UDP;
-               fcb->phcs = skb->h.uh->check;
+               fcb->phcs = udp_hdr(skb)->check;
        } else
-               fcb->phcs = skb->h.th->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.
         * l4os is the distance between the start of the
         * l3 hdr and the l4 hdr */
-       fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
-       fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+       fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN);
+       fcb->l4os = skb_network_header_len(skb);
 
        fcb->flags = flags;
 }
@@ -1025,6 +1050,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
+       /* The powerpc-specific eieio() is used, as wmb() has too strong
+        * semantics (it requires synchronization between cacheable and
+        * uncacheable mappings, which eieio doesn't provide and which we
+        * don't need), thus requiring a more expensive sync instruction.  At
+        * some point, the set of architecture-independent barrier functions
+        * should be expanded to include weaker barriers.
+        */
+
+       eieio();
        txbdp->status = status;
 
        /* If this was the last BD in the ring, the next one */
@@ -1124,20 +1158,6 @@ static void gfar_vlan_rx_register(struct net_device *dev,
        spin_unlock_irqrestore(&priv->rxlock, flags);
 }
 
-
-static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
-{
-       struct gfar_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->rxlock, flags);
-
-       vlan_group_set_device(priv->vlgrp, vid, NULL);
-
-       spin_unlock_irqrestore(&priv->rxlock, flags);
-}
-
-
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
        int tempsize, tempval;
@@ -1295,14 +1315,13 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
         */
        skb_reserve(skb, alignamount);
 
-       skb->dev = dev;
-
        bdp->bufPtr = dma_map_single(NULL, skb->data,
                        priv->rx_buffer_size, DMA_FROM_DEVICE);
 
        bdp->length = 0;
 
        /* Mark the buffer empty */
+       eieio();
        bdp->status |= (RXBD_EMPTY | RXBD_INTERRUPT);
 
        return skb;
@@ -1486,6 +1505,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
        bdp = priv->cur_rx;
 
        while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
+               rmb();
                skb = priv->rx_skbuff[priv->skb_currx];
 
                if (!(bdp->status &