@@ -29,22 +29,28 @@ config STMMAC_DUAL_MAC
Ethernet Controllers. This option turns on the second Ethernet
device on this kind of platforms.
-config STMMAC_TIMER
+config STMMAC_EXT_TIMER
bool "STMMAC Timer optimisation"
default n
help
Use an external timer for mitigating the number of network
interrupts. Currently, for SH architectures, it is possible
- to use the TMU channel 2 and the SH-RTC device.
+ to use the TMU channel 2 (via Generic Timer) and the SH-RTC
+ device. If the timer registration fails during the interface
+ initialisation then the driver will work without any
+ mitigation schema.
choice
prompt "Select Timer device"
- depends on STMMAC_TIMER
+ depends on STMMAC_EXT_TIMER
-config STMMAC_TMU_TIMER
- bool "TMU channel 2"
- depends on CPU_SH4
+config STMMAC_GEN_TIMER
+ bool "Generic External Timer"
+ depends on SH_TIMER_TMU
help
+ Use the Generic timer for mitigating the interrupts.
+ For example, in case of SUPERH the TMU channel 2
+ is used for that.
config STMMAC_RTC_TIMER
bool "Real time clock"
@@ -1,5 +1,5 @@
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
-stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
+stmmac-$(CONFIG_STMMAC_EXT_TIMER) += stmmac_timer.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o $(stmmac-y)
@@ -43,6 +43,12 @@
#undef FRAME_FILTER_DEBUG
/* #define FRAME_FILTER_DEBUG */
+enum mitigation_timer {
+ no_timer = 0,
+ external = 1,
+ embedded = 2,
+};
+
struct stmmac_extra_stats {
/* Transmit errors */
unsigned long tx_underflow ____cacheline_aligned;
@@ -25,7 +25,7 @@
#include <linux/stmmac.h>
#include "common.h"
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
#include "stmmac_timer.h"
#endif
@@ -77,9 +77,10 @@ struct stmmac_priv {
spinlock_t lock;
int wolopts;
int wolenabled;
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
struct stmmac_timer *tm;
#endif
+ unsigned int timer;
#ifdef STMMAC_VLAN_TAG_USED
struct vlan_group *vlgrp;
#endif
@@ -122,7 +122,7 @@ MODULE_PARM_DESC(tc, "DMA threshold control value");
/* Pay attention to tune this parameter; take care of both
* hardware capability and network stabitily/performance impact.
* Many tests showed that ~4ms latency seems to be good enough. */
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
#define DEFAULT_PERIODIC_RATE 256
static int tmrate = DEFAULT_PERIODIC_RATE;
module_param(tmrate, int, S_IRUGO | S_IWUSR);
@@ -415,9 +415,9 @@ static void init_dma_desc_rings(struct net_device *dev)
else
bfsize = DMA_BUFFER_SIZE;
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
/* Disable interrupts on completion for the reception if timer is on */
- if (likely(priv->tm->enable))
+ if (likely(priv->timer == external))
dis_ic = 1;
#endif
/* If the MTU exceeds 8k so use the second buffer in the chain */
@@ -650,8 +650,8 @@ static void stmmac_tx(struct stmmac_priv *priv)
static inline void stmmac_enable_irq(struct stmmac_priv *priv)
{
-#ifdef CONFIG_STMMAC_TIMER
- if (likely(priv->tm->enable))
+#ifdef CONFIG_STMMAC_EXT_TIMER
+ if (likely(priv->timer == external))
priv->tm->timer_start(priv->tm->timer_callb, tmrate);
else
#endif
@@ -660,8 +660,8 @@ static inline void stmmac_enable_irq(struct stmmac_priv *priv)
static inline void stmmac_disable_irq(struct stmmac_priv *priv)
{
-#ifdef CONFIG_STMMAC_TIMER
- if (likely(priv->tm->enable))
+#ifdef CONFIG_STMMAC_EXT_TIMER
+ if (likely(priv->timer == external))
priv->tm->timer_stop(priv->tm->timer_callb);
else
#endif
@@ -693,7 +693,7 @@ static inline void _stmmac_schedule(struct stmmac_priv *priv)
}
}
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
void stmmac_schedule(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
@@ -795,7 +795,7 @@ static int stmmac_open(struct net_device *dev)
return ret;
}
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
if (unlikely(priv->tm == NULL)) {
pr_err("%s: ERROR: timer memory alloc failed\n", __func__);
@@ -812,7 +812,7 @@ static int stmmac_open(struct net_device *dev)
priv->tm->timer_start = stmmac_no_timer_started;
priv->tm->timer_stop = stmmac_no_timer_stopped;
} else
- priv->tm->enable = 1;
+ priv->timer = external;
#endif
/* Create and initialize the TX/RX descriptors chains. */
@@ -863,8 +863,8 @@ static int stmmac_open(struct net_device *dev)
priv->hw->dma->start_tx(priv->ioaddr);
priv->hw->dma->start_rx(priv->ioaddr);
-#ifdef CONFIG_STMMAC_TIMER
- if (likely(priv->tm->enable))
+#ifdef CONFIG_STMMAC_EXT_TIMER
+ if (likely(priv->timer == external))
priv->tm->timer_start(priv->tm->timer_callb, tmrate);
#endif
/* Dump DMA/MAC registers */
@@ -901,11 +901,13 @@ static int stmmac_release(struct net_device *dev)
netif_stop_queue(dev);
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
/* Stop and release the timer */
- stmmac_close_ext_timer(priv->tm->timer_callb);
- if (priv->tm != NULL)
+ if (priv->tm != NULL) {
+ if (likely(priv->timer == external))
+ stmmac_close_ext_timer(priv->tm->timer_callb);
kfree(priv->tm);
+ }
#endif
napi_disable(&priv->napi);
skb_queue_purge(&priv->rx_recycle);
@@ -1096,9 +1098,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
/* Interrupt on completition only for the latest segment */
priv->hw->desc->close_tx_desc(desc);
-#ifdef CONFIG_STMMAC_TIMER
- /* Clean IC while using timer */
- if (likely(priv->tm->enable))
+#ifdef CONFIG_STMMAC_EXT_TIMER
+ /* Clean IC while using ext timer */
+ if (likely(priv->timer == external))
priv->hw->desc->clear_tx_ic(desc);
#endif
/* To avoid raise condition */
@@ -1815,10 +1817,11 @@ static int stmmac_suspend(struct device *dev)
if (priv->phydev)
phy_stop(priv->phydev);
-#ifdef CONFIG_STMMAC_TIMER
- priv->tm->timer_stop(priv->tm->timer_callb);
- if (likely(priv->tm->enable))
+#ifdef CONFIG_STMMAC_EXT_TIMER
+ if (likely(priv->timer == external)) {
+ priv->tm->timer_stop(priv->tm->timer_callb);
dis_ic = 1;
+ }
#endif
napi_disable(&priv->napi);
@@ -1865,8 +1868,8 @@ static int stmmac_resume(struct device *dev)
priv->hw->dma->start_tx(priv->ioaddr);
priv->hw->dma->start_rx(priv->ioaddr);
-#ifdef CONFIG_STMMAC_TIMER
- if (likely(priv->tm->enable))
+#ifdef CONFIG_STMMAC_EXT_TIMER
+ if (likely(priv->timer == external))
priv->tm->timer_start(priv->tm->timer_callb, tmrate);
#endif
napi_enable(&priv->napi);
@@ -1977,7 +1980,7 @@ static int __init stmmac_cmdline_opt(char *str)
(unsigned long *)&flow_ctrl);
else if (!strncmp(opt, "pause:", 6))
strict_strtoul(opt + 6, 0, (unsigned long *)&pause);
-#ifdef CONFIG_STMMAC_TIMER
+#ifdef CONFIG_STMMAC_EXT_TIMER
else if (!strncmp(opt, "tmrate:", 7))
strict_strtoul(opt + 7, 0, (unsigned long *)&tmrate);
#endif
@@ -102,7 +102,7 @@ int stmmac_close_ext_timer(void *timer)
return 0;
}
-#elif defined(CONFIG_STMMAC_TMU_TIMER)
+#elif defined(CONFIG_STMMAC_GEN_TIMER)
#include <linux/generictimer.h>
/* Set rate and start the timer */
@@ -131,7 +131,7 @@ int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
if (timer == NULL)
return -1;
- STMMAC_TIMER_MSG(dev->name, "sh_tmu", tm->freq);
+ STMMAC_TIMER_MSG(dev->name, "Generic", tm->freq);
tm->timer_callb = timer;
tm->timer_start = stmmac_tmu_set_rate;
@@ -26,7 +26,6 @@ struct stmmac_timer {
void (*timer_start) (void *timer, unsigned int new_freq);
void (*timer_stop) (void *timer);
unsigned int freq;
- unsigned int enable;
void *timer_callb;
};