Changeset 20892


Ignore:
Timestamp:
2010-04-16T01:31:17+02:00 (8 years ago)
Author:
nbd
Message:

ar71xx: fix up alignment handling

  • on ar724x, rx buffers can be aligned with an offset of 2, which keeps the ip header aligned
  • alignment offset is only added if the ar8216 workaround is not active and the phy driver does not advertise its own packet alignment
  • ar71xx and ar91xx can not handle rx alignment offsets, however taking a hit on unaligned exceptions seems to have less overhead than re-aligning the data for large packets
  • use memmove to re-align small packets, if necessary

tested on ar9132, ar7240 and ar7242 based devices without ar8216 headers

Location:
trunk/target/linux/ar71xx/files/drivers/net/ag71xx
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar8216.c

    r20673 r20892  
    4040        } 
    4141 
    42         skb_put(skb, pktlen); 
    4342        skb_pull(skb, AR8216_HEADER_LEN); 
    4443        return 0; 
  • trunk/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c

    r20751 r20892  
    193193} 
    194194 
     195static int ag71xx_rx_reserve(struct ag71xx *ag) 
     196{ 
     197        int reserve = 0; 
     198 
     199        if (ag71xx_get_pdata(ag)->is_ar724x) { 
     200                if (!ag71xx_has_ar8216(ag)) 
     201                        reserve = 2; 
     202 
     203                if (ag->phy_dev) 
     204                        reserve += 4 - (ag->phy_dev->pkt_align % 4); 
     205 
     206                reserve %= 4; 
     207        } 
     208 
     209        return reserve + AG71XX_RX_PKT_RESERVE; 
     210} 
     211 
     212 
    195213static int ag71xx_ring_rx_init(struct ag71xx *ag) 
    196214{ 
    197215        struct ag71xx_ring *ring = &ag->rx_ring; 
     216        unsigned int reserve = ag71xx_rx_reserve(ag); 
    198217        unsigned int i; 
    199218        int ret; 
     
    213232                dma_addr_t dma_addr; 
    214233 
    215                 skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + AG71XX_RX_PKT_RESERVE); 
     234                skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve); 
    216235                if (!skb) { 
    217236                        ret = -ENOMEM; 
     
    220239 
    221240                skb->dev = ag->dev; 
    222                 skb_reserve(skb, AG71XX_RX_PKT_RESERVE); 
     241                skb_reserve(skb, reserve); 
    223242 
    224243                dma_addr = dma_map_single(&ag->dev->dev, skb->data, 
     
    243262{ 
    244263        struct ag71xx_ring *ring = &ag->rx_ring; 
     264        unsigned int reserve = ag71xx_rx_reserve(ag); 
    245265        unsigned int count; 
    246266 
     
    255275                        struct sk_buff *skb; 
    256276 
    257                         skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + 
    258                                             AG71XX_RX_PKT_RESERVE); 
     277                        skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve); 
    259278                        if (skb == NULL) 
    260279                                break; 
    261280 
    262                         skb_reserve(skb, AG71XX_RX_PKT_RESERVE); 
     281                        skb_reserve(skb, reserve); 
    263282                        skb->dev = ag->dev; 
    264283 
     
    760779} 
    761780 
    762 static int ag71xx_rx_copy_skb(struct ag71xx *ag, struct sk_buff **pskb, 
    763                               int pktlen) 
    764 { 
    765         struct sk_buff *copy_skb; 
    766  
    767         if (ag->phy_dev && (ag->phy_dev->pkt_align % 4) == 2) 
    768                 goto keep; 
    769  
    770         copy_skb = netdev_alloc_skb(ag->dev, pktlen + NET_IP_ALIGN); 
    771         if (!copy_skb) 
    772                 return -ENOMEM; 
    773  
    774         skb_reserve(copy_skb, NET_IP_ALIGN); 
    775         skb_copy_from_linear_data(*pskb, copy_skb->data, pktlen); 
    776         skb_put(copy_skb, pktlen); 
    777  
    778         dev_kfree_skb_any(*pskb); 
    779         *pskb = copy_skb; 
    780  
    781         return 0; 
    782  
    783  keep: 
    784         skb_put(*pskb, pktlen); 
    785         return 0; 
     781static void ag71xx_rx_align_skb(struct ag71xx *ag, struct sk_buff *skb, int len) 
     782{ 
     783        int offset = ((unsigned long) skb->data) % 4; 
     784        void *data; 
     785 
     786        if (offset == 2) 
     787                return; 
     788 
     789        if (ag->phy_dev && ag->phy_dev->pkt_align != 0) 
     790                return; 
     791 
     792        if (len > 128) 
     793                return; 
     794 
     795        if (WARN_ON(skb_headroom(skb) < 2)) 
     796                return; 
     797 
     798        data = skb->data; 
     799        skb->data -= 2; 
     800        memmove(skb->data, data, len); 
    786801} 
    787802 
     
    823838                dev->stats.rx_bytes += pktlen; 
    824839 
     840                skb_put(skb, pktlen); 
    825841                if (ag71xx_has_ar8216(ag)) 
    826842                        err = ag71xx_remove_ar8216_header(ag, skb, pktlen); 
    827                 else 
    828                         err = ag71xx_rx_copy_skb(ag, &skb, pktlen); 
     843 
     844                ag71xx_rx_align_skb(ag, skb, pktlen); 
    829845 
    830846                if (err) { 
Note: See TracChangeset for help on using the changeset viewer.