Commit dc423b6b authored by David S. Miller's avatar David S. Miller

Merge branch 'ftgmac-rework-batch2-rx-path'

Benjamin Herrenschmidt says:

====================
ftgmac: Rework batch 2 - RX path

This is the second batch of updates to the ftgmac100 driver.

This one tackles the RX path of the driver, simplifying
it greatly to match common practice while significantly
increasing the performance.

(The bulk of the performance gains of my series will be
provided by the TX path improvements, notably fragmented
sends, these will be in the next batch).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bd414860 d930655d
...@@ -43,8 +43,8 @@ ...@@ -43,8 +43,8 @@
#define RX_QUEUE_ENTRIES 256 /* must be power of 2 */ #define RX_QUEUE_ENTRIES 256 /* must be power of 2 */
#define TX_QUEUE_ENTRIES 512 /* must be power of 2 */ #define TX_QUEUE_ENTRIES 512 /* must be power of 2 */
#define MAX_PKT_SIZE 1518 #define MAX_PKT_SIZE 1536
#define RX_BUF_SIZE PAGE_SIZE /* must be smaller than 0x3fff */ #define RX_BUF_SIZE MAX_PKT_SIZE /* must be smaller than 0x3fff */
struct ftgmac100_descs { struct ftgmac100_descs {
struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES]; struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
...@@ -60,7 +60,7 @@ struct ftgmac100 { ...@@ -60,7 +60,7 @@ struct ftgmac100 {
dma_addr_t descs_dma_addr; dma_addr_t descs_dma_addr;
/* Rx ring */ /* Rx ring */
struct page *rx_pages[RX_QUEUE_ENTRIES]; struct sk_buff *rx_skbs[RX_QUEUE_ENTRIES];
unsigned int rx_pointer; unsigned int rx_pointer;
u32 rxdes0_edorr_mask; u32 rxdes0_edorr_mask;
...@@ -71,6 +71,10 @@ struct ftgmac100 { ...@@ -71,6 +71,10 @@ struct ftgmac100 {
u32 txdes0_edotr_mask; u32 txdes0_edotr_mask;
spinlock_t tx_lock; spinlock_t tx_lock;
/* Scratch page to use when rx skb alloc fails */
void *rx_scratch;
dma_addr_t rx_scratch_dma;
/* Component structures */ /* Component structures */
struct net_device *netdev; struct net_device *netdev;
struct device *dev; struct device *dev;
...@@ -88,9 +92,6 @@ struct ftgmac100 { ...@@ -88,9 +92,6 @@ struct ftgmac100 {
bool need_mac_restart; bool need_mac_restart;
}; };
static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
struct ftgmac100_rxdes *rxdes, gfp_t gfp);
static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr) static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr)
{ {
iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR); iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR);
...@@ -277,128 +278,49 @@ static void ftgmac100_stop_hw(struct ftgmac100 *priv) ...@@ -277,128 +278,49 @@ static void ftgmac100_stop_hw(struct ftgmac100 *priv)
iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR); iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
} }
static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes *rxdes) static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
{ struct ftgmac100_rxdes *rxdes, gfp_t gfp)
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS);
}
static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS);
}
static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY);
}
static void ftgmac100_rxdes_set_dma_own(const struct ftgmac100 *priv,
struct ftgmac100_rxdes *rxdes)
{
/* clear status bits */
rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask);
}
static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ERR);
}
static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR);
}
static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL);
}
static bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT);
}
static bool ftgmac100_rxdes_odd_nibble(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB);
}
static unsigned int ftgmac100_rxdes_data_length(struct ftgmac100_rxdes *rxdes)
{
return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC;
}
static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes *rxdes)
{
return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_MULTICAST);
}
static void ftgmac100_rxdes_set_end_of_ring(const struct ftgmac100 *priv,
struct ftgmac100_rxdes *rxdes)
{
rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
}
static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes *rxdes,
dma_addr_t addr)
{
rxdes->rxdes3 = cpu_to_le32(addr);
}
static dma_addr_t ftgmac100_rxdes_get_dma_addr(struct ftgmac100_rxdes *rxdes)
{
return le32_to_cpu(rxdes->rxdes3);
}
static bool ftgmac100_rxdes_is_tcp(struct ftgmac100_rxdes *rxdes)
{ {
return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) == struct net_device *netdev = priv->netdev;
cpu_to_le32(FTGMAC100_RXDES1_PROT_TCPIP); struct sk_buff *skb;
} dma_addr_t map;
int err;
static bool ftgmac100_rxdes_is_udp(struct ftgmac100_rxdes *rxdes) skb = netdev_alloc_skb_ip_align(netdev, RX_BUF_SIZE);
{ if (unlikely(!skb)) {
return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) == if (net_ratelimit())
cpu_to_le32(FTGMAC100_RXDES1_PROT_UDPIP); netdev_warn(netdev, "failed to allocate rx skb\n");
} err = -ENOMEM;
map = priv->rx_scratch_dma;
} else {
map = dma_map_single(priv->dev, skb->data, RX_BUF_SIZE,
DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(priv->dev, map))) {
if (net_ratelimit())
netdev_err(netdev, "failed to map rx page\n");
dev_kfree_skb_any(skb);
map = priv->rx_scratch_dma;
skb = NULL;
err = -ENOMEM;
}
}
static bool ftgmac100_rxdes_tcpcs_err(struct ftgmac100_rxdes *rxdes) /* Store skb */
{ priv->rx_skbs[entry] = skb;
return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR);
}
static bool ftgmac100_rxdes_udpcs_err(struct ftgmac100_rxdes *rxdes) /* Store DMA address into RX desc */
{ rxdes->rxdes3 = cpu_to_le32(map);
return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_UDP_CHKSUM_ERR);
}
static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes *rxdes) /* Ensure the above is ordered vs clearing the OWN bit */
{ dma_wmb();
return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_IP_CHKSUM_ERR);
}
static inline struct page **ftgmac100_rxdes_page_slot(struct ftgmac100 *priv,
struct ftgmac100_rxdes *rxdes)
{
return &priv->rx_pages[rxdes - priv->descs->rxdes];
}
/* /* Clean status (which resets own bit) */
* rxdes2 is not used by hardware. We use it to keep track of page. if (entry == (RX_QUEUE_ENTRIES - 1))
* Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu(). rxdes->rxdes0 = cpu_to_le32(priv->rxdes0_edorr_mask);
*/ else
static void ftgmac100_rxdes_set_page(struct ftgmac100 *priv, rxdes->rxdes0 = 0;
struct ftgmac100_rxdes *rxdes,
struct page *page)
{
*ftgmac100_rxdes_page_slot(priv, rxdes) = page;
}
static struct page *ftgmac100_rxdes_get_page(struct ftgmac100 *priv, return 0;
struct ftgmac100_rxdes *rxdes)
{
return *ftgmac100_rxdes_page_slot(priv, rxdes);
} }
static int ftgmac100_next_rx_pointer(int pointer) static int ftgmac100_next_rx_pointer(int pointer)
...@@ -406,183 +328,143 @@ static int ftgmac100_next_rx_pointer(int pointer) ...@@ -406,183 +328,143 @@ static int ftgmac100_next_rx_pointer(int pointer)
return (pointer + 1) & (RX_QUEUE_ENTRIES - 1); return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
} }
static void ftgmac100_rx_pointer_advance(struct ftgmac100 *priv) static void ftgmac100_rx_packet_error(struct ftgmac100 *priv, u32 status)
{
priv->rx_pointer = ftgmac100_next_rx_pointer(priv->rx_pointer);
}
static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct ftgmac100 *priv)
{
return &priv->descs->rxdes[priv->rx_pointer];
}
static struct ftgmac100_rxdes *
ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv)
{
struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
while (ftgmac100_rxdes_packet_ready(rxdes)) {
if (ftgmac100_rxdes_first_segment(rxdes))
return rxdes;
ftgmac100_rxdes_set_dma_own(priv, rxdes);
ftgmac100_rx_pointer_advance(priv);
rxdes = ftgmac100_current_rxdes(priv);
}
return NULL;
}
static bool ftgmac100_rx_packet_error(struct ftgmac100 *priv,
struct ftgmac100_rxdes *rxdes)
{ {
struct net_device *netdev = priv->netdev; struct net_device *netdev = priv->netdev;
bool error = false;
if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) {
if (net_ratelimit())
netdev_info(netdev, "rx err\n");
if (status & FTGMAC100_RXDES0_RX_ERR)
netdev->stats.rx_errors++; netdev->stats.rx_errors++;
error = true;
}
if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) {
if (net_ratelimit())
netdev_info(netdev, "rx crc err\n");
if (status & FTGMAC100_RXDES0_CRC_ERR)
netdev->stats.rx_crc_errors++; netdev->stats.rx_crc_errors++;
error = true;
} else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) {
if (net_ratelimit())
netdev_info(netdev, "rx IP checksum err\n");
error = true;
}
if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) {
if (net_ratelimit())
netdev_info(netdev, "rx frame too long\n");
netdev->stats.rx_length_errors++;
error = true;
} else if (unlikely(ftgmac100_rxdes_runt(rxdes))) {
if (net_ratelimit())
netdev_info(netdev, "rx runt\n");
if (status & (FTGMAC100_RXDES0_FTL |
FTGMAC100_RXDES0_RUNT |
FTGMAC100_RXDES0_RX_ODD_NB))
netdev->stats.rx_length_errors++; netdev->stats.rx_length_errors++;
error = true;
} else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) {
if (net_ratelimit())
netdev_info(netdev, "rx odd nibble\n");
netdev->stats.rx_length_errors++;
error = true;
}
return error;
} }
static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv) static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
{ {
struct net_device *netdev = priv->netdev; struct net_device *netdev = priv->netdev;
struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv); struct ftgmac100_rxdes *rxdes;
bool done = false; struct sk_buff *skb;
unsigned int pointer, size;
u32 status, csum_vlan;
dma_addr_t map;
if (net_ratelimit()) /* Grab next RX descriptor */
netdev_dbg(netdev, "drop packet %p\n", rxdes); pointer = priv->rx_pointer;
rxdes = &priv->descs->rxdes[pointer];
do { /* Grab descriptor status */
if (ftgmac100_rxdes_last_segment(rxdes)) status = le32_to_cpu(rxdes->rxdes0);
done = true;
ftgmac100_rxdes_set_dma_own(priv, rxdes); /* Do we have a packet ? */
ftgmac100_rx_pointer_advance(priv); if (!(status & FTGMAC100_RXDES0_RXPKT_RDY))
rxdes = ftgmac100_current_rxdes(priv); return false;
} while (!done && ftgmac100_rxdes_packet_ready(rxdes));
netdev->stats.rx_dropped++; /* Order subsequent reads with the test for the ready bit */
} dma_rmb();
static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) /* We don't cope with fragmented RX packets */
{ if (unlikely(!(status & FTGMAC100_RXDES0_FRS) ||
struct net_device *netdev = priv->netdev; !(status & FTGMAC100_RXDES0_LRS)))
struct ftgmac100_rxdes *rxdes; goto drop;
struct sk_buff *skb;
bool done = false;
rxdes = ftgmac100_rx_locate_first_segment(priv); /* Grab received size and csum vlan field in the descriptor */
if (!rxdes) size = status & FTGMAC100_RXDES0_VDBC;
return false; csum_vlan = le32_to_cpu(rxdes->rxdes1);
if (unlikely(ftgmac100_rx_packet_error(priv, rxdes))) { /* Any error (other than csum offload) flagged ? */
ftgmac100_rx_drop_packet(priv); if (unlikely(status & RXDES0_ANY_ERROR)) {
return true; /* Correct for incorrect flagging of runt packets
* with vlan tags... Just accept a runt packet that
* has been flagged as vlan and whose size is at
* least 60 bytes.
*/
if ((status & FTGMAC100_RXDES0_RUNT) &&
(csum_vlan & FTGMAC100_RXDES1_VLANTAG_AVAIL) &&
(size >= 60))
status &= ~FTGMAC100_RXDES0_RUNT;
/* Any error still in there ? */
if (status & RXDES0_ANY_ERROR) {
ftgmac100_rx_packet_error(priv, status);
goto drop;
}
} }
/* start processing */ /* If the packet had no skb (failed to allocate earlier)
skb = netdev_alloc_skb_ip_align(netdev, 128); * then try to allocate one and skip
if (unlikely(!skb)) { */
if (net_ratelimit()) skb = priv->rx_skbs[pointer];
netdev_err(netdev, "rx skb alloc failed\n"); if (!unlikely(skb)) {
ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
ftgmac100_rx_drop_packet(priv); goto drop;
return true;
} }
if (unlikely(ftgmac100_rxdes_multicast(rxdes))) if (unlikely(status & FTGMAC100_RXDES0_MULTICAST))
netdev->stats.multicast++; netdev->stats.multicast++;
/* /* If the HW found checksum errors, bounce it to software.
* It seems that HW does checksum incorrectly with fragmented packets, *
* so we are conservative here - if HW checksum error, let software do * If we didn't, we need to see if the packet was recognized
* the checksum again. * by HW as one of the supported checksummed protocols before
* we accept the HW test results.
*/ */
if ((ftgmac100_rxdes_is_tcp(rxdes) && !ftgmac100_rxdes_tcpcs_err(rxdes)) || if (netdev->features & NETIF_F_RXCSUM) {
(ftgmac100_rxdes_is_udp(rxdes) && !ftgmac100_rxdes_udpcs_err(rxdes))) u32 err_bits = FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
FTGMAC100_RXDES1_IP_CHKSUM_ERR;
if ((csum_vlan & err_bits) ||
!(csum_vlan & FTGMAC100_RXDES1_PROT_MASK))
skb->ip_summed = CHECKSUM_NONE;
else
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
}
do { /* Transfer received size to skb */
dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes); skb_put(skb, size);
struct page *page = ftgmac100_rxdes_get_page(priv, rxdes);
unsigned int size;
dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
size = ftgmac100_rxdes_data_length(rxdes);
skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, size);
skb->len += size; /* Tear down DMA mapping, do necessary cache management */
skb->data_len += size; map = le32_to_cpu(rxdes->rxdes3);
skb->truesize += PAGE_SIZE;
if (ftgmac100_rxdes_last_segment(rxdes)) #if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU)
done = true; /* When we don't have an iommu, we can save cycles by not
* invalidating the cache for the part of the packet that
* wasn't received.
*/
dma_unmap_single(priv->dev, map, size, DMA_FROM_DEVICE);
#else
dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
#endif
ftgmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
ftgmac100_rx_pointer_advance(priv); /* Resplenish rx ring */
rxdes = ftgmac100_current_rxdes(priv); ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
} while (!done); priv->rx_pointer = ftgmac100_next_rx_pointer(pointer);
/* Small frames are copied into linear part of skb to free one page */
if (skb->len <= 128) {
skb->truesize -= PAGE_SIZE;
__pskb_pull_tail(skb, skb->len);
} else {
/* We pull the minimum amount into linear part */
__pskb_pull_tail(skb, ETH_HLEN);
}
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
netdev->stats.rx_packets++; netdev->stats.rx_packets++;
netdev->stats.rx_bytes += skb->len; netdev->stats.rx_bytes += size;
/* push packet to protocol stack */ /* push packet to protocol stack */
if (skb->ip_summed == CHECKSUM_NONE)
netif_receive_skb(skb);
else
napi_gro_receive(&priv->napi, skb); napi_gro_receive(&priv->napi, skb);
(*processed)++; (*processed)++;
return true; return true;
drop:
/* Clean rxdes0 (which resets own bit) */
rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask);
priv->rx_pointer = ftgmac100_next_rx_pointer(pointer);
netdev->stats.rx_dropped++;
return true;
} }
static void ftgmac100_txdes_reset(const struct ftgmac100 *priv, static void ftgmac100_txdes_reset(const struct ftgmac100 *priv,
...@@ -793,34 +675,6 @@ static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb, ...@@ -793,34 +675,6 @@ static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
struct ftgmac100_rxdes *rxdes, gfp_t gfp)
{
struct net_device *netdev = priv->netdev;
struct page *page;
dma_addr_t map;
page = alloc_page(gfp);
if (!page) {
if (net_ratelimit())
netdev_err(netdev, "failed to allocate rx page\n");
return -ENOMEM;
}
map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(priv->dev, map))) {
if (net_ratelimit())
netdev_err(netdev, "failed to map rx page\n");
__free_page(page);
return -ENOMEM;
}
ftgmac100_rxdes_set_page(priv, rxdes, page);
ftgmac100_rxdes_set_dma_addr(rxdes, map);
ftgmac100_rxdes_set_dma_own(priv, rxdes);
return 0;
}
static void ftgmac100_free_buffers(struct ftgmac100 *priv) static void ftgmac100_free_buffers(struct ftgmac100 *priv)
{ {
int i; int i;
...@@ -828,14 +682,15 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv) ...@@ -828,14 +682,15 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv)
/* Free all RX buffers */ /* Free all RX buffers */
for (i = 0; i < RX_QUEUE_ENTRIES; i++) { for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i]; struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
struct page *page = ftgmac100_rxdes_get_page(priv, rxdes); struct sk_buff *skb = priv->rx_skbs[i];
dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes); dma_addr_t map = le32_to_cpu(rxdes->rxdes3);
if (!page) if (!skb)
continue; continue;
dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE); priv->rx_skbs[i] = NULL;
__free_page(page); dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
} }
/* Free all TX buffers */ /* Free all TX buffers */
...@@ -858,6 +713,11 @@ static void ftgmac100_free_rings(struct ftgmac100 *priv) ...@@ -858,6 +713,11 @@ static void ftgmac100_free_rings(struct ftgmac100 *priv)
if (priv->descs) if (priv->descs)
dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs), dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs),
priv->descs, priv->descs_dma_addr); priv->descs, priv->descs_dma_addr);
/* Free scratch packet buffer */
if (priv->rx_scratch)
dma_free_coherent(priv->dev, RX_BUF_SIZE,
priv->rx_scratch, priv->rx_scratch_dma);
} }
static int ftgmac100_alloc_rings(struct ftgmac100 *priv) static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
...@@ -869,17 +729,30 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv) ...@@ -869,17 +729,30 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
if (!priv->descs) if (!priv->descs)
return -ENOMEM; return -ENOMEM;
/* Allocate scratch packet buffer */
priv->rx_scratch = dma_alloc_coherent(priv->dev,
RX_BUF_SIZE,
&priv->rx_scratch_dma,
GFP_KERNEL);
if (!priv->rx_scratch)
return -ENOMEM;
return 0; return 0;
} }
static void ftgmac100_init_rings(struct ftgmac100 *priv) static void ftgmac100_init_rings(struct ftgmac100 *priv)
{ {
struct ftgmac100_rxdes *rxdes;
int i; int i;
/* Initialize RX ring */ /* Initialize RX ring */
for (i = 0; i < RX_QUEUE_ENTRIES; i++) for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
priv->descs->rxdes[i].rxdes0 = 0; rxdes = &priv->descs->rxdes[i];
ftgmac100_rxdes_set_end_of_ring(priv, &priv->descs->rxdes[i - 1]); rxdes->rxdes0 = 0;
rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma);
}
/* Mark the end of the ring */
rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
/* Initialize TX ring */ /* Initialize TX ring */
for (i = 0; i < TX_QUEUE_ENTRIES; i++) for (i = 0; i < TX_QUEUE_ENTRIES; i++)
...@@ -894,7 +767,7 @@ static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv) ...@@ -894,7 +767,7 @@ static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
for (i = 0; i < RX_QUEUE_ENTRIES; i++) { for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i]; struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
if (ftgmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL)) if (ftgmac100_alloc_rx_buf(priv, i, rxdes, GFP_KERNEL))
return -ENOMEM; return -ENOMEM;
} }
return 0; return 0;
...@@ -1095,6 +968,14 @@ static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id) ...@@ -1095,6 +968,14 @@ static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static bool ftgmac100_check_rx(struct ftgmac100 *priv)
{
struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[priv->rx_pointer];
/* Do we have a packet ? */
return !!(rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY));
}
static int ftgmac100_poll(struct napi_struct *napi, int budget) static int ftgmac100_poll(struct napi_struct *napi, int budget)
{ {
struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi); struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi);
...@@ -1134,8 +1015,7 @@ static int ftgmac100_poll(struct napi_struct *napi, int budget) ...@@ -1134,8 +1015,7 @@ static int ftgmac100_poll(struct napi_struct *napi, int budget)
*/ */
iowrite32(FTGMAC100_INT_RXTX, iowrite32(FTGMAC100_INT_RXTX,
priv->base + FTGMAC100_OFFSET_ISR); priv->base + FTGMAC100_OFFSET_ISR);
if (ftgmac100_rxdes_packet_ready if (ftgmac100_check_rx(priv) || priv->tx_pending)
(ftgmac100_current_rxdes(priv)) || priv->tx_pending)
return budget; return budget;
/* deschedule NAPI */ /* deschedule NAPI */
...@@ -1545,7 +1425,7 @@ static int ftgmac100_probe(struct platform_device *pdev) ...@@ -1545,7 +1425,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
* when NCSI is enabled on the interface. It doesn't work * when NCSI is enabled on the interface. It doesn't work
* in that case. * in that case.
*/ */
netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO; netdev->features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_GRO;
if (priv->use_ncsi && if (priv->use_ncsi &&
of_get_property(pdev->dev.of_node, "no-hw-checksum", NULL)) of_get_property(pdev->dev.of_node, "no-hw-checksum", NULL))
netdev->features &= ~NETIF_F_IP_CSUM; netdev->features &= ~NETIF_F_IP_CSUM;
......
...@@ -227,10 +227,10 @@ struct ftgmac100_txdes { ...@@ -227,10 +227,10 @@ struct ftgmac100_txdes {
* Receive descriptor, aligned to 16 bytes * Receive descriptor, aligned to 16 bytes
*/ */
struct ftgmac100_rxdes { struct ftgmac100_rxdes {
unsigned int rxdes0; __le32 rxdes0; /* Control & status bits */
unsigned int rxdes1; __le32 rxdes1; /* Checksum and vlan status */
unsigned int rxdes2; /* not used by HW */ __le32 rxdes2; /* length/type on AST2500 */
unsigned int rxdes3; /* RXBUF_BADR */ __le32 rxdes3; /* DMA buffer address */
} __attribute__ ((aligned(16))); } __attribute__ ((aligned(16)));
#define FTGMAC100_RXDES0_VDBC 0x3fff #define FTGMAC100_RXDES0_VDBC 0x3fff
...@@ -248,6 +248,14 @@ struct ftgmac100_rxdes { ...@@ -248,6 +248,14 @@ struct ftgmac100_rxdes {
#define FTGMAC100_RXDES0_FRS (1 << 29) #define FTGMAC100_RXDES0_FRS (1 << 29)
#define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31) #define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31)
/* Errors we care about for dropping packets */
#define RXDES0_ANY_ERROR ( \
FTGMAC100_RXDES0_RX_ERR | \
FTGMAC100_RXDES0_CRC_ERR | \
FTGMAC100_RXDES0_FTL | \
FTGMAC100_RXDES0_RUNT | \
FTGMAC100_RXDES0_RX_ODD_NB)
#define FTGMAC100_RXDES1_VLANTAG_CI 0xffff #define FTGMAC100_RXDES1_VLANTAG_CI 0xffff
#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20) #define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20)
#define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20) #define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment