Skip to content

Commit 79ba2b4

Browse files
committed
Merge branch 'fec-next'
Frank Li says: ==================== net: fec: add interrupt coalescence improve error handle when parse queue number. add interrupt coalescence feature. Change from v2 to v3 - add error check in fec_enet_set_coalesce - fix a run time warning to get clock rate in interrupt - fix commit message use TKT number Change from v1 to v2 - fix indention - use errata number instead of TKT ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 709f6c5 + 37d6017 commit 79ba2b4

File tree

2 files changed

+177
-13
lines changed

2 files changed

+177
-13
lines changed

drivers/net/ethernet/freescale/fec.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ struct bufdesc_ex {
316316
* the skbuffer directly.
317317
*/
318318

319-
#define FEC_ENET_RX_PAGES 8
319+
#define FEC_ENET_RX_PAGES 256
320320
#define FEC_ENET_RX_FRSIZE 2048
321321
#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
322322
#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
@@ -355,6 +355,14 @@ struct bufdesc_ex {
355355
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_TS_TIMER)
356356
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
357357

358+
/* ENET interrupt coalescing macro define */
359+
#define FEC_ITR_CLK_SEL (0x1 << 30)
360+
#define FEC_ITR_EN (0x1 << 31)
361+
#define FEC_ITR_ICFT(X) ((X & 0xFF) << 20)
362+
#define FEC_ITR_ICTT(X) ((X) & 0xFFFF)
363+
#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */
364+
#define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */
365+
358366
#define FEC_VLAN_TAG_LEN 0x04
359367
#define FEC_ETHTYPE_LEN 0x02
360368

@@ -466,6 +474,13 @@ struct fec_enet_private {
466474

467475
unsigned int tx_align;
468476
unsigned int rx_align;
477+
478+
/* hw interrupt coalesce */
479+
unsigned int rx_pkts_itr;
480+
unsigned int rx_time_itr;
481+
unsigned int tx_pkts_itr;
482+
unsigned int tx_time_itr;
483+
unsigned int itr_clk_rate;
469484
};
470485

471486
void fec_ptp_init(struct platform_device *pdev);

drivers/net/ethernet/freescale/fec_main.c

Lines changed: 161 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include "fec.h"
6464

6565
static void set_multicast_list(struct net_device *ndev);
66+
static void fec_enet_itr_coal_init(struct net_device *ndev);
6667

6768
#define DRIVER_NAME "fec"
6869

@@ -110,6 +111,12 @@ static void set_multicast_list(struct net_device *ndev);
110111
* independent rings
111112
*/
112113
#define FEC_QUIRK_HAS_AVB (1 << 8)
114+
/* There is a TDAR race condition for mutliQ when the software sets TDAR
115+
* and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles).
116+
* This will cause the udma_tx and udma_tx_arbiter state machines to hang.
117+
* The issue exist at i.MX6SX enet IP.
118+
*/
119+
#define FEC_QUIRK_ERR007885 (1 << 9)
113120

114121
static struct platform_device_id fec_devtype[] = {
115122
{
@@ -138,7 +145,7 @@ static struct platform_device_id fec_devtype[] = {
138145
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
139146
FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
140147
FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
141-
FEC_QUIRK_HAS_AVB,
148+
FEC_QUIRK_HAS_AVB | FEC_QUIRK_ERR007885,
142149
}, {
143150
/* sentinel */
144151
}
@@ -708,6 +715,8 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
708715
struct tso_t tso;
709716
unsigned int index = 0;
710717
int ret;
718+
const struct platform_device_id *id_entry =
719+
platform_get_device_id(fep->pdev);
711720

712721
if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
713722
dev_kfree_skb_any(skb);
@@ -769,7 +778,12 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
769778
txq->cur_tx = bdp;
770779

771780
/* Trigger transmission start */
772-
writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
781+
if (!(id_entry->driver_data & FEC_QUIRK_ERR007885) ||
782+
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
783+
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
784+
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
785+
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)))
786+
writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
773787

774788
return 0;
775789

@@ -1095,6 +1109,10 @@ fec_restart(struct net_device *ndev)
10951109

10961110
/* Enable interrupts we wish to service */
10971111
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
1112+
1113+
/* Init the interrupt coalescing */
1114+
fec_enet_itr_coal_init(ndev);
1115+
10981116
}
10991117

11001118
static void
@@ -2234,12 +2252,141 @@ static int fec_enet_nway_reset(struct net_device *dev)
22342252
return genphy_restart_aneg(phydev);
22352253
}
22362254

2255+
/* ITR clock source is enet system clock (clk_ahb).
2256+
* TCTT unit is cycle_ns * 64 cycle
2257+
* So, the ICTT value = X us / (cycle_ns * 64)
2258+
*/
2259+
static int fec_enet_us_to_itr_clock(struct net_device *ndev, int us)
2260+
{
2261+
struct fec_enet_private *fep = netdev_priv(ndev);
2262+
2263+
return us * (fep->itr_clk_rate / 64000) / 1000;
2264+
}
2265+
2266+
/* Set threshold for interrupt coalescing */
2267+
static void fec_enet_itr_coal_set(struct net_device *ndev)
2268+
{
2269+
struct fec_enet_private *fep = netdev_priv(ndev);
2270+
const struct platform_device_id *id_entry =
2271+
platform_get_device_id(fep->pdev);
2272+
int rx_itr, tx_itr;
2273+
2274+
if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
2275+
return;
2276+
2277+
/* Must be greater than zero to avoid unpredictable behavior */
2278+
if (!fep->rx_time_itr || !fep->rx_pkts_itr ||
2279+
!fep->tx_time_itr || !fep->tx_pkts_itr)
2280+
return;
2281+
2282+
/* Select enet system clock as Interrupt Coalescing
2283+
* timer Clock Source
2284+
*/
2285+
rx_itr = FEC_ITR_CLK_SEL;
2286+
tx_itr = FEC_ITR_CLK_SEL;
2287+
2288+
/* set ICFT and ICTT */
2289+
rx_itr |= FEC_ITR_ICFT(fep->rx_pkts_itr);
2290+
rx_itr |= FEC_ITR_ICTT(fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr));
2291+
tx_itr |= FEC_ITR_ICFT(fep->tx_pkts_itr);
2292+
tx_itr |= FEC_ITR_ICTT(fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr));
2293+
2294+
rx_itr |= FEC_ITR_EN;
2295+
tx_itr |= FEC_ITR_EN;
2296+
2297+
writel(tx_itr, fep->hwp + FEC_TXIC0);
2298+
writel(rx_itr, fep->hwp + FEC_RXIC0);
2299+
writel(tx_itr, fep->hwp + FEC_TXIC1);
2300+
writel(rx_itr, fep->hwp + FEC_RXIC1);
2301+
writel(tx_itr, fep->hwp + FEC_TXIC2);
2302+
writel(rx_itr, fep->hwp + FEC_RXIC2);
2303+
}
2304+
2305+
static int
2306+
fec_enet_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
2307+
{
2308+
struct fec_enet_private *fep = netdev_priv(ndev);
2309+
const struct platform_device_id *id_entry =
2310+
platform_get_device_id(fep->pdev);
2311+
2312+
if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
2313+
return -EOPNOTSUPP;
2314+
2315+
ec->rx_coalesce_usecs = fep->rx_time_itr;
2316+
ec->rx_max_coalesced_frames = fep->rx_pkts_itr;
2317+
2318+
ec->tx_coalesce_usecs = fep->tx_time_itr;
2319+
ec->tx_max_coalesced_frames = fep->tx_pkts_itr;
2320+
2321+
return 0;
2322+
}
2323+
2324+
static int
2325+
fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
2326+
{
2327+
struct fec_enet_private *fep = netdev_priv(ndev);
2328+
const struct platform_device_id *id_entry =
2329+
platform_get_device_id(fep->pdev);
2330+
2331+
unsigned int cycle;
2332+
2333+
if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
2334+
return -EOPNOTSUPP;
2335+
2336+
if (ec->rx_max_coalesced_frames > 255) {
2337+
pr_err("Rx coalesced frames exceed hardware limiation");
2338+
return -EINVAL;
2339+
}
2340+
2341+
if (ec->tx_max_coalesced_frames > 255) {
2342+
pr_err("Tx coalesced frame exceed hardware limiation");
2343+
return -EINVAL;
2344+
}
2345+
2346+
cycle = fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr);
2347+
if (cycle > 0xFFFF) {
2348+
pr_err("Rx coalesed usec exceeed hardware limiation");
2349+
return -EINVAL;
2350+
}
2351+
2352+
cycle = fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr);
2353+
if (cycle > 0xFFFF) {
2354+
pr_err("Rx coalesed usec exceeed hardware limiation");
2355+
return -EINVAL;
2356+
}
2357+
2358+
fep->rx_time_itr = ec->rx_coalesce_usecs;
2359+
fep->rx_pkts_itr = ec->rx_max_coalesced_frames;
2360+
2361+
fep->tx_time_itr = ec->tx_coalesce_usecs;
2362+
fep->tx_pkts_itr = ec->tx_max_coalesced_frames;
2363+
2364+
fec_enet_itr_coal_set(ndev);
2365+
2366+
return 0;
2367+
}
2368+
2369+
static void fec_enet_itr_coal_init(struct net_device *ndev)
2370+
{
2371+
struct ethtool_coalesce ec;
2372+
2373+
ec.rx_coalesce_usecs = FEC_ITR_ICTT_DEFAULT;
2374+
ec.rx_max_coalesced_frames = FEC_ITR_ICFT_DEFAULT;
2375+
2376+
ec.tx_coalesce_usecs = FEC_ITR_ICTT_DEFAULT;
2377+
ec.tx_max_coalesced_frames = FEC_ITR_ICFT_DEFAULT;
2378+
2379+
fec_enet_set_coalesce(ndev, &ec);
2380+
}
2381+
22372382
static const struct ethtool_ops fec_enet_ethtool_ops = {
22382383
.get_settings = fec_enet_get_settings,
22392384
.set_settings = fec_enet_set_settings,
22402385
.get_drvinfo = fec_enet_get_drvinfo,
22412386
.nway_reset = fec_enet_nway_reset,
22422387
.get_link = ethtool_op_get_link,
2388+
.get_coalesce = fec_enet_get_coalesce,
2389+
.set_coalesce = fec_enet_set_coalesce,
22432390
#ifndef CONFIG_M5272
22442391
.get_pauseparam = fec_enet_get_pauseparam,
22452392
.set_pauseparam = fec_enet_set_pauseparam,
@@ -2890,23 +3037,23 @@ fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
28903037

28913038
/* parse the num of tx and rx queues */
28923039
err = of_property_read_u32(np, "fsl,num-tx-queues", num_tx);
2893-
err |= of_property_read_u32(np, "fsl,num-rx-queues", num_rx);
2894-
if (err) {
3040+
if (err)
28953041
*num_tx = 1;
3042+
3043+
err = of_property_read_u32(np, "fsl,num-rx-queues", num_rx);
3044+
if (err)
28963045
*num_rx = 1;
2897-
return;
2898-
}
28993046

29003047
if (*num_tx < 1 || *num_tx > FEC_ENET_MAX_TX_QS) {
2901-
dev_err(&pdev->dev, "Invalidate num_tx(=%d), fail back to 1\n",
2902-
*num_tx);
3048+
dev_warn(&pdev->dev, "Invalid num_tx(=%d), fall back to 1\n",
3049+
*num_tx);
29033050
*num_tx = 1;
29043051
return;
29053052
}
29063053

29073054
if (*num_rx < 1 || *num_rx > FEC_ENET_MAX_RX_QS) {
2908-
dev_err(&pdev->dev, "Invalidate num_rx(=%d), fail back to 1\n",
2909-
*num_rx);
3055+
dev_warn(&pdev->dev, "Invalid num_rx(=%d), fall back to 1\n",
3056+
*num_rx);
29103057
*num_rx = 1;
29113058
return;
29123059
}
@@ -2924,8 +3071,8 @@ fec_probe(struct platform_device *pdev)
29243071
const struct of_device_id *of_id;
29253072
static int dev_id;
29263073
struct device_node *np = pdev->dev.of_node, *phy_node;
2927-
int num_tx_qs = 1;
2928-
int num_rx_qs = 1;
3074+
int num_tx_qs;
3075+
int num_rx_qs;
29293076

29303077
of_id = of_match_device(fec_dt_ids, &pdev->dev);
29313078
if (of_id)
@@ -3006,6 +3153,8 @@ fec_probe(struct platform_device *pdev)
30063153
goto failed_clk;
30073154
}
30083155

3156+
fep->itr_clk_rate = clk_get_rate(fep->clk_ahb);
3157+
30093158
/* enet_out is optional, depends on board */
30103159
fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");
30113160
if (IS_ERR(fep->clk_enet_out))

0 commit comments

Comments
 (0)