>From e7fa457acf502c73f4581cd975a37ace410da734 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: <01e33a3f6c46db63ba90f1db3b99eaf62c7071d1.1338026442.git.romieu@fr.zoreil.com> References: <01e33a3f6c46db63ba90f1db3b99eaf62c7071d1.1338026442.git.romieu@fr.zoreil.com> From: Francois Romieu Date: Fri, 25 May 2012 12:37:02 +0200 Subject: [PATCH 4/6] r8169: add extra Tx descriptor ring room for debug. X-Organisation: Land of Sunshine Inc. Signed-off-by: Francois Romieu --- drivers/net/ethernet/realtek/r8169.c | 100 +++++++++++++++++++++++++++++----- 1 files changed, 85 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 3feb374..4812515 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -82,9 +82,11 @@ static const int multicast_filter_limit = 32; #define R8169_REGS_SIZE 256 #define R8169_NAPI_WEIGHT 64 #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ +#define NUM_TX_DESC_DBG 16 /* Tx descriptor ring canary */ #define NUM_RX_DESC 256 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ -#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define R8169_TX_RING_BYTES \ + ((NUM_TX_DESC + NUM_TX_DESC_DBG) * sizeof(struct TxDesc)) #define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL8169_TX_TIMEOUT (6*HZ) @@ -774,6 +776,11 @@ struct rtl8169_private { } phy_action; } *rtl_fw; #define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN) + + struct { + struct sk_buff *skb; + dma_addr_t mapping; + } guard; }; MODULE_AUTHOR("Realtek and the Linux r8169 crew "); @@ -5326,28 +5333,90 @@ err_out: return -ENOMEM; } -static int rtl8169_init_ring(struct net_device *dev) +static int rtl_init_ring_tx(struct rtl8169_private *tp) +{ + struct device *d = &tp->pci_dev->dev; + struct sk_buff *skb; + dma_addr_t mapping; + int i; + + memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info)); + + /* Paranoid debug helping stuff ony beyond this point. */ + +#define RTL_DBG_SKB_LEN 80 + + skb = netdev_alloc_skb_ip_align(tp->dev, RTL_DBG_SKB_LEN); + if (!skb) + return -ENOMEM; + + for (i = 0; i < RTL_DBG_SKB_LEN; i++) + skb->data[i] = 0xaa; + + mapping = dma_map_single(d, skb->data, RTL_DBG_SKB_LEN, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(d, mapping))) { + dev_kfree_skb(skb); + return -EIO; + } + + for (i = NUM_TX_DESC; i < (NUM_TX_DESC + NUM_TX_DESC_DBG); i++) { + struct TxDesc *txd = tp->TxDescArray + i; + + txd->addr = cpu_to_le64(mapping); + txd->opts1 = cpu_to_le32(DescOwn | FirstFrag | LastFrag | + RTL_DBG_SKB_LEN); + } + tp->TxDescArray[i - 1].opts1 |= RingEnd; + + tp->guard.skb = skb; + tp->guard.mapping = mapping; + + return 0; +} + +static void rtl_clean_ring_tx(struct rtl8169_private *tp) +{ + struct device *d = &tp->pci_dev->dev; + + dev_kfree_skb(tp->guard.skb); + dma_unmap_single(d, tp->guard.mapping, RTL_DBG_SKB_LEN, DMA_TO_DEVICE); +} + +static int rtl_init_ring_rx(struct rtl8169_private *tp) +{ + memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *)); + return rtl8169_rx_fill(tp); +} + +static int rtl8169_init_rings(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); + int rc; rtl8169_init_ring_indexes(tp); - memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info)); - memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *)); + rc = rtl_init_ring_tx(tp); + if (rc < 0) + return rc; - return rtl8169_rx_fill(tp); + rc = rtl_init_ring_rx(tp); + if (rc < 0) + rtl_clean_ring_tx(tp); + + return rc; } -static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb, - struct TxDesc *desc) +static void rtl_unmap_tx_skb(struct rtl8169_private *tp, + struct ring_info *tx_skb, struct TxDesc *desc) { + struct device *d = &tp->pci_dev->dev; unsigned int len = tx_skb->len; dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE); desc->opts1 &= cpu_to_le32(RingEnd); desc->opts2 = 0x00; - desc->addr = 0x00; + desc->addr = cpu_to_le64(tp->guard.mapping); tx_skb->len = 0; } @@ -5364,8 +5433,7 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start, if (len) { struct sk_buff *skb = tx_skb->skb; - rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb, - tp->TxDescArray + entry); + rtl_unmap_tx_skb(tp, tx_skb, tp->TxDescArray + entry); if (skb) { tp->dev->stats.tx_dropped++; dev_kfree_skb(skb); @@ -5398,7 +5466,7 @@ static void rtl_print_ring(struct rtl8169_private *tp) netif_info(tp, drv, dev, "Tx ring: dirty=%08x current=%08x\n", tp->dirty_tx, tp->cur_tx); - for (i = 0; i < NUM_TX_DESC; i++) { + for (i = 0; i < (NUM_TX_DESC + NUM_TX_DESC_DBG); i++) { struct TxDesc *desc = tp->TxDescArray + i; netif_info(tp, drv, dev, "[%03d] %08x %08x %0llx\n", i, @@ -5600,7 +5668,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; err_dma_1: - rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); + rtl_unmap_tx_skb(tp, tp->tx_skb + entry, txd); err_dma_0: dev_kfree_skb(skb); dev->stats.tx_dropped++; @@ -5698,8 +5766,7 @@ xmit_race: break; } - rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb, - tp->TxDescArray + entry); + rtl_unmap_tx_skb(tp, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { struct sk_buff *skb = tx_skb->skb; @@ -6034,6 +6101,8 @@ static void rtl8169_down(struct net_device *dev) rtl8169_rx_clear(tp); + rtl_clean_ring_tx(tp); + rtl_pll_power_down(tp); } @@ -6099,7 +6168,7 @@ static int rtl_open(struct net_device *dev) if (!tp->RxDescArray) goto err_free_tx_0; - retval = rtl8169_init_ring(dev); + retval = rtl8169_init_rings(dev); if (retval < 0) goto err_free_rx_1; @@ -6143,6 +6212,7 @@ out: err_release_fw_2: rtl_release_firmware(tp); rtl8169_rx_clear(tp); + rtl_clean_ring_tx(tp); err_free_rx_1: dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, tp->RxPhyAddr); -- 1.7.7.6