Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfashe...
[pandora-kernel.git] / drivers / net / bfin_mac.c
index a8ec60e..3db7db1 100644 (file)
@@ -605,36 +605,87 @@ adjust_head:
 static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
                                struct net_device *dev)
 {
-       unsigned int data;
+       u16 *data;
 
        current_tx_ptr->skb = skb;
 
-       /*
-        * Is skb->data always 16-bit aligned?
-        * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)?
-        */
-       if ((((unsigned int)(skb->data)) & 0x02) == 2) {
-               /* move skb->data to current_tx_ptr payload */
-               data = (unsigned int)(skb->data) - 2;
-               *((unsigned short *)data) = (unsigned short)(skb->len);
-               current_tx_ptr->desc_a.start_addr = (unsigned long)data;
-               /* this is important! */
-               blackfin_dcache_flush_range(data, (data + (skb->len)) + 2);
-
+       if (ANOMALY_05000285) {
+               /*
+                * TXDWA feature is not avaible to older revision < 0.3 silicon
+                * of BF537
+                *
+                * Only if data buffer is ODD WORD alignment, we do not
+                * need to memcpy
+                */
+               u32 data_align = (u32)(skb->data) & 0x3;
+               if (data_align == 0x2) {
+                       /* move skb->data to current_tx_ptr payload */
+                       data = (u16 *)(skb->data) - 1;
+                       *data = (u16)(skb->len);
+                       current_tx_ptr->desc_a.start_addr = (u32)data;
+                       /* this is important! */
+                       blackfin_dcache_flush_range((u32)data,
+                                       (u32)((u8 *)data + skb->len + 4));
+               } else {
+                       *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
+                       memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
+                               skb->len);
+                       current_tx_ptr->desc_a.start_addr =
+                               (u32)current_tx_ptr->packet;
+                       if (current_tx_ptr->status.status_word != 0)
+                               current_tx_ptr->status.status_word = 0;
+                       blackfin_dcache_flush_range(
+                               (u32)current_tx_ptr->packet,
+                               (u32)(current_tx_ptr->packet + skb->len + 2));
+               }
        } else {
-               *((unsigned short *)(current_tx_ptr->packet)) =
-                   (unsigned short)(skb->len);
-               memcpy((char *)(current_tx_ptr->packet + 2), skb->data,
-                      (skb->len));
-               current_tx_ptr->desc_a.start_addr =
-                   (unsigned long)current_tx_ptr->packet;
-               if (current_tx_ptr->status.status_word != 0)
-                       current_tx_ptr->status.status_word = 0;
-               blackfin_dcache_flush_range((unsigned int)current_tx_ptr->
-                                           packet,
-                                           (unsigned int)(current_tx_ptr->
-                                                          packet + skb->len) +
-                                           2);
+               /*
+                * TXDWA feature is avaible to revision < 0.3 silicon of
+                * BF537 and always avaible to BF52x
+                */
+               u32 data_align = (u32)(skb->data) & 0x3;
+               if (data_align == 0x0) {
+                       u16 sysctl = bfin_read_EMAC_SYSCTL();
+                       sysctl |= TXDWA;
+                       bfin_write_EMAC_SYSCTL(sysctl);
+
+                       /* move skb->data to current_tx_ptr payload */
+                       data = (u16 *)(skb->data) - 2;
+                       *data = (u16)(skb->len);
+                       current_tx_ptr->desc_a.start_addr = (u32)data;
+                       /* this is important! */
+                       blackfin_dcache_flush_range(
+                                       (u32)data,
+                                       (u32)((u8 *)data + skb->len + 4));
+               } else if (data_align == 0x2) {
+                       u16 sysctl = bfin_read_EMAC_SYSCTL();
+                       sysctl &= ~TXDWA;
+                       bfin_write_EMAC_SYSCTL(sysctl);
+
+                       /* move skb->data to current_tx_ptr payload */
+                       data = (u16 *)(skb->data) - 1;
+                       *data = (u16)(skb->len);
+                       current_tx_ptr->desc_a.start_addr = (u32)data;
+                       /* this is important! */
+                       blackfin_dcache_flush_range(
+                                       (u32)data,
+                                       (u32)((u8 *)data + skb->len + 4));
+               } else {
+                       u16 sysctl = bfin_read_EMAC_SYSCTL();
+                       sysctl &= ~TXDWA;
+                       bfin_write_EMAC_SYSCTL(sysctl);
+
+                       *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
+                       memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
+                               skb->len);
+                       current_tx_ptr->desc_a.start_addr =
+                               (u32)current_tx_ptr->packet;
+                       if (current_tx_ptr->status.status_word != 0)
+                               current_tx_ptr->status.status_word = 0;
+                       blackfin_dcache_flush_range(
+                               (u32)current_tx_ptr->packet,
+                               (u32)(current_tx_ptr->packet + skb->len + 2));
+               }
        }
 
        /* enable this packet's dma */
@@ -691,7 +742,6 @@ static void bfin_mac_rx(struct net_device *dev)
                                         (unsigned long)skb->tail);
 
        dev->last_rx = jiffies;
-       skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
 #if defined(BFIN_MAC_CSUM_OFFLOAD)
        skb->csum = current_rx_ptr->status.ip_payload_csum;
@@ -920,6 +970,7 @@ static int bfin_mac_open(struct net_device *dev)
        phy_start(lp->phydev);
        phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
        setup_system_regs(dev);
+       setup_mac_addr(dev->dev_addr);
        bfin_mac_disable();
        bfin_mac_enable();
        pr_debug("hardware init finished\n");
@@ -955,7 +1006,7 @@ static int bfin_mac_close(struct net_device *dev)
        return 0;
 }
 
-static int __init bfin_mac_probe(struct platform_device *pdev)
+static int __devinit bfin_mac_probe(struct platform_device *pdev)
 {
        struct net_device *ndev;
        struct bfin_mac_local *lp;
@@ -1081,7 +1132,7 @@ out_err_probe_mac:
        return rc;
 }
 
-static int bfin_mac_remove(struct platform_device *pdev)
+static int __devexit bfin_mac_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct bfin_mac_local *lp = netdev_priv(ndev);
@@ -1128,7 +1179,7 @@ static int bfin_mac_resume(struct platform_device *pdev)
 
 static struct platform_driver bfin_mac_driver = {
        .probe = bfin_mac_probe,
-       .remove = bfin_mac_remove,
+       .remove = __devexit_p(bfin_mac_remove),
        .resume = bfin_mac_resume,
        .suspend = bfin_mac_suspend,
        .driver = {