|
@@ -468,77 +468,13 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes *txdes)
|
|
|
+static u32 ftgmac100_base_tx_ctlstat(struct ftgmac100 *priv,
|
|
|
+ unsigned int index)
|
|
|
{
|
|
|
- return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_end_of_ring(const struct ftgmac100 *priv,
|
|
|
- struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_first_segment(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS);
|
|
|
-}
|
|
|
-
|
|
|
-static inline bool ftgmac100_txdes_get_first_segment(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- return (txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_FTS)) != 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_last_segment(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS);
|
|
|
-}
|
|
|
-
|
|
|
-static inline bool ftgmac100_txdes_get_last_segment(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- return (txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_LTS)) != 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_buffer_size(struct ftgmac100_txdes *txdes,
|
|
|
- unsigned int len)
|
|
|
-{
|
|
|
- txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len));
|
|
|
-}
|
|
|
-
|
|
|
-static inline unsigned int ftgmac100_txdes_get_buffer_size(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- return FTGMAC100_TXDES0_TXBUF_SIZE(cpu_to_le32(txdes->txdes0));
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_tcpcs(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM);
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_udpcs(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM);
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM);
|
|
|
-}
|
|
|
-
|
|
|
-static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes *txdes,
|
|
|
- dma_addr_t addr)
|
|
|
-{
|
|
|
- txdes->txdes3 = cpu_to_le32(addr);
|
|
|
-}
|
|
|
-
|
|
|
-static dma_addr_t ftgmac100_txdes_get_dma_addr(struct ftgmac100_txdes *txdes)
|
|
|
-{
|
|
|
- return (dma_addr_t)le32_to_cpu(txdes->txdes3);
|
|
|
+ if (index == (TX_QUEUE_ENTRIES - 1))
|
|
|
+ return priv->txdes0_edotr_mask;
|
|
|
+ else
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int ftgmac100_next_tx_pointer(int pointer)
|
|
@@ -566,29 +502,24 @@ static bool ftgmac100_tx_buf_cleanable(struct ftgmac100 *priv)
|
|
|
static void ftgmac100_free_tx_packet(struct ftgmac100 *priv,
|
|
|
unsigned int pointer,
|
|
|
struct sk_buff *skb,
|
|
|
- struct ftgmac100_txdes *txdes)
|
|
|
+ struct ftgmac100_txdes *txdes,
|
|
|
+ u32 ctl_stat)
|
|
|
{
|
|
|
- dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes);
|
|
|
+ dma_addr_t map = le32_to_cpu(txdes->txdes3);
|
|
|
+ size_t len;
|
|
|
|
|
|
- if (ftgmac100_txdes_get_first_segment(txdes)) {
|
|
|
- dma_unmap_single(priv->dev, map, skb_headlen(skb),
|
|
|
- DMA_TO_DEVICE);
|
|
|
+ if (ctl_stat & FTGMAC100_TXDES0_FTS) {
|
|
|
+ len = skb_headlen(skb);
|
|
|
+ dma_unmap_single(priv->dev, map, len, DMA_TO_DEVICE);
|
|
|
} else {
|
|
|
- dma_unmap_page(priv->dev, map,
|
|
|
- ftgmac100_txdes_get_buffer_size(txdes),
|
|
|
- DMA_TO_DEVICE);
|
|
|
+ len = FTGMAC100_TXDES0_TXBUF_SIZE(ctl_stat);
|
|
|
+ dma_unmap_page(priv->dev, map, len, DMA_TO_DEVICE);
|
|
|
}
|
|
|
|
|
|
- if (ftgmac100_txdes_get_last_segment(txdes))
|
|
|
+ /* Free SKB on last segment */
|
|
|
+ if (ctl_stat & FTGMAC100_TXDES0_LTS)
|
|
|
dev_kfree_skb(skb);
|
|
|
priv->tx_skbs[pointer] = NULL;
|
|
|
-
|
|
|
- /* Clear txdes0 except end of ring bit, clear txdes1 as we
|
|
|
- * only "OR" into it, leave 2 and 3 alone as 2 is unused
|
|
|
- * and 3 will be overwritten entirely
|
|
|
- */
|
|
|
- txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask);
|
|
|
- txdes->txdes1 = 0;
|
|
|
}
|
|
|
|
|
|
static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
|
|
@@ -597,17 +528,20 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
|
|
|
struct ftgmac100_txdes *txdes;
|
|
|
struct sk_buff *skb;
|
|
|
unsigned int pointer;
|
|
|
+ u32 ctl_stat;
|
|
|
|
|
|
pointer = priv->tx_clean_pointer;
|
|
|
txdes = &priv->descs->txdes[pointer];
|
|
|
|
|
|
- if (ftgmac100_txdes_owned_by_dma(txdes))
|
|
|
+ ctl_stat = le32_to_cpu(txdes->txdes0);
|
|
|
+ if (ctl_stat & FTGMAC100_TXDES0_TXDMA_OWN)
|
|
|
return false;
|
|
|
|
|
|
skb = priv->tx_skbs[pointer];
|
|
|
netdev->stats.tx_packets++;
|
|
|
netdev->stats.tx_bytes += skb->len;
|
|
|
- ftgmac100_free_tx_packet(priv, pointer, skb, txdes);
|
|
|
+ ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
|
|
|
+ txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
|
|
|
|
|
|
priv->tx_clean_pointer = ftgmac100_next_tx_pointer(pointer);
|
|
|
|
|
@@ -644,6 +578,7 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
|
|
|
struct ftgmac100 *priv = netdev_priv(netdev);
|
|
|
struct ftgmac100_txdes *txdes, *first;
|
|
|
unsigned int pointer, nfrags, len, i, j;
|
|
|
+ u32 f_ctl_stat, ctl_stat, csum_vlan;
|
|
|
dma_addr_t map;
|
|
|
|
|
|
/* The HW doesn't pad small frames */
|
|
@@ -679,26 +614,34 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
|
|
|
pointer = priv->tx_pointer;
|
|
|
txdes = first = &priv->descs->txdes[pointer];
|
|
|
|
|
|
- /* Setup it up with the packet head. We don't set the OWN bit yet. */
|
|
|
+ /* Setup it up with the packet head. Don't write the head to the
|
|
|
+ * ring just yet
|
|
|
+ */
|
|
|
priv->tx_skbs[pointer] = skb;
|
|
|
- ftgmac100_txdes_set_dma_addr(txdes, map);
|
|
|
- ftgmac100_txdes_set_buffer_size(txdes, len);
|
|
|
- ftgmac100_txdes_set_first_segment(txdes);
|
|
|
+ f_ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer);
|
|
|
+ f_ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN;
|
|
|
+ f_ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len);
|
|
|
+ f_ctl_stat |= FTGMAC100_TXDES0_FTS;
|
|
|
+ if (nfrags == 0)
|
|
|
+ f_ctl_stat |= FTGMAC100_TXDES0_LTS;
|
|
|
+ txdes->txdes3 = cpu_to_le32(map);
|
|
|
|
|
|
/* Setup HW checksumming */
|
|
|
+ csum_vlan = 0;
|
|
|
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
|
|
__be16 protocol = skb->protocol;
|
|
|
|
|
|
if (protocol == cpu_to_be16(ETH_P_IP)) {
|
|
|
u8 ip_proto = ip_hdr(skb)->protocol;
|
|
|
|
|
|
- ftgmac100_txdes_set_ipcs(txdes);
|
|
|
+ csum_vlan |= FTGMAC100_TXDES1_IP_CHKSUM;
|
|
|
if (ip_proto == IPPROTO_TCP)
|
|
|
- ftgmac100_txdes_set_tcpcs(txdes);
|
|
|
+ csum_vlan |= FTGMAC100_TXDES1_TCP_CHKSUM;
|
|
|
else if (ip_proto == IPPROTO_UDP)
|
|
|
- ftgmac100_txdes_set_udpcs(txdes);
|
|
|
+ csum_vlan |= FTGMAC100_TXDES1_UDP_CHKSUM;
|
|
|
}
|
|
|
}
|
|
|
+ txdes->txdes1 = cpu_to_le32(csum_vlan);
|
|
|
|
|
|
/* Next descriptor */
|
|
|
pointer = ftgmac100_next_tx_pointer(pointer);
|
|
@@ -718,20 +661,24 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
|
|
|
/* Setup descriptor */
|
|
|
priv->tx_skbs[pointer] = skb;
|
|
|
txdes = &priv->descs->txdes[pointer];
|
|
|
- ftgmac100_txdes_set_dma_addr(txdes, map);
|
|
|
- ftgmac100_txdes_set_buffer_size(txdes, len);
|
|
|
- ftgmac100_txdes_set_dma_own(txdes);
|
|
|
+ ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer);
|
|
|
+ ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN;
|
|
|
+ ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len);
|
|
|
+ if (i == (nfrags - 1))
|
|
|
+ ctl_stat |= FTGMAC100_TXDES0_LTS;
|
|
|
+ txdes->txdes0 = cpu_to_le32(ctl_stat);
|
|
|
+ txdes->txdes1 = 0;
|
|
|
+ txdes->txdes3 = cpu_to_le32(map);
|
|
|
+
|
|
|
+ /* Next one */
|
|
|
pointer = ftgmac100_next_tx_pointer(pointer);
|
|
|
}
|
|
|
|
|
|
- /* Tag last fragment */
|
|
|
- ftgmac100_txdes_set_last_segment(txdes);
|
|
|
-
|
|
|
/* Order the previous packet and descriptor udpates
|
|
|
- * before setting the OWN bit.
|
|
|
+ * before setting the OWN bit on the first descriptor.
|
|
|
*/
|
|
|
dma_wmb();
|
|
|
- ftgmac100_txdes_set_dma_own(first);
|
|
|
+ first->txdes0 = cpu_to_le32(f_ctl_stat);
|
|
|
|
|
|
/* Update next TX pointer */
|
|
|
priv->tx_pointer = pointer;
|
|
@@ -758,13 +705,16 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
|
|
|
|
|
|
/* Free head */
|
|
|
pointer = priv->tx_pointer;
|
|
|
- ftgmac100_free_tx_packet(priv, pointer, skb, first);
|
|
|
+ ftgmac100_free_tx_packet(priv, pointer, skb, first, f_ctl_stat);
|
|
|
+ first->txdes0 = cpu_to_le32(f_ctl_stat & priv->txdes0_edotr_mask);
|
|
|
|
|
|
/* Then all fragments */
|
|
|
for (j = 0; j < i; j++) {
|
|
|
pointer = ftgmac100_next_tx_pointer(pointer);
|
|
|
txdes = &priv->descs->txdes[pointer];
|
|
|
- ftgmac100_free_tx_packet(priv, pointer, skb, txdes);
|
|
|
+ ctl_stat = le32_to_cpu(txdes->txdes0);
|
|
|
+ ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
|
|
|
+ txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
|
|
|
}
|
|
|
|
|
|
/* This cannot be reached if we successfully mapped the
|
|
@@ -802,8 +752,10 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv)
|
|
|
struct ftgmac100_txdes *txdes = &priv->descs->txdes[i];
|
|
|
struct sk_buff *skb = priv->tx_skbs[i];
|
|
|
|
|
|
- if (skb)
|
|
|
- ftgmac100_free_tx_packet(priv, i, skb, txdes);
|
|
|
+ if (!skb)
|
|
|
+ continue;
|
|
|
+ ftgmac100_free_tx_packet(priv, i, skb, txdes,
|
|
|
+ le32_to_cpu(txdes->txdes0));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -843,6 +795,7 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
|
|
|
static void ftgmac100_init_rings(struct ftgmac100 *priv)
|
|
|
{
|
|
|
struct ftgmac100_rxdes *rxdes;
|
|
|
+ struct ftgmac100_txdes *txdes;
|
|
|
int i;
|
|
|
|
|
|
/* Initialize RX ring */
|
|
@@ -855,9 +808,11 @@ static void ftgmac100_init_rings(struct ftgmac100 *priv)
|
|
|
rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
|
|
|
|
|
|
/* Initialize TX ring */
|
|
|
- for (i = 0; i < TX_QUEUE_ENTRIES; i++)
|
|
|
- priv->descs->txdes[i].txdes0 = 0;
|
|
|
- ftgmac100_txdes_set_end_of_ring(priv, &priv->descs->txdes[i -1]);
|
|
|
+ for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
|
|
|
+ txdes = &priv->descs->txdes[i];
|
|
|
+ txdes->txdes0 = 0;
|
|
|
+ }
|
|
|
+ txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
|
|
|
}
|
|
|
|
|
|
static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
|