From ceb8f6be7e5a254cb5b894be7a032170ec34607b Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 20 Mar 2015 11:50:16 -0500 Subject: amd-xgbe: Use the new DMA memory barriers where appropriate Use the new lighter weight memory barriers when working with the device descriptors. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-drv.c') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 885b02b5be07..8635c9484b3a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1800,6 +1800,9 @@ static void xgbe_rx_refresh(struct xgbe_channel *channel) ring->dirty++; } + /* Make sure everything is written before the register write */ + wmb(); + /* Update the Rx Tail Pointer Register with address of * the last cleaned entry */ rdata = XGBE_GET_DESC_DATA(ring, ring->dirty - 1); @@ -1863,7 +1866,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) /* Make sure descriptor fields are read after reading the OWN * bit */ - rmb(); + dma_rmb(); #ifdef XGMAC_ENABLE_TX_DESC_DUMP xgbe_dump_tx_desc(ring, ring->dirty, 1, 0); -- cgit v1.2.3-59-g8ed1b From 386d325dbdf16919f3416a1b6f26fcfd1c9549ff Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 20 Mar 2015 11:50:22 -0500 Subject: amd-xgbe: Set DMA mask based on hardware register value The hardware supplies a value that indicates the DMA range that it is capable of using. Use this value rather than hard-coding it in the driver. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 2 ++ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 16 ++++++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe-main.c | 19 ++++++++++--------- drivers/net/ethernet/amd/xgbe/xgbe.h | 1 + 4 files changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-drv.c') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 29a09271b64a..34c28aac767f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -365,6 +365,8 @@ #define MAC_HWF0R_TXCOESEL_WIDTH 1 #define MAC_HWF0R_VLHASH_INDEX 4 #define MAC_HWF0R_VLHASH_WIDTH 1 +#define MAC_HWF1R_ADDR64_INDEX 14 +#define MAC_HWF1R_ADDR64_WIDTH 2 #define MAC_HWF1R_ADVTHWORD_INDEX 13 #define MAC_HWF1R_ADVTHWORD_WIDTH 1 #define MAC_HWF1R_DBGMEMA_INDEX 19 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 8635c9484b3a..ef4625e48976 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -519,6 +519,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) RXFIFOSIZE); hw_feat->tx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TXFIFOSIZE); + hw_feat->dma_width = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADDR64); hw_feat->dcb = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DCBEN); hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN); hw_feat->tso = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN); @@ -553,6 +554,21 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) break; } + /* Translate the address width setting into actual number */ + switch (hw_feat->dma_width) { + case 0: + hw_feat->dma_width = 32; + break; + case 1: + hw_feat->dma_width = 40; + break; + case 2: + hw_feat->dma_width = 48; + break; + default: + hw_feat->dma_width = 32; + } + /* The Queue, Channel and TC counts are zero based so increment them * to get the actual number */ diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 32dd65137051..2e4c22d94a6b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -374,15 +374,6 @@ static int xgbe_probe(struct platform_device *pdev) pdata->awcache = XGBE_DMA_SYS_AWCACHE; } - /* Set the DMA mask */ - if (!dev->dma_mask) - dev->dma_mask = &dev->coherent_dma_mask; - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); - if (ret) { - dev_err(dev, "dma_set_mask_and_coherent failed\n"); - goto err_io; - } - /* Get the device interrupt */ ret = platform_get_irq(pdev, 0); if (ret < 0) { @@ -409,6 +400,16 @@ static int xgbe_probe(struct platform_device *pdev) /* Set default configuration data */ xgbe_default_config(pdata); + /* Set the DMA mask */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + ret = dma_set_mask_and_coherent(dev, + DMA_BIT_MASK(pdata->hw_feat.dma_width)); + if (ret) { + dev_err(dev, "dma_set_mask_and_coherent failed\n"); + goto err_io; + } + /* Calculate the number of Tx and Rx rings to be created * -Tx (DMA) Channels map 1-to-1 to Tx Queues so set * the number of Tx queues to the number of Tx channels diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 1eea3e5a5d08..bfe11fb06036 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -632,6 +632,7 @@ struct xgbe_hw_features { unsigned int rx_fifo_size; /* MTL Receive FIFO Size */ unsigned int tx_fifo_size; /* MTL Transmit FIFO Size */ unsigned int adv_ts_hi; /* Advance Timestamping High Word */ + unsigned int dma_width; /* DMA width */ unsigned int dcb; /* DCB Feature */ unsigned int sph; /* Split Header Feature */ unsigned int tso; /* TCP Segmentation Offload */ -- cgit v1.2.3-59-g8ed1b From c635eaacbf77bd6dae917925ef1e76d044b0da07 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 20 Mar 2015 11:50:28 -0500 Subject: amd-xgbe: Remove Tx coalescing The Tx coalescing support in the driver was a software implementation for something lacking in the hardware. Using hrtimers, the idea was to trigger a timer interrupt after having queued a packet for transmit. Unfortunately, as the timer value was lowered, the timer expired before the hardware actually did the transmit and so it was racey and resulted in unnecessary interrupts. Remove the Tx coalescing support and hrtimer and replace with a Tx timer that is used as a reclaim timer in case of inactivity. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 7 +++---- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 16 +++++----------- drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 6 ++---- drivers/net/ethernet/amd/xgbe/xgbe.h | 4 ++-- 4 files changed, 12 insertions(+), 21 deletions(-) (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-drv.c') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index e165d069d6b0..80dd7a92f357 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1367,12 +1367,11 @@ static void xgbe_tx_start_xmit(struct xgbe_channel *channel, XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO, lower_32_bits(rdata->rdesc_dma)); - /* Start the Tx coalescing timer */ + /* Start the Tx timer */ if (pdata->tx_usecs && !channel->tx_timer_active) { channel->tx_timer_active = 1; - hrtimer_start(&channel->tx_timer, - ktime_set(0, pdata->tx_usecs * NSEC_PER_USEC), - HRTIMER_MODE_REL); + mod_timer(&channel->tx_timer, + jiffies + usecs_to_jiffies(pdata->tx_usecs)); } ring->tx.xmit_more = 0; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index ef4625e48976..122a631c4ce0 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -411,11 +411,9 @@ static irqreturn_t xgbe_dma_isr(int irq, void *data) return IRQ_HANDLED; } -static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) +static void xgbe_tx_timer(unsigned long data) { - struct xgbe_channel *channel = container_of(timer, - struct xgbe_channel, - tx_timer); + struct xgbe_channel *channel = (struct xgbe_channel *)data; struct xgbe_prv_data *pdata = channel->pdata; struct napi_struct *napi; @@ -437,8 +435,6 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) channel->tx_timer_active = 0; DBGPR("<--xgbe_tx_timer\n"); - - return HRTIMER_NORESTART; } static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata) @@ -454,9 +450,8 @@ static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata) break; DBGPR(" %s adding tx timer\n", channel->name); - hrtimer_init(&channel->tx_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - channel->tx_timer.function = xgbe_tx_timer; + setup_timer(&channel->tx_timer, xgbe_tx_timer, + (unsigned long)channel); } DBGPR("<--xgbe_init_tx_timers\n"); @@ -475,8 +470,7 @@ static void xgbe_stop_tx_timers(struct xgbe_prv_data *pdata) break; DBGPR(" %s deleting tx timer\n", channel->name); - channel->tx_timer_active = 0; - hrtimer_cancel(&channel->tx_timer); + del_timer_sync(&channel->tx_timer); } DBGPR("<--xgbe_stop_tx_timers\n"); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 43e5571fe858..376d6a529ea1 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -388,7 +388,6 @@ static int xgbe_get_coalesce(struct net_device *netdev, ec->rx_coalesce_usecs = hw_if->riwt_to_usec(pdata, riwt); ec->rx_max_coalesced_frames = pdata->rx_frames; - ec->tx_coalesce_usecs = pdata->tx_usecs; ec->tx_max_coalesced_frames = pdata->tx_frames; DBGPR("<--xgbe_get_coalesce\n"); @@ -402,13 +401,14 @@ static int xgbe_set_coalesce(struct net_device *netdev, struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; unsigned int rx_frames, rx_riwt, rx_usecs; - unsigned int tx_frames, tx_usecs; + unsigned int tx_frames; DBGPR("-->xgbe_set_coalesce\n"); /* Check for not supported parameters */ if ((ec->rx_coalesce_usecs_irq) || (ec->rx_max_coalesced_frames_irq) || + (ec->tx_coalesce_usecs) || (ec->tx_coalesce_usecs_irq) || (ec->tx_max_coalesced_frames_irq) || (ec->stats_block_coalesce_usecs) || @@ -457,7 +457,6 @@ static int xgbe_set_coalesce(struct net_device *netdev, return -EINVAL; } - tx_usecs = ec->tx_coalesce_usecs; tx_frames = ec->tx_max_coalesced_frames; /* Check the bounds of values for Tx */ @@ -471,7 +470,6 @@ static int xgbe_set_coalesce(struct net_device *netdev, pdata->rx_frames = rx_frames; hw_if->config_rx_coalesce(pdata); - pdata->tx_usecs = tx_usecs; pdata->tx_frames = tx_frames; hw_if->config_tx_coalesce(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index bfe11fb06036..72b8f27e7216 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -222,7 +222,7 @@ ((_idx) & ((_ring)->rdesc_count - 1))) /* Default coalescing parameters */ -#define XGMAC_INIT_DMA_TX_USECS 50 +#define XGMAC_INIT_DMA_TX_USECS 1000 #define XGMAC_INIT_DMA_TX_FRAMES 25 #define XGMAC_MAX_DMA_RIWT 0xff @@ -410,7 +410,7 @@ struct xgbe_channel { unsigned int saved_ier; unsigned int tx_timer_active; - struct hrtimer tx_timer; + struct timer_list tx_timer; struct xgbe_ring *tx_ring; struct xgbe_ring *rx_ring; -- cgit v1.2.3-59-g8ed1b From 4a57ebcc2c1e8a924c3897df2c11c5d4620ec89e Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 20 Mar 2015 11:50:34 -0500 Subject: amd-xgbe: Fix Rx coalescing reporting The Rx coalescing value is internally converted from usecs to a value that the hardware can use. When reporting the Rx coalescing value, this internal value is converted back to usecs. During the conversion from and back to usecs some rounding occurs. So, for example, when setting an Rx usec of 30, it will be reported as 29. Fix this reporting issue by keeping the original usec value and using that during reporting. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 1 + drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 12 +++++------- drivers/net/ethernet/amd/xgbe/xgbe.h | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-drv.c') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 122a631c4ce0..fc362be5472b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -702,6 +702,7 @@ void xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_init_rx_coalesce\n"); pdata->rx_riwt = hw_if->usec_to_riwt(pdata, XGMAC_INIT_DMA_RX_USECS); + pdata->rx_usecs = XGMAC_INIT_DMA_RX_USECS; pdata->rx_frames = XGMAC_INIT_DMA_RX_FRAMES; hw_if->config_rx_coalesce(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 376d6a529ea1..b4f6eaaa08f0 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -377,15 +377,12 @@ static int xgbe_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) { struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; - unsigned int riwt; DBGPR("-->xgbe_get_coalesce\n"); memset(ec, 0, sizeof(struct ethtool_coalesce)); - riwt = pdata->rx_riwt; - ec->rx_coalesce_usecs = hw_if->riwt_to_usec(pdata, riwt); + ec->rx_coalesce_usecs = pdata->rx_usecs; ec->rx_max_coalesced_frames = pdata->rx_frames; ec->tx_max_coalesced_frames = pdata->tx_frames; @@ -438,17 +435,17 @@ static int xgbe_set_coalesce(struct net_device *netdev, } rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs); + rx_usecs = ec->rx_coalesce_usecs; rx_frames = ec->rx_max_coalesced_frames; /* Use smallest possible value if conversion resulted in zero */ - if (ec->rx_coalesce_usecs && !rx_riwt) + if (rx_usecs && !rx_riwt) rx_riwt = 1; /* Check the bounds of values for Rx */ if (rx_riwt > XGMAC_MAX_DMA_RIWT) { - rx_usecs = hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT); netdev_alert(netdev, "rx-usec is limited to %d usecs\n", - rx_usecs); + hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT)); return -EINVAL; } if (rx_frames > pdata->rx_desc_count) { @@ -467,6 +464,7 @@ static int xgbe_set_coalesce(struct net_device *netdev, } pdata->rx_riwt = rx_riwt; + pdata->rx_usecs = rx_usecs; pdata->rx_frames = rx_frames; hw_if->config_rx_coalesce(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 72b8f27e7216..dd742426eb04 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -716,6 +716,7 @@ struct xgbe_prv_data { /* Rx coalescing settings */ unsigned int rx_riwt; + unsigned int rx_usecs; unsigned int rx_frames; /* Current Rx buffer size */ -- cgit v1.2.3-59-g8ed1b From 385565a1f0d365793e1f90746237d508bfeef9af Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 20 Mar 2015 11:50:41 -0500 Subject: amd-xgbe: Use napi_alloc_skb when allocating skb in softirq Use the napi_alloc_skb function to allocate an skb when running within the softirq context to avoid calls to local_irq_save/restore. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-drv.c') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index fc362be5472b..347fe2419a18 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1821,16 +1821,15 @@ static void xgbe_rx_refresh(struct xgbe_channel *channel) lower_32_bits(rdata->rdesc_dma)); } -static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata, +static struct sk_buff *xgbe_create_skb(struct napi_struct *napi, struct xgbe_ring_data *rdata, unsigned int *len) { - struct net_device *netdev = pdata->netdev; struct sk_buff *skb; u8 *packet; unsigned int copy_len; - skb = netdev_alloc_skb_ip_align(netdev, rdata->rx.hdr.dma_len); + skb = napi_alloc_skb(napi, rdata->rx.hdr.dma_len); if (!skb) return NULL; @@ -2000,7 +1999,7 @@ read_again: rdata->rx.hdr.dma_len, DMA_FROM_DEVICE); - skb = xgbe_create_skb(pdata, rdata, &put_len); + skb = xgbe_create_skb(napi, rdata, &put_len); if (!skb) { error = 1; goto skip_data; -- cgit v1.2.3-59-g8ed1b