* [PATCH 0/3] defxx: DEFEA fixes and updates
From: Maciej W. Rozycki @ 2014-09-25 10:06 UTC (permalink / raw)
To: netdev
Hi,
I have finally got my hands on an EISA variation of the board (DEC
FDDIcontroller/EISA aka DEFEA) and was able to do some testing. Here are
initial updates to the driver that address problems I encountered so far.
More to come later on as I get back to the system that I have in a remote
location -- I need to double-check MMIO support and see what might have
been causing spurious interrupts I saw with the 8259A PIC the board's
interrupt line has been routed to.
Maciej
^ permalink raw reply
* [PATCH v1 1/4] net: fec: ptp: Use the 31-bit ptp timer.
From: Luwei Zhou @ 2014-09-25 8:10 UTC (permalink / raw)
To: davem, richardcochran
Cc: netdev, shawn.guo, bhutchings, R49496, b38611, b20596, stephen
In-Reply-To: <1411632621-17429-1-git-send-email-b45643@freescale.com>
When ptp switches from software adjustment to hardware ajustment, linux ptp can't converge.
It is caused by the IP limit. Hardware adjustment logcial have issue when ptp counter
runs over 0x80000000(31 bit counter). The internal IP reference manual already remove 32bit
free-running count support. This patch replace the 32-bit PTP timer with 31-bit.
Signed-off-by: Luwei Zhou <b45643@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
drivers/net/ethernet/freescale/fec_ptp.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index cca3617..8016bdd 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -70,6 +70,7 @@
#define FEC_TS_TIMESTAMP 0x418
#define FEC_CC_MULT (1 << 31)
+#define FEC_COUNTER_PERIOD (1 << 31)
/**
* fec_ptp_read - read raw cycle counter (to be used by time counter)
* @cc: the cyclecounter structure
@@ -113,14 +114,15 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
/* 1ns counter */
writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC);
- /* use free running count */
- writel(0, fep->hwp + FEC_ATIME_EVT_PERIOD);
+ /* use 31-bit timer counter */
+ writel(FEC_COUNTER_PERIOD, fep->hwp + FEC_ATIME_EVT_PERIOD);
- writel(FEC_T_CTRL_ENABLE, fep->hwp + FEC_ATIME_CTRL);
+ writel(FEC_T_CTRL_ENABLE | FEC_T_CTRL_PERIOD_RST,
+ fep->hwp + FEC_ATIME_CTRL);
memset(&fep->cc, 0, sizeof(fep->cc));
fep->cc.read = fec_ptp_read;
- fep->cc.mask = CLOCKSOURCE_MASK(32);
+ fep->cc.mask = CLOCKSOURCE_MASK(31);
fep->cc.shift = 31;
fep->cc.mult = FEC_CC_MULT;
--
1.9.1
^ permalink raw reply related
* [PATCH v1 0/4] Enable FEC pps ouput
From: Luwei Zhou @ 2014-09-25 8:10 UTC (permalink / raw)
To: davem, richardcochran
Cc: netdev, shawn.guo, bhutchings, R49496, b38611, b20596, stephen
This patch does:
- Replace 32-bit free-running PTP timer with 31-bit.
- Implement hardware PTP timestamp adjustment.
- Enable PPS output based on hardware adjustment.
Luwei Zhou (4):
net: fec: ptp: Use the 31-bit ptp timer.
net: fec: ptp: Use hardware algorithm to adjust PTP counter.
net: fec: ptp: Enalbe PPS ouput based on ptp clock
ARM: Documentation: Update fec dts binding doc
Documentation/devicetree/bindings/net/fsl-fec.txt | 2 +
drivers/net/ethernet/freescale/fec.h | 7 +
drivers/net/ethernet/freescale/fec_main.c | 2 +
drivers/net/ethernet/freescale/fec_ptp.c | 301 ++++++++++++++++++++--
4 files changed, 297 insertions(+), 15 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH v1 3/4] net: fec: ptp: Enalbe PPS ouput based on ptp clock
From: Luwei Zhou @ 2014-09-25 8:10 UTC (permalink / raw)
To: davem, richardcochran
Cc: netdev, shawn.guo, bhutchings, R49496, b38611, b20596, stephen
In-Reply-To: <1411632621-17429-1-git-send-email-b45643@freescale.com>
FEC ptp timer has 4 channel compare/trigger function. It can be used to enable pps output.
The pulse would be ouput high exactly on N second. The pulse ouput high on compare event mode
is used to produce pulse per second. The pulse width would be one cycle based on ptp timer clock
source.Since 31-bit ptp hardware timer is used, the timer will wrap more than 2 seconds. We need to
reload the compare compare event about every 1 second.
Signed-off-by: Luwei Zhou <b45643@freescale.com>
---
drivers/net/ethernet/freescale/fec.h | 7 +
drivers/net/ethernet/freescale/fec_main.c | 2 +
drivers/net/ethernet/freescale/fec_ptp.c | 223 +++++++++++++++++++++++++++++-
3 files changed, 231 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 26fb1de..f8e23e6 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -481,12 +481,19 @@ struct fec_enet_private {
unsigned int tx_pkts_itr;
unsigned int tx_time_itr;
unsigned int itr_clk_rate;
+
+ /* pps */
+ int pps_channel;
+ unsigned int reload_period;
+ int pps_enable;
+ unsigned int next_counter;
};
void fec_ptp_init(struct platform_device *pdev);
void fec_ptp_start_cyclecounter(struct net_device *ndev);
int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
+uint fec_ptp_check_pps_event(struct fec_enet_private *fep);
/****************************************************************************/
#endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 3a4ec0f..5a4ce36 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1558,6 +1558,8 @@ fec_enet_interrupt(int irq, void *dev_id)
complete(&fep->mdio_done);
}
+ fec_ptp_check_pps_event(fep);
+
return ret;
}
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index e2bf786..c55239d 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -61,6 +61,24 @@
#define FEC_T_INC_CORR_MASK 0x00007f00
#define FEC_T_INC_CORR_OFFSET 8
+#define FEC_T_CTRL_PINPER 0x00000080
+#define FEC_T_TF0_MASK 0x00000001
+#define FEC_T_TF0_OFFSET 0
+#define FEC_T_TF1_MASK 0x00000002
+#define FEC_T_TF1_OFFSET 1
+#define FEC_T_TF2_MASK 0x00000004
+#define FEC_T_TF2_OFFSET 2
+#define FEC_T_TF3_MASK 0x00000008
+#define FEC_T_TF3_OFFSET 3
+#define FEC_T_TDRE_MASK 0x00000001
+#define FEC_T_TDRE_OFFSET 0
+#define FEC_T_TMODE_MASK 0x0000003C
+#define FEC_T_TMODE_OFFSET 2
+#define FEC_T_TIE_MASK 0x00000040
+#define FEC_T_TIE_OFFSET 6
+#define FEC_T_TF_MASK 0x00000080
+#define FEC_T_TF_OFFSET 7
+
#define FEC_ATIME_CTRL 0x400
#define FEC_ATIME 0x404
#define FEC_ATIME_EVT_OFFSET 0x408
@@ -69,9 +87,162 @@
#define FEC_ATIME_INC 0x414
#define FEC_TS_TIMESTAMP 0x418
+#define FEC_TGSR 0x604
+#define FEC_TCSR(n) (0x608 + n * 0x08)
+#define FEC_TCCR(n) (0x60C + n * 0x08)
+#define MAX_TIMER_CHANNEL 3
+#define FEC_TMODE_TOGGLE 0x05
+#define FEC_HIGH_PULSE 0x0F
+
#define FEC_CC_MULT (1 << 31)
#define FEC_COUNTER_PERIOD (1 << 31)
#define FEC_T_PERIOD_ONE_SEC (1000000000UL)
+#define PPS_OUPUT_RELOAD_PERIOD FEC_T_PERIOD_ONE_SEC
+
+/**
+ * fec_ptp_enable_pps
+ * @fep: the fec_enet_private structure handle
+ * @enable: enable the channel pps output
+ *
+ * This function enble the PPS ouput on the timer channel.
+ */
+static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
+{
+ unsigned long flags;
+ u32 val, tempval;
+ int inc;
+ struct timespec ts;
+ u64 ns;
+ u32 remainder;
+ val = 0;
+
+ if (fep->pps_channel == -1 || fep->pps_channel > MAX_TIMER_CHANNEL) {
+ dev_err(&fep->pdev->dev, "Invalid pps channel\n");
+ return -EINVAL;
+ }
+
+ if (!(fep->hwts_tx_en || fep->hwts_rx_en)) {
+ dev_err(&fep->pdev->dev, "No ptp stack is running\n");
+ return -EINVAL;
+ }
+
+ if (fep->pps_enable == enable)
+ return 0;
+
+ fep->reload_period = PPS_OUPUT_RELOAD_PERIOD;
+ inc = FEC_T_PERIOD_ONE_SEC / clk_get_rate(fep->clk_ptp);
+
+ spin_lock_irqsave(&fep->tmreg_lock, flags);
+
+ if (enable) {
+ /*
+ * clear capture or output compare interrupt status if have.
+ */
+ writel(FEC_T_TF_MASK, fep->hwp + FEC_TCSR(fep->pps_channel));
+
+ /*
+ * It is recommended to doulbe check the TMODE field in the
+ * TCSR register to be cleared before the first compare counter
+ * is written into TCCR register. Just add a double check.
+ */
+ val = readl(fep->hwp + FEC_TCSR(fep->pps_channel));
+ do {
+ val &= ~(FEC_T_TMODE_MASK);
+ writel(val, fep->hwp + FEC_TCSR(fep->pps_channel));
+ val = readl(fep->hwp + FEC_TCSR(fep->pps_channel));
+ } while (val & FEC_T_TMODE_MASK);
+
+ /*
+ * Dummy read counter to update the counter
+ */
+ timecounter_read(&fep->tc);
+ /*
+ * linux ptp is running. We want to find the first compare event
+ * in the next second point. So we need to know what the ptp time
+ * is now and how many nanoseconds is ahead to get next second.
+ * The remaining nanosecond ahead before the next second would be
+ * FEC_T_PERIOD_ONE_SEC - ts.tv_nsec. Add the remaining nanoseconds
+ * to current timer would be next second.
+ */
+ tempval = readl(fep->hwp + FEC_ATIME_CTRL);
+ tempval |= FEC_T_CTRL_CAPTURE;
+ writel(tempval, fep->hwp + FEC_ATIME_CTRL);
+
+ tempval = readl(fep->hwp + FEC_ATIME);
+ /*
+ * Converse the ptp local counter to 1588 timestamp
+ */
+ ns = timecounter_cyc2time(&fep->tc, tempval);
+ ts.tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
+ ts.tv_nsec = remainder;
+
+ /*
+ * The tempval is less than 3 seconds, and so val is less than
+ * 4 seconds. No overflow for 32bit calculation.
+ */
+ val = FEC_T_PERIOD_ONE_SEC - (u32)ts.tv_nsec + tempval;
+
+ /* Need to consider the situation that the current time is
+ * very close to the second point, which means FEC_T_PERIOD_ONE_SEC
+ * - ts.tv_nsec is close to be zero(For example 20ns); Since the timer
+ * is still running when we calculate the first compare event, it is
+ * possible that the remaining nanoseonds run out before the compare
+ * counter is calculated and written into TCCR register. To avoid
+ * this possibility, we will set the compare event to be the next
+ * of next second. The current setting is 31-bit timer and wrap
+ * around over 2 seconds. So it is okay to set the next of next
+ * seond for the timer.
+ */
+ val += FEC_T_PERIOD_ONE_SEC;
+
+ /*
+ * We add (2 *FEC_T_PERIOD_ONE_SEC - (u32)ts.tv_nsec) to current
+ * ptp counter, which maybe cause 32-bit wrap. Since the
+ * (FEC_T_PERIOD_ONE_SEC - (u32)ts.tv_nsec) is less than 2 second.
+ * We can ensure the wrap will not cause issue. If the offset
+ * is bigger than fep->cc.mask would be a error.
+ */
+ val &= fep->cc.mask;
+ writel(val, fep->hwp + FEC_TCCR(fep->pps_channel));
+
+ /*
+ * Calculate the second the compare event timestamp.
+ */
+ fep->next_counter = (val + fep->reload_period) & fep->cc.mask;
+
+ /*
+ * Enable compare event when overflow
+ */
+ val = readl(fep->hwp + FEC_ATIME_CTRL);
+ val |= FEC_T_CTRL_PINPER;
+ writel(val, fep->hwp + FEC_ATIME_CTRL);
+
+ /*
+ * Compare channel setting.
+ */
+ val = readl(fep->hwp + FEC_TCSR(fep->pps_channel));
+ val |= (1 << FEC_T_TF_OFFSET | 1 << FEC_T_TIE_OFFSET);
+ val &= ~(1 << FEC_T_TDRE_OFFSET);
+ val &= ~(FEC_T_TMODE_MASK);
+ val |= (FEC_HIGH_PULSE << FEC_T_TMODE_OFFSET);
+ writel(val, fep->hwp + FEC_TCSR(fep->pps_channel));
+
+ /*
+ * Write the second compare event timestamp and calculate
+ * the third timestamp. Refer the TCCR register detail in the spec.
+ */
+ writel(fep->next_counter, fep->hwp + FEC_TCCR(fep->pps_channel));
+ fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask;
+ } else {
+ writel(0, fep->hwp + FEC_TCSR(fep->pps_channel));
+ }
+
+ fep->pps_enable = enable;
+ spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+
+ return 0;
+}
+
/**
* fec_ptp_read - read raw cycle counter (to be used by time counter)
* @cc: the cyclecounter structure
@@ -322,6 +493,15 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
static int fec_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
+ struct fec_enet_private *fep =
+ container_of(ptp, struct fec_enet_private, ptp_caps);
+ int ret = 0;
+
+ if (rq->type == PTP_CLK_REQ_PPS) {
+ ret = fec_ptp_enable_pps(fep, on);
+
+ return ret;
+ }
return -EOPNOTSUPP;
}
@@ -427,6 +607,8 @@ void fec_ptp_init(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
+ struct device_node *np = pdev->dev.of_node;
+ int err;
fep->ptp_caps.owner = THIS_MODULE;
snprintf(fep->ptp_caps.name, 16, "fec ptp");
@@ -436,7 +618,7 @@ void fec_ptp_init(struct platform_device *pdev)
fep->ptp_caps.n_ext_ts = 0;
fep->ptp_caps.n_per_out = 0;
fep->ptp_caps.n_pins = 0;
- fep->ptp_caps.pps = 0;
+ fep->ptp_caps.pps = 1;
fep->ptp_caps.adjfreq = fec_ptp_adjfreq;
fep->ptp_caps.adjtime = fec_ptp_adjtime;
fep->ptp_caps.gettime = fec_ptp_gettime;
@@ -444,6 +626,10 @@ void fec_ptp_init(struct platform_device *pdev)
fep->ptp_caps.enable = fec_ptp_enable;
fep->cycle_speed = clk_get_rate(fep->clk_ptp);
+ err = of_property_read_u32(np, "pps-channel",
+ &fep->pps_channel);
+ if (err)
+ fep->pps_channel = -1;
spin_lock_init(&fep->tmreg_lock);
@@ -459,3 +645,38 @@ void fec_ptp_init(struct platform_device *pdev)
schedule_delayed_work(&fep->time_keep, HZ);
}
+
+/**
+ * fec_ptp_check_pps_event
+ * @fep: the fec_enet_private structure handle
+ *
+ * This function check the pps event and reload the timer compare counter.
+ */
+uint fec_ptp_check_pps_event(struct fec_enet_private *fep)
+{
+ u32 val;
+ u8 channel = fep->pps_channel;
+ struct ptp_clock_event event;
+
+ val = readl(fep->hwp + FEC_TCSR(channel));
+ if (val & FEC_T_TF_MASK) {
+ /*
+ * Write the next next compare(not the next according the spec) value to the register
+ */
+ writel(fep->next_counter, fep->hwp + FEC_TCCR(channel));
+ do {
+ writel(val, fep->hwp + FEC_TCSR(channel));
+ } while (readl(fep->hwp + FEC_TCSR(channel)) & FEC_T_TF_MASK);
+
+ /*
+ * Update the counter;
+ */
+ fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask;
+
+ event.type = PTP_CLOCK_PPS;
+ ptp_clock_event(fep->ptp_clock, &event);
+ return 1;
+ }
+
+ return 0;
+}
--
1.9.1
^ permalink raw reply related
* [PATCH v1 2/4] net: fec: ptp: Use hardware algorithm to adjust PTP counter.
From: Luwei Zhou @ 2014-09-25 8:10 UTC (permalink / raw)
To: davem, richardcochran
Cc: netdev, shawn.guo, bhutchings, R49496, b38611, b20596, stephen
In-Reply-To: <1411632621-17429-1-git-send-email-b45643@freescale.com>
The FEC IP supports hardware adjustment for ptp timer. Refer to the description of
ENET_ATCOR and ENET_ATINC registers in the spec about the hardware adjustment. This
patch uses hardware support to adjust the ptp offset and frequency on the slave side.
Signed-off-by: Luwei Zhou <b45643@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
Signed-off-by: Fugang Duan <b38611@freescale.com>
---
drivers/net/ethernet/freescale/fec_ptp.c | 68 +++++++++++++++++++++++++++-----
1 file changed, 58 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 8016bdd..e2bf786 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -71,6 +71,7 @@
#define FEC_CC_MULT (1 << 31)
#define FEC_COUNTER_PERIOD (1 << 31)
+#define FEC_T_PERIOD_ONE_SEC (1000000000UL)
/**
* fec_ptp_read - read raw cycle counter (to be used by time counter)
* @cc: the cyclecounter structure
@@ -145,33 +146,65 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
*/
static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
{
- u64 diff;
unsigned long flags;
int neg_adj = 0;
- u32 mult = FEC_CC_MULT;
+ u32 i, tmp;
+ u32 ptp_ts_clk, ptp_inc;
+ u32 corr_inc, corr_period;
+ u32 corr_ns;
struct fec_enet_private *fep =
container_of(ptp, struct fec_enet_private, ptp_caps);
+ if (ppb == 0)
+ return 0;
+
if (ppb < 0) {
ppb = -ppb;
neg_adj = 1;
}
- diff = mult;
- diff *= ppb;
- diff = div_u64(diff, 1000000000ULL);
+ ptp_ts_clk = clk_get_rate(fep->clk_ptp);
+ ptp_inc = FEC_T_PERIOD_ONE_SEC / ptp_ts_clk;
+
+ /*
+ * In theory, corr_inc/corr_period = ppb/FEC_T_PERIOD_ONE_SEC;
+ * Try to find the corr_inc between 1 to ptp_inc to meet adjustment
+ * requirement.
+ */
+ for (i = 1; i <= ptp_inc; i++) {
+ if (((i * FEC_T_PERIOD_ONE_SEC) / ppb) >= ptp_inc) {
+ corr_inc = i;
+ corr_period = ((i * FEC_T_PERIOD_ONE_SEC) /
+ (ptp_inc * ppb));
+ break;
+ }
+ }
+ /*
+ * Not found? Set it to high value - double speed
+ * correct in every clock step.
+ */
+ if (i > ptp_inc) {
+ corr_inc = ptp_inc;
+ corr_period = 1;
+ }
+
+ if (neg_adj)
+ corr_ns = ptp_inc - corr_inc;
+ else
+ corr_ns = ptp_inc + corr_inc;
spin_lock_irqsave(&fep->tmreg_lock, flags);
+
+ tmp = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
+ tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
+ writel(tmp, fep->hwp + FEC_ATIME_INC);
+ writel(corr_period, fep->hwp + FEC_ATIME_CORR);
/*
- * dummy read to set cycle_last in tc to now.
- * So use adjusted mult to calculate when next call
- * timercounter_read.
+ * dummy read to update the timer.
*/
timecounter_read(&fep->tc);
- fep->cc.mult = neg_adj ? mult - diff : mult + diff;
-
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
return 0;
@@ -190,12 +223,20 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
container_of(ptp, struct fec_enet_private, ptp_caps);
unsigned long flags;
u64 now;
+ u32 counter;
spin_lock_irqsave(&fep->tmreg_lock, flags);
now = timecounter_read(&fep->tc);
now += delta;
+ /*
+ * Get the timer value based on adjusted timestamp.
+ * Update the counter with the masked value.
+ */
+ counter = now & fep->cc.mask;
+ writel(counter, fep->hwp + FEC_ATIME);
+
/* reset the timecounter */
timecounter_init(&fep->tc, &fep->cc, now);
@@ -246,6 +287,7 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
u64 ns;
unsigned long flags;
+ u32 counter;
mutex_lock(&fep->ptp_clk_mutex);
/* Check the ptp clock */
@@ -256,8 +298,14 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
ns = ts->tv_sec * 1000000000ULL;
ns += ts->tv_nsec;
+ /*
+ * Get the timer value based on timestamp.
+ * Update the counter with the masked value.
+ */
+ counter = ns & fep->cc.mask;
spin_lock_irqsave(&fep->tmreg_lock, flags);
+ writel(counter, fep->hwp + FEC_ATIME);
timecounter_init(&fep->tc, &fep->cc, ns);
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
mutex_unlock(&fep->ptp_clk_mutex);
--
1.9.1
^ permalink raw reply related
* [PATCH v1 4/4] ARM: Documentation: Update fec dts binding doc
From: Luwei Zhou @ 2014-09-25 8:10 UTC (permalink / raw)
To: davem, richardcochran
Cc: netdev, shawn.guo, bhutchings, R49496, b38611, b20596, stephen
In-Reply-To: <1411632621-17429-1-git-send-email-b45643@freescale.com>
This patch update fec devicetree binding doc that add Optional properties
"pps-channel".
Signed-off-by: Luwei Zhou <b45643@freescale.com>
---
Documentation/devicetree/bindings/net/fsl-fec.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
index 0c8775c..14a4fbb 100644
--- a/Documentation/devicetree/bindings/net/fsl-fec.txt
+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -22,6 +22,8 @@ Optional properties:
- fsl,num-rx-queues : The property is valid for enet-avb IP, which supports
hw multi queues. Should specify the rx queue number, otherwise set rx queue
number to 1.
+- pps-channel: The FEC ptp support 4 channel timer. Specify the channel number
+ to output PPS signal.
Optional subnodes:
- mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
--
1.9.1
^ permalink raw reply related
* [PATCH 2/4] xfrm: hash prefixed policies based on preflen thresholds
From: Steffen Klassert @ 2014-09-25 9:10 UTC (permalink / raw)
To: David Miller; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <1411636225-4433-1-git-send-email-steffen.klassert@secunet.com>
From: Christophe Gouault <christophe.gouault@6wind.com>
The idea is an extension of the current policy hashing.
Today only non-prefixed policies are stored in a hash table. This
patch relaxes the constraints, and hashes policies whose prefix
lengths are greater or equal to a configurable threshold.
Each hash table (one per direction) maintains its own set of IPv4 and
IPv6 thresholds (dbits4, sbits4, dbits6, sbits6), by default (32, 32,
128, 128).
Example, if the output hash table is configured with values (16, 24,
56, 64):
ip xfrm policy add dir out src 10.22.0.0/20 dst 10.24.1.0/24 ... => hashed
ip xfrm policy add dir out src 10.22.0.0/16 dst 10.24.1.1/32 ... => hashed
ip xfrm policy add dir out src 10.22.0.0/16 dst 10.24.0.0/16 ... => unhashed
ip xfrm policy add dir out \
src 3ffe:304:124:2200::/60 dst 3ffe:304:124:2401::/64 ... => hashed
ip xfrm policy add dir out \
src 3ffe:304:124:2200::/56 dst 3ffe:304:124:2401::2/128 ... => hashed
ip xfrm policy add dir out \
src 3ffe:304:124:2200::/56 dst 3ffe:304:124:2400::/56 ... => unhashed
The high order bits of the addresses (up to the threshold) are used to
compute the hash key.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
include/net/netns/xfrm.h | 4 +++
net/xfrm/xfrm_hash.h | 76 +++++++++++++++++++++++++++++++++++++++++-------
net/xfrm/xfrm_policy.c | 53 +++++++++++++++++++++++++++++----
3 files changed, 117 insertions(+), 16 deletions(-)
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 3492434..41902a8 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -13,6 +13,10 @@ struct ctl_table_header;
struct xfrm_policy_hash {
struct hlist_head *table;
unsigned int hmask;
+ u8 dbits4;
+ u8 sbits4;
+ u8 dbits6;
+ u8 sbits6;
};
struct netns_xfrm {
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index 0622d31..666c5ff 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -3,6 +3,7 @@
#include <linux/xfrm.h>
#include <linux/socket.h>
+#include <linux/jhash.h>
static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr)
{
@@ -28,6 +29,58 @@ static inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr,
saddr->a6[2] ^ saddr->a6[3]);
}
+static inline u32 __bits2mask32(__u8 bits)
+{
+ u32 mask32 = 0xffffffff;
+
+ if (bits == 0)
+ mask32 = 0;
+ else if (bits < 32)
+ mask32 <<= (32 - bits);
+
+ return mask32;
+}
+
+static inline unsigned int __xfrm4_dpref_spref_hash(const xfrm_address_t *daddr,
+ const xfrm_address_t *saddr,
+ __u8 dbits,
+ __u8 sbits)
+{
+ return jhash_2words(ntohl(daddr->a4) & __bits2mask32(dbits),
+ ntohl(saddr->a4) & __bits2mask32(sbits),
+ 0);
+}
+
+static inline unsigned int __xfrm6_pref_hash(const xfrm_address_t *addr,
+ __u8 prefixlen)
+{
+ int pdw;
+ int pbi;
+ u32 initval = 0;
+
+ pdw = prefixlen >> 5; /* num of whole u32 in prefix */
+ pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */
+
+ if (pbi) {
+ __be32 mask;
+
+ mask = htonl((0xffffffff) << (32 - pbi));
+
+ initval = (__force u32)(addr->a6[pdw] & mask);
+ }
+
+ return jhash2((__force u32 *)addr->a6, pdw, initval);
+}
+
+static inline unsigned int __xfrm6_dpref_spref_hash(const xfrm_address_t *daddr,
+ const xfrm_address_t *saddr,
+ __u8 dbits,
+ __u8 sbits)
+{
+ return __xfrm6_pref_hash(daddr, dbits) ^
+ __xfrm6_pref_hash(saddr, sbits);
+}
+
static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr,
const xfrm_address_t *saddr,
u32 reqid, unsigned short family,
@@ -84,7 +137,8 @@ static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
}
static inline unsigned int __sel_hash(const struct xfrm_selector *sel,
- unsigned short family, unsigned int hmask)
+ unsigned short family, unsigned int hmask,
+ u8 dbits, u8 sbits)
{
const xfrm_address_t *daddr = &sel->daddr;
const xfrm_address_t *saddr = &sel->saddr;
@@ -92,19 +146,19 @@ static inline unsigned int __sel_hash(const struct xfrm_selector *sel,
switch (family) {
case AF_INET:
- if (sel->prefixlen_d != 32 ||
- sel->prefixlen_s != 32)
+ if (sel->prefixlen_d < dbits ||
+ sel->prefixlen_s < sbits)
return hmask + 1;
- h = __xfrm4_daddr_saddr_hash(daddr, saddr);
+ h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits);
break;
case AF_INET6:
- if (sel->prefixlen_d != 128 ||
- sel->prefixlen_s != 128)
+ if (sel->prefixlen_d < dbits ||
+ sel->prefixlen_s < sbits)
return hmask + 1;
- h = __xfrm6_daddr_saddr_hash(daddr, saddr);
+ h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits);
break;
}
h ^= (h >> 16);
@@ -113,17 +167,19 @@ static inline unsigned int __sel_hash(const struct xfrm_selector *sel,
static inline unsigned int __addr_hash(const xfrm_address_t *daddr,
const xfrm_address_t *saddr,
- unsigned short family, unsigned int hmask)
+ unsigned short family,
+ unsigned int hmask,
+ u8 dbits, u8 sbits)
{
unsigned int h = 0;
switch (family) {
case AF_INET:
- h = __xfrm4_daddr_saddr_hash(daddr, saddr);
+ h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits);
break;
case AF_INET6:
- h = __xfrm6_daddr_saddr_hash(daddr, saddr);
+ h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits);
break;
}
h ^= (h >> 16);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index beeed60..e6ff7b4 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -344,12 +344,39 @@ static inline unsigned int idx_hash(struct net *net, u32 index)
return __idx_hash(index, net->xfrm.policy_idx_hmask);
}
+/* calculate policy hash thresholds */
+static void __get_hash_thresh(struct net *net,
+ unsigned short family, int dir,
+ u8 *dbits, u8 *sbits)
+{
+ switch (family) {
+ case AF_INET:
+ *dbits = net->xfrm.policy_bydst[dir].dbits4;
+ *sbits = net->xfrm.policy_bydst[dir].sbits4;
+ break;
+
+ case AF_INET6:
+ *dbits = net->xfrm.policy_bydst[dir].dbits6;
+ *sbits = net->xfrm.policy_bydst[dir].sbits6;
+ break;
+
+ default:
+ *dbits = 0;
+ *sbits = 0;
+ }
+}
+
static struct hlist_head *policy_hash_bysel(struct net *net,
const struct xfrm_selector *sel,
unsigned short family, int dir)
{
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
- unsigned int hash = __sel_hash(sel, family, hmask);
+ unsigned int hash;
+ u8 dbits;
+ u8 sbits;
+
+ __get_hash_thresh(net, family, dir, &dbits, &sbits);
+ hash = __sel_hash(sel, family, hmask, dbits, sbits);
return (hash == hmask + 1 ?
&net->xfrm.policy_inexact[dir] :
@@ -362,25 +389,35 @@ static struct hlist_head *policy_hash_direct(struct net *net,
unsigned short family, int dir)
{
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
- unsigned int hash = __addr_hash(daddr, saddr, family, hmask);
+ unsigned int hash;
+ u8 dbits;
+ u8 sbits;
+
+ __get_hash_thresh(net, family, dir, &dbits, &sbits);
+ hash = __addr_hash(daddr, saddr, family, hmask, dbits, sbits);
return net->xfrm.policy_bydst[dir].table + hash;
}
-static void xfrm_dst_hash_transfer(struct hlist_head *list,
+static void xfrm_dst_hash_transfer(struct net *net,
+ struct hlist_head *list,
struct hlist_head *ndsttable,
- unsigned int nhashmask)
+ unsigned int nhashmask,
+ int dir)
{
struct hlist_node *tmp, *entry0 = NULL;
struct xfrm_policy *pol;
unsigned int h0 = 0;
+ u8 dbits;
+ u8 sbits;
redo:
hlist_for_each_entry_safe(pol, tmp, list, bydst) {
unsigned int h;
+ __get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
- pol->family, nhashmask);
+ pol->family, nhashmask, dbits, sbits);
if (!entry0) {
hlist_del(&pol->bydst);
hlist_add_head(&pol->bydst, ndsttable+h);
@@ -434,7 +471,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
write_lock_bh(&net->xfrm.xfrm_policy_lock);
for (i = hmask; i >= 0; i--)
- xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
+ xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir);
net->xfrm.policy_bydst[dir].table = ndst;
net->xfrm.policy_bydst[dir].hmask = nhashmask;
@@ -2830,6 +2867,10 @@ static int __net_init xfrm_policy_init(struct net *net)
if (!htab->table)
goto out_bydst;
htab->hmask = hmask;
+ htab->dbits4 = 32;
+ htab->sbits4 = 32;
+ htab->dbits6 = 128;
+ htab->sbits6 = 128;
}
INIT_LIST_HEAD(&net->xfrm.policy_all);
--
1.9.1
^ permalink raw reply related
* [PATCH 4/4] ipsec: Remove obsolete MAX_AH_AUTH_LEN
From: Steffen Klassert @ 2014-09-25 9:10 UTC (permalink / raw)
To: David Miller; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <1411636225-4433-1-git-send-email-steffen.klassert@secunet.com>
From: Herbert Xu <herbert@gondor.apana.org.au>
While tracking down the MAX_AH_AUTH_LEN crash in an old kernel
I thought that this limit was rather arbitrary and we should
just get rid of it.
In fact it seems that we've already done all the work needed
to remove it apart from actually removing it. This limit was
there in order to limit stack usage. Since we've already
switched over to allocating scratch space using kmalloc, there
is no longer any need to limit the authentication length.
This patch kills all references to it, including the BUG_ONs
that led me here.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
include/net/ah.h | 3 ---
net/ipv4/ah4.c | 2 --
net/ipv6/ah6.c | 2 --
net/xfrm/xfrm_user.c | 3 +--
4 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/include/net/ah.h b/include/net/ah.h
index ca95b98..4e2dfa4 100644
--- a/include/net/ah.h
+++ b/include/net/ah.h
@@ -3,9 +3,6 @@
#include <linux/skbuff.h>
-/* This is the maximum truncated ICV length that we know of. */
-#define MAX_AH_AUTH_LEN 64
-
struct crypto_ahash;
struct ah_data {
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index a2afa89..ac9a32e 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -505,8 +505,6 @@ static int ah_init_state(struct xfrm_state *x)
ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;
- BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
-
if (x->props.flags & XFRM_STATE_ALIGN4)
x->props.header_len = XFRM_ALIGN4(sizeof(struct ip_auth_hdr) +
ahp->icv_trunc_len);
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index fcffd4e..6d16eb0 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -713,8 +713,6 @@ static int ah6_init_state(struct xfrm_state *x)
ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;
- BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
-
x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
ahp->icv_trunc_len);
switch (x->props.mode) {
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index eaf8a8f..e812e98 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -333,8 +333,7 @@ static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
if (!algo)
return -ENOSYS;
- if ((ualg->alg_trunc_len / 8) > MAX_AH_AUTH_LEN ||
- ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
+ if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
return -EINVAL;
*props = algo->desc.sadb_alg_id;
--
1.9.1
^ permalink raw reply related
* [PATCH 3/4] xfrm: configure policy hash table thresholds by netlink
From: Steffen Klassert @ 2014-09-25 9:10 UTC (permalink / raw)
To: David Miller; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <1411636225-4433-1-git-send-email-steffen.klassert@secunet.com>
From: Christophe Gouault <christophe.gouault@6wind.com>
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
include/net/netns/xfrm.h | 10 ++++++
include/net/xfrm.h | 1 +
include/uapi/linux/xfrm.h | 7 ++++
net/xfrm/xfrm_policy.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++
net/xfrm/xfrm_user.c | 80 +++++++++++++++++++++++++++++++++++++++++--
5 files changed, 182 insertions(+), 3 deletions(-)
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 41902a8..9da7982 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -19,6 +19,15 @@ struct xfrm_policy_hash {
u8 sbits6;
};
+struct xfrm_policy_hthresh {
+ struct work_struct work;
+ seqlock_t lock;
+ u8 lbits4;
+ u8 rbits4;
+ u8 lbits6;
+ u8 rbits6;
+};
+
struct netns_xfrm {
struct list_head state_all;
/*
@@ -45,6 +54,7 @@ struct netns_xfrm {
struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2];
unsigned int policy_count[XFRM_POLICY_MAX * 2];
struct work_struct policy_hash_work;
+ struct xfrm_policy_hthresh policy_hthresh;
struct sock *nlsk;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 721e9c3..dc4865e 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1591,6 +1591,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir,
u32 id, int delete, int *err);
int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
+void xfrm_policy_hash_rebuild(struct net *net);
u32 xfrm_get_acqseq(void);
int verify_spi_info(u8 proto, u32 min, u32 max);
int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h
index 25e5dd9..02d5125 100644
--- a/include/uapi/linux/xfrm.h
+++ b/include/uapi/linux/xfrm.h
@@ -328,6 +328,8 @@ enum xfrm_spdattr_type_t {
XFRMA_SPD_UNSPEC,
XFRMA_SPD_INFO,
XFRMA_SPD_HINFO,
+ XFRMA_SPD_IPV4_HTHRESH,
+ XFRMA_SPD_IPV6_HTHRESH,
__XFRMA_SPD_MAX
#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
@@ -347,6 +349,11 @@ struct xfrmu_spdhinfo {
__u32 spdhmcnt;
};
+struct xfrmu_spdhthresh {
+ __u8 lbits;
+ __u8 rbits;
+};
+
struct xfrm_usersa_info {
struct xfrm_selector sel;
struct xfrm_id id;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e6ff7b4..55bcb86 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -566,6 +566,86 @@ static void xfrm_hash_resize(struct work_struct *work)
mutex_unlock(&hash_resize_mutex);
}
+static void xfrm_hash_rebuild(struct work_struct *work)
+{
+ struct net *net = container_of(work, struct net,
+ xfrm.policy_hthresh.work);
+ unsigned int hmask;
+ struct xfrm_policy *pol;
+ struct xfrm_policy *policy;
+ struct hlist_head *chain;
+ struct hlist_head *odst;
+ struct hlist_node *newpos;
+ int i;
+ int dir;
+ unsigned seq;
+ u8 lbits4, rbits4, lbits6, rbits6;
+
+ mutex_lock(&hash_resize_mutex);
+
+ /* read selector prefixlen thresholds */
+ do {
+ seq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
+
+ lbits4 = net->xfrm.policy_hthresh.lbits4;
+ rbits4 = net->xfrm.policy_hthresh.rbits4;
+ lbits6 = net->xfrm.policy_hthresh.lbits6;
+ rbits6 = net->xfrm.policy_hthresh.rbits6;
+ } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq));
+
+ write_lock_bh(&net->xfrm.xfrm_policy_lock);
+
+ /* reset the bydst and inexact table in all directions */
+ for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
+ INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
+ hmask = net->xfrm.policy_bydst[dir].hmask;
+ odst = net->xfrm.policy_bydst[dir].table;
+ for (i = hmask; i >= 0; i--)
+ INIT_HLIST_HEAD(odst + i);
+ if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
+ /* dir out => dst = remote, src = local */
+ net->xfrm.policy_bydst[dir].dbits4 = rbits4;
+ net->xfrm.policy_bydst[dir].sbits4 = lbits4;
+ net->xfrm.policy_bydst[dir].dbits6 = rbits6;
+ net->xfrm.policy_bydst[dir].sbits6 = lbits6;
+ } else {
+ /* dir in/fwd => dst = local, src = remote */
+ net->xfrm.policy_bydst[dir].dbits4 = lbits4;
+ net->xfrm.policy_bydst[dir].sbits4 = rbits4;
+ net->xfrm.policy_bydst[dir].dbits6 = lbits6;
+ net->xfrm.policy_bydst[dir].sbits6 = rbits6;
+ }
+ }
+
+ /* re-insert all policies by order of creation */
+ list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
+ newpos = NULL;
+ chain = policy_hash_bysel(net, &policy->selector,
+ policy->family,
+ xfrm_policy_id2dir(policy->index));
+ hlist_for_each_entry(pol, chain, bydst) {
+ if (policy->priority >= pol->priority)
+ newpos = &pol->bydst;
+ else
+ break;
+ }
+ if (newpos)
+ hlist_add_behind(&policy->bydst, newpos);
+ else
+ hlist_add_head(&policy->bydst, chain);
+ }
+
+ write_unlock_bh(&net->xfrm.xfrm_policy_lock);
+
+ mutex_unlock(&hash_resize_mutex);
+}
+
+void xfrm_policy_hash_rebuild(struct net *net)
+{
+ schedule_work(&net->xfrm.policy_hthresh.work);
+}
+EXPORT_SYMBOL(xfrm_policy_hash_rebuild);
+
/* Generate new index... KAME seems to generate them ordered by cost
* of an absolute inpredictability of ordering of rules. This will not pass. */
static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
@@ -2872,9 +2952,16 @@ static int __net_init xfrm_policy_init(struct net *net)
htab->dbits6 = 128;
htab->sbits6 = 128;
}
+ net->xfrm.policy_hthresh.lbits4 = 32;
+ net->xfrm.policy_hthresh.rbits4 = 32;
+ net->xfrm.policy_hthresh.lbits6 = 128;
+ net->xfrm.policy_hthresh.rbits6 = 128;
+
+ seqlock_init(&net->xfrm.policy_hthresh.lock);
INIT_LIST_HEAD(&net->xfrm.policy_all);
INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
+ INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild);
if (net_eq(net, &init_net))
register_netdevice_notifier(&xfrm_dev_notifier);
return 0;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index d4db6eb..eaf8a8f 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -964,7 +964,9 @@ static inline size_t xfrm_spdinfo_msgsize(void)
{
return NLMSG_ALIGN(4)
+ nla_total_size(sizeof(struct xfrmu_spdinfo))
- + nla_total_size(sizeof(struct xfrmu_spdhinfo));
+ + nla_total_size(sizeof(struct xfrmu_spdhinfo))
+ + nla_total_size(sizeof(struct xfrmu_spdhthresh))
+ + nla_total_size(sizeof(struct xfrmu_spdhthresh));
}
static int build_spdinfo(struct sk_buff *skb, struct net *net,
@@ -973,9 +975,11 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
struct xfrmk_spdinfo si;
struct xfrmu_spdinfo spc;
struct xfrmu_spdhinfo sph;
+ struct xfrmu_spdhthresh spt4, spt6;
struct nlmsghdr *nlh;
int err;
u32 *f;
+ unsigned lseq;
nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
if (nlh == NULL) /* shouldn't really happen ... */
@@ -993,9 +997,22 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
sph.spdhcnt = si.spdhcnt;
sph.spdhmcnt = si.spdhmcnt;
+ do {
+ lseq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
+
+ spt4.lbits = net->xfrm.policy_hthresh.lbits4;
+ spt4.rbits = net->xfrm.policy_hthresh.rbits4;
+ spt6.lbits = net->xfrm.policy_hthresh.lbits6;
+ spt6.rbits = net->xfrm.policy_hthresh.rbits6;
+ } while (read_seqretry(&net->xfrm.policy_hthresh.lock, lseq));
+
err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
if (!err)
err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
+ if (!err)
+ err = nla_put(skb, XFRMA_SPD_IPV4_HTHRESH, sizeof(spt4), &spt4);
+ if (!err)
+ err = nla_put(skb, XFRMA_SPD_IPV6_HTHRESH, sizeof(spt6), &spt6);
if (err) {
nlmsg_cancel(skb, nlh);
return err;
@@ -1004,6 +1021,51 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
return nlmsg_end(skb, nlh);
}
+static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct nlattr **attrs)
+{
+ struct net *net = sock_net(skb->sk);
+ struct xfrmu_spdhthresh *thresh4 = NULL;
+ struct xfrmu_spdhthresh *thresh6 = NULL;
+
+ /* selector prefixlen thresholds to hash policies */
+ if (attrs[XFRMA_SPD_IPV4_HTHRESH]) {
+ struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH];
+
+ if (nla_len(rta) < sizeof(*thresh4))
+ return -EINVAL;
+ thresh4 = nla_data(rta);
+ if (thresh4->lbits > 32 || thresh4->rbits > 32)
+ return -EINVAL;
+ }
+ if (attrs[XFRMA_SPD_IPV6_HTHRESH]) {
+ struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH];
+
+ if (nla_len(rta) < sizeof(*thresh6))
+ return -EINVAL;
+ thresh6 = nla_data(rta);
+ if (thresh6->lbits > 128 || thresh6->rbits > 128)
+ return -EINVAL;
+ }
+
+ if (thresh4 || thresh6) {
+ write_seqlock(&net->xfrm.policy_hthresh.lock);
+ if (thresh4) {
+ net->xfrm.policy_hthresh.lbits4 = thresh4->lbits;
+ net->xfrm.policy_hthresh.rbits4 = thresh4->rbits;
+ }
+ if (thresh6) {
+ net->xfrm.policy_hthresh.lbits6 = thresh6->lbits;
+ net->xfrm.policy_hthresh.rbits6 = thresh6->rbits;
+ }
+ write_sequnlock(&net->xfrm.policy_hthresh.lock);
+
+ xfrm_policy_hash_rebuild(net);
+ }
+
+ return 0;
+}
+
static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
{
@@ -2274,6 +2336,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),
+ [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
};
@@ -2308,10 +2371,17 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
[XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) },
};
+static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
+ [XFRMA_SPD_IPV4_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
+ [XFRMA_SPD_IPV6_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
+};
+
static const struct xfrm_link {
int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
int (*dump)(struct sk_buff *, struct netlink_callback *);
int (*done)(struct netlink_callback *);
+ const struct nla_policy *nla_pol;
+ int nla_max;
} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
[XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
@@ -2335,6 +2405,9 @@ static const struct xfrm_link {
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },
+ [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_set_spdinfo,
+ .nla_pol = xfrma_spd_policy,
+ .nla_max = XFRMA_SPD_MAX },
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
};
@@ -2371,8 +2444,9 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
}
- err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,
- xfrma_policy);
+ err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs,
+ link->nla_max ? : XFRMA_MAX,
+ link->nla_pol ? : xfrma_policy);
if (err < 0)
return err;
--
1.9.1
^ permalink raw reply related
* pull request (net-next): ipsec-next 2014-09-25
From: Steffen Klassert @ 2014-09-25 9:10 UTC (permalink / raw)
To: David Miller; +Cc: Herbert Xu, Steffen Klassert, netdev
1) Remove useless hash_resize_mutex in xfrm_hash_resize().
This mutex is used only there, but xfrm_hash_resize()
can't be called concurrently at all. From Ying Xue.
2) Extend policy hashing to prefixed policies based on
prefix lenght thresholds. From Christophe Gouault.
3) Make the policy hash table thresholds configurable
via netlink. From Christophe Gouault.
4) Remove the maximum authentication length for AH.
This was needed to limit stack usage. We switched
already to allocate space, so no need to keep the
limit. From Herbert Xu.
Please pull or let me know if there are problems.
Thanks!
The following changes since commit a3d1214688d5259a200414def4d38f1e4531febd:
neigh: document gc_thresh2 (2014-08-25 17:37:10 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git master
for you to fetch changes up to 689f1c9de2abbd76fda224d12cea5f43568a4335:
ipsec: Remove obsolete MAX_AH_AUTH_LEN (2014-09-18 10:54:36 +0200)
----------------------------------------------------------------
Christophe Gouault (2):
xfrm: hash prefixed policies based on preflen thresholds
xfrm: configure policy hash table thresholds by netlink
Herbert Xu (1):
ipsec: Remove obsolete MAX_AH_AUTH_LEN
Ying Xue (1):
xfrm: remove useless hash_resize_mutex locks
include/net/ah.h | 3 -
include/net/netns/xfrm.h | 14 +++++
include/net/xfrm.h | 1 +
include/uapi/linux/xfrm.h | 7 +++
net/ipv4/ah4.c | 2 -
net/ipv6/ah6.c | 2 -
net/xfrm/xfrm_hash.h | 76 +++++++++++++++++++++----
net/xfrm/xfrm_policy.c | 140 ++++++++++++++++++++++++++++++++++++++++++++--
net/xfrm/xfrm_state.c | 13 +----
net/xfrm/xfrm_user.c | 83 +++++++++++++++++++++++++--
10 files changed, 303 insertions(+), 38 deletions(-)
^ permalink raw reply
* [PATCH 1/4] xfrm: remove useless hash_resize_mutex locks
From: Steffen Klassert @ 2014-09-25 9:10 UTC (permalink / raw)
To: David Miller; +Cc: Herbert Xu, Steffen Klassert, netdev
In-Reply-To: <1411636225-4433-1-git-send-email-steffen.klassert@secunet.com>
From: Ying Xue <ying.xue@windriver.com>
In xfrm_state.c, hash_resize_mutex is defined as a local variable
and only used in xfrm_hash_resize() which is declared as a work
handler of xfrm.state_hash_work. But when the xfrm.state_hash_work
work is put in the global workqueue(system_wq) with schedule_work(),
the work will be really inserted in the global workqueue if it was
not already queued, otherwise, it is still left in the same position
on the the global workqueue. This means the xfrm_hash_resize() work
handler is only executed once at any time no matter how many times
its work is scheduled, that is, xfrm_hash_resize() is not called
concurrently at all, so hash_resize_mutex is redundant for us.
Cc: Christophe Gouault <christophe.gouault@6wind.com>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Ying Xue <ying.xue@windriver.com>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_state.c | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 0ab5413..de971b6 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -97,8 +97,6 @@ static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
}
-static DEFINE_MUTEX(hash_resize_mutex);
-
static void xfrm_hash_resize(struct work_struct *work)
{
struct net *net = container_of(work, struct net, xfrm.state_hash_work);
@@ -107,22 +105,20 @@ static void xfrm_hash_resize(struct work_struct *work)
unsigned int nhashmask, ohashmask;
int i;
- mutex_lock(&hash_resize_mutex);
-
nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
ndst = xfrm_hash_alloc(nsize);
if (!ndst)
- goto out_unlock;
+ return;
nsrc = xfrm_hash_alloc(nsize);
if (!nsrc) {
xfrm_hash_free(ndst, nsize);
- goto out_unlock;
+ return;
}
nspi = xfrm_hash_alloc(nsize);
if (!nspi) {
xfrm_hash_free(ndst, nsize);
xfrm_hash_free(nsrc, nsize);
- goto out_unlock;
+ return;
}
spin_lock_bh(&net->xfrm.xfrm_state_lock);
@@ -148,9 +144,6 @@ static void xfrm_hash_resize(struct work_struct *work)
xfrm_hash_free(odst, osize);
xfrm_hash_free(osrc, osize);
xfrm_hash_free(ospi, osize);
-
-out_unlock:
- mutex_unlock(&hash_resize_mutex);
}
static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
--
1.9.1
^ permalink raw reply related
* Re: [RFC PATCH net-next v2 0/5] netns: allow to identify peer netns
From: Nicolas Dichtel @ 2014-09-25 8:53 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Andy Lutomirski, Stephen Hemminger, Eric W. Biederman,
linux-api-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, David Miller
In-Reply-To: <CAHA+R7Ot2kLHb+ne5AW3bFNc87qkFOiEHEyDh9sFrsHqXgrY3g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Le 24/09/2014 18:45, Cong Wang a écrit :
> On Wed, Sep 24, 2014 at 9:27 AM, Nicolas Dichtel
> <nicolas.dichtel@6wind.com> wrote:
>> Now informations got with 'ip link' are wrong and incomplete:
>> - the link dev is now tunl0 instead of eth0, because we only got an
>> ifindex
>> from the kernel without any netns informations.
>
> This is not new, macvlan has the same problem. This is why I said
> it is mostly a display problem, maybe just mark the ifindex as -1 or
> something when it is not in this netns. At least I don't expect the inner
> netns know anything outside, and I don't think I am the only one using
> netns in this way.
I understand your point but there is several use of netns. Netns can be used
also to instantiate virtual routers. In this case, administrators or daemons
need to be able to monitor and dump the configuration on all netns
(particularly beeing able to identify fully x-netns interfaces). We start to
discuss this in one of the two thread pointed in my cover letter and get the
conclusion that checking user ns is a good way to know if an id should be
disclosed or not for a peer netns.
Can you describe your use case?
>
>> - the encapsulation addresses are not part of this netns but the user
>> doesn't
>> known that (still because netns info is missing). These IPv4 addresses
>> may
>> exist into this netns.
>
> I don't remember your x-netns code, but we have two choices:
>
> 1) Lookup the route of the netns which it is in
>
> If the address is not available in this netns, it will fail, this is expected
> since tunnel device is not a pure L2 device. Or maybe just fail
> early when we move it.
>
> 2) Lookup the route of the netns where it was created
>
> Transparent for upper layer, but as you said, the outer address is not
> available in this netns therefore hard to display. Just hiding this information
> doesn't seem wrong to me.
Your assumption here is that all dameons were started before the tunnel was
created. But this is not true, a daemon may be started later. Another case is
when a daemon crash: we need to be able to restart it and it should be able to
recover all needed information.
>
>
>> - it's not possible to create the same netdevice with these infos.
>>
>
> This is expected, because after all you are already in a different netns.
>
A different netns only means a different network stack, not a different user ns
or mount ns or PID ns, ...
If you only play with netns, you may want to monitor all activies in all netns
(this is already possible) and beeing able to link information between netns
(this is what I'm trying to solve).
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply
* Re: [RFC PATCH net-next v2 0/5] netns: allow to identify peer netns
From: Nicolas Dichtel @ 2014-09-25 8:53 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Andy Lutomirski, Stephen Hemminger, Eric W. Biederman,
linux-api-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, David Miller
In-Reply-To: <CAHA+R7MM04ew=J8sHfSQERwoCAgEDfrGgtgRORqs3ePgtjVYWg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Le 24/09/2014 18:48, Cong Wang a écrit :
> On Wed, Sep 24, 2014 at 9:31 AM, Nicolas Dichtel
> <nicolas.dichtel@6wind.com> wrote:
>>> I think in this case your ID's are still available, but aren't you
>>> providing a new way
>>> for the inner netns device to escape which we are trying to avoid?
>>
>> It's why the ids depend on user ns. Only if user ns are the same we allow to
>> get an id for a peer netns.
>
> Too late, userns is relatively new, relying on it breaks our existing
> assumption.
>
I don't get your point. netns has been added in kernel after user ns:
acce292c82d4 user namespace: add the framework => 2.6.23
5f256becd868 [NET]: Basic network namespace infrastructure. => 2.6.24
In the kernel, each netns is linked with a user ns.
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply
* Re: [net-next PATCH 1/1 V4] qdisc: bulk dequeue support for qdiscs with TCQ_F_ONETXQUEUE
From: Jesper Dangaard Brouer @ 2014-09-25 8:25 UTC (permalink / raw)
To: Jamal Hadi Salim
Cc: Eric Dumazet, netdev, therbert, David S. Miller, Alexander Duyck,
toke, Florian Westphal, Dave Taht, John Fastabend,
Daniel Borkmann, Hannes Frederic Sowa, brouer
In-Reply-To: <54234225.5000503@mojatatu.com>
On Wed, 24 Sep 2014 18:13:57 -0400
Jamal Hadi Salim <jhs@mojatatu.com> wrote:
> On 09/24/14 13:58, Jesper Dangaard Brouer wrote:
> > On Wed, 24 Sep 2014 10:23:15 -0700
> > Eric Dumazet <eric.dumazet@gmail.com> wrote:
> >
>
> >
> >> pktgen is nice, but do not represent the majority of the traffic we send
> >> from high performance host where we want this bulk dequeue thing ;)
> >
> > This patch is actually targetted towards more normal use-cases.
> > Pktgen cannot even use this work, as it bypass the qdisc layer...
>
> When you post these patches - can you please also post basic performance
> numbers? You dont have to show improvement if it is hard for bulking
> to kick in, but you need to show no harm in at least latency for the
> general use case (i.e not pktgen maybe forwarding activity or something
> sourced from tcp).
I've done measurements with netperf-wrapper:
http://netoptimizer.blogspot.dk/2014/09/mini-tutorial-for-netperf-wrapper-setup.html
I have already previously posted my measurements here:
http://people.netfilter.org/hawk/qdisc/
http://people.netfilter.org/hawk/qdisc/measure01/
http://people.netfilter.org/hawk/qdisc/experiment01/
Please, see my previous mail where I described each graph.
The above measurements is for 10Gbit/s, but I've also done measurements
on 1Gbit/s driver igb, and 10Mbit/s by forcing igb to use 10Mbit/s.
Those results I forgot upload (and I cannot upload them right now, as
I'm currently in Switzerland).
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* Re: [RFC PATCH net-next v2 0/5] netns: allow to identify peer netns
From: Nicolas Dichtel @ 2014-09-25 7:54 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Network Development, Linux Containers,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux API,
David S. Miller, Eric W. Biederman, Stephen Hemminger,
Andrew Morton
In-Reply-To: <CALCETrXMkV_1XR2mXOoO_2_vpB=6cPbWAAOhPFhPbDa_1P+zxw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Le 24/09/2014 19:05, Andy Lutomirski a écrit :
> On Wed, Sep 24, 2014 at 2:31 AM, Nicolas Dichtel
> <nicolas.dichtel-pdR9zngts4EAvxtiuMwx3w@public.gmane.org> wrote:
>> Le 23/09/2014 21:26, Andy Lutomirski a écrit :
>>
>>> On Tue, Sep 23, 2014 at 6:20 AM, Nicolas Dichtel
>>> <nicolas.dichtel-pdR9zngts4EAvxtiuMwx3w@public.gmane.org> wrote:
>>>>
>>>> The goal of this serie is to be able to multicast netlink messages with
>>>> an
>>>> attribute that identify a peer netns.
>>>> This is needed by the userland to interpret some informations contained
>>>> in
>>>> netlink messages (like IFLA_LINK value, but also some other attributes in
>>>> case
>>>> of x-netns netdevice (see also
>>>> http://thread.gmane.org/gmane.linux.network/315933/focus=316064 and
>>>> http://thread.gmane.org/gmane.linux.kernel.containers/28301/focus=4239)).
>>>>
>>>> Ids are stored in the parent user namespace. These ids are valid only
>>>> inside
>>>> this user namespace. The user can retrieve these ids via a new netlink
>>>> messages,
>>>> but only if peer netns are in the same user namespace.
>>>
>>>
>>> What about the parent / ancestors of the owning userns? Can processes
>>> in those usernses see any form of netns id?
>>
>> With this serie no. I'm not sure if ancestors really needs to be able to
>> get these ids. What is your opinion?
>
> I might be missing some consideration here, but I would hope that ip
> link would work correctly if I have a veth interface shared with a
> netns that's in a child userns.
No, you're right. Will send a v3.
^ permalink raw reply
* Re: [PATCH net] sparc: bpf_jit: fix loads from negative offsets
From: Alexei Starovoitov @ 2014-09-25 6:30 UTC (permalink / raw)
To: David Miller; +Cc: Network Development
In-Reply-To: <20140924.150837.1990547182303548810.davem@davemloft.net>
On Wed, Sep 24, 2014 at 12:08 PM, David Miller <davem@davemloft.net> wrote:
>
> BTW, there is a trick to load arbitrary negative 32-bit constants sign
> extended to 64-bit, in just two instructions:
>
> sethi %(~value), reg
> xor reg, ~(0x400 | (value & 0x3ff)), reg
>
> Or something like that, it's been a while. GCC knows how to emit
> that sequence too.
nice, that's a neat trick.
gcc computes it as:
sethi %(~value), reg
xor reg, -0x400 | (value & 0x3ff), reg
and llvm as:
sethi %(~value), reg
xor reg, ~(~value & 0x3ff), reg
both are equivalent. I'll try to teach JIT to emit this.
Thanks!
^ permalink raw reply
* Re: [PATCH/RFC repost 4/8] datapath: execution of select group action
From: Simon Horman @ 2014-09-25 4:43 UTC (permalink / raw)
To: Thomas Graf; +Cc: dev, netdev, Pravin Shelar, Jesse Gross
In-Reply-To: <20140924081942.GB24298@casper.infradead.org>
On Wed, Sep 24, 2014 at 09:19:42AM +0100, Thomas Graf wrote:
> On 09/24/14 at 03:01pm, Simon Horman wrote:
> > > > + /* Only possible type of attributes is OVS_SELECT_GROUP_ATTR_BUCKET */
> > > > + for (bucket = nla_data(attr), rem = nla_len(attr); rem > 0;
> > > > + bucket = nla_next(bucket, &rem)) {
> > > > + uint16_t weight = bucket_weight(bucket);
> > >
> > > I think we should validate only once when we copy then assume it is
> > > correct.
>
> > That is the intention of this code, is it doing something else?
>
> I must have treated the BUG_ON as validation when I wrote that
> comment ;-)
>
> > Nice idea. I think that would work out quite well.
> >
> > The main question for me would be where to store such a table,
> > which comes back to my remark above about more storing a more
> > efficient efficient form of the action.
>
> I had the same issue when working on zone support for the
> conntrack action that is in the works. It needs to keep a ref to
> a ct template which is registered with the conntrack engine. I
> ended up converting the Netlink attributes to a struct and storing
> that in an attribute in sf_acts then converting it back.
>
> You can find the WIP code in the following branch:
> https://github.com/tgraf/ovs/tree/nat
>
> datapath: Use central function to free sw_flow_actions
> RFC: Add support for connection tracking.
> datapath: Add zone support
Thanks, I think something along those lines could work out
quite well for a select group action.
> > > Do we need a recursion limit here?
> >
> > I believe that is already handled by the depth check that occurs
> > when the actions are copied.
>
> Right, I can see it now. Thanks.
>
^ permalink raw reply
* Re: [PATCH/RFC repost 5/8] datapath: Move last_action() helper to datapath.h
From: Simon Horman @ 2014-09-25 4:42 UTC (permalink / raw)
To: Thomas Graf; +Cc: dev, netdev, Pravin Shelar, Jesse Gross
In-Reply-To: <20140924082015.GC24298@casper.infradead.org>
On Wed, Sep 24, 2014 at 09:20:15AM +0100, Thomas Graf wrote:
> On 09/24/14 at 03:00pm, Simon Horman wrote:
> > On Fri, Sep 19, 2014 at 03:06:38PM +0100, Thomas Graf wrote:
> > > Can we rename & move this to <net/netlink.h> instead?
> >
> > Sure, how about nla_is_last()?
>
> Sounds great
Done. I have posted the result as a patch separate to the select group series.
^ permalink raw reply
* linux-next: manual merge of the net-next tree with the arm-soc tree
From: Stephen Rothwell @ 2014-09-25 2:58 UTC (permalink / raw)
To: David Miller, netdev, Olof Johansson, Arnd Bergmann,
linux-arm-kernel
Cc: linux-next, linux-kernel, Romain Perier, Heiko Stuebner
[-- Attachment #1: Type: text/plain, Size: 3487 bytes --]
Hi all,
Today's linux-next merge of the net-next tree got conflicts in
arch/arm/boot/dts/rk3188.dtsi and arch/arm/boot/dts/rk3xxx.dtsi between
commits fd14e6f9b461 ("ARM: dts: rockchip: add dwc2 controllers for
rk3066 and rk3188") and 4ff4ae1258a9 ("ARM: dts: rockchip: add emmc
nodes for rk3066 and rk3188") from the arm-soc tree and commit
18ec91e1947f ("ARM: dts: Add emac nodes to the rk3188 device tree")
from the net-next tree.
I fixed it up (see below) and can carry the fix as necessary (no action
is required).
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc arch/arm/boot/dts/rk3188.dtsi
index 82732f5249b2,7f25bc51f2ee..000000000000
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@@ -147,27 -147,24 +147,45 @@@
bias-disable;
};
+ emmc {
+ emmc_clk: emmc-clk {
+ rockchip,pins = <RK_GPIO0 24 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ emmc_cmd: emmc-cmd {
+ rockchip,pins = <RK_GPIO0 26 RK_FUNC_2 &pcfg_pull_up>;
+ };
+
+ emmc_rst: emmc-rst {
+ rockchip,pins = <RK_GPIO0 27 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ /*
+ * The data pins are shared between nandc and emmc and
+ * not accessible through pinctrl. Also they should've
+ * been already set correctly by firmware, as
+ * flash/emmc is the boot-device.
+ */
+ };
+
+ emac {
+ emac_xfer: emac-xfer {
+ rockchip,pins = <RK_GPIO3 16 RK_FUNC_2 &pcfg_pull_none>, /* tx_en */
+ <RK_GPIO3 17 RK_FUNC_2 &pcfg_pull_none>, /* txd1 */
+ <RK_GPIO3 18 RK_FUNC_2 &pcfg_pull_none>, /* txd0 */
+ <RK_GPIO3 19 RK_FUNC_2 &pcfg_pull_none>, /* rxd0 */
+ <RK_GPIO3 20 RK_FUNC_2 &pcfg_pull_none>, /* rxd1 */
+ <RK_GPIO3 21 RK_FUNC_2 &pcfg_pull_none>, /* mac_clk */
+ <RK_GPIO3 22 RK_FUNC_2 &pcfg_pull_none>, /* rx_err */
+ <RK_GPIO3 23 RK_FUNC_2 &pcfg_pull_none>; /* crs_dvalid */
+ };
+
+ emac_mdio: emac-mdio {
+ rockchip,pins = <RK_GPIO3 24 RK_FUNC_2 &pcfg_pull_none>,
+ <RK_GPIO3 25 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
i2c0 {
i2c0_xfer: i2c0-xfer {
rockchip,pins = <RK_GPIO1 24 RK_FUNC_1 &pcfg_pull_none>,
diff --cc arch/arm/boot/dts/rk3xxx.dtsi
index 7332d12eb565,208b1df6bcb0..000000000000
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@@ -134,24 -91,23 +134,41 @@@
status = "disabled";
};
+ usb_otg: usb@10180000 {
+ compatible = "rockchip,rk3066-usb", "snps,dwc2";
+ reg = <0x10180000 0x40000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_OTG0>;
+ clock-names = "otg";
+ status = "disabled";
+ };
+
+ usb_host: usb@101c0000 {
+ compatible = "snps,dwc2";
+ reg = <0x101c0000 0x40000>;
+ interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_OTG1>;
+ clock-names = "otg";
+ status = "disabled";
+ };
+
+ emac: ethernet@10204000 {
+ compatible = "snps,arc-emac";
+ reg = <0x10204000 0x3c>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rockchip,grf = <&grf>;
+
+ clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>;
+ clock-names = "hclk", "macref";
+ max-speed = <100>;
+ phy-mode = "rmii";
+
+ status = "disabled";
+ };
+
mmc0: dwmmc@10214000 {
compatible = "rockchip,rk2928-dw-mshc";
reg = <0x10214000 0x1000>;
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [net-next PATCH 1/1 V4] qdisc: bulk dequeue support for qdiscs with TCQ_F_ONETXQUEUE
From: Dave Taht @ 2014-09-25 2:58 UTC (permalink / raw)
To: Tom Herbert
Cc: Eric Dumazet, Jesper Dangaard Brouer, Linux Netdev List,
David S. Miller, Alexander Duyck,
Toke Høiland-Jørgensen, Florian Westphal,
Jamal Hadi Salim, John Fastabend, Daniel Borkmann,
Hannes Frederic Sowa
In-Reply-To: <CA+mtBx-3HTHvodGXJ_zHArbeLtbeTc3XUc_CZr4CgfvU9BiDAA@mail.gmail.com>
On Wed, Sep 24, 2014 at 7:38 PM, Tom Herbert <therbert@google.com> wrote:
> On Wed, Sep 24, 2014 at 7:12 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
>> On Wed, 2014-09-24 at 12:22 -0700, Eric Dumazet wrote:
>>> On Wed, 2014-09-24 at 11:34 -0700, Tom Herbert wrote:
>>> > >
>>> > I believe drivers typically use skb->len for BQL tracking. Since
>>> > bytelimit is based on BQL here, it might be more correct to use
>>> > skb->len.
>>
>> Speaking of BQL, I wonder if we now should try to not wakeup queues as
>> soon some room was made, and instead have a 50% threshold ?
>>
>> This would probably increase probability to have bulk dequeues ;)
>>
> It would be good to have data on that.
+1.
Yes, I'd be very carefully observing BQL's behavior as these changes are made.
netperf-wrapper could rather easily sample bql's limit on as low as
10ms interval
I think....
and... me being me, I volunteer to watch 100Mbit and down.
> In the absence of TSO, I've
> seen BQL limits at around 30K for "standard" interrupt rates on 10G.
It is typically 3k at 100Mbit, 1500 at 10Mbit. It thus usually goes overlimit
by a MTU. I have simple tons of data on this on tons of kernels for
various platforms.
> This should mean that ~15K becomes available every interrupt period
> (the math is actually straightforward), so that should already have 10
> packet batches which isn't bad!
>
> It's also probably true that we can tradeoff batching for latency in
> many ways-- more batching increase latency, less batching helps
> latency. For instance, the interrupt rate can be modulated to balance
> between latency and batching (CPU utilization).
I have long hoped that the actual BQL limit in play would feed into
TCP small queues when there are a lot of flows to make each tcp
"small" queue gradually smaller...
> Tom
>
>>
>> diff --git a/include/linux/dynamic_queue_limits.h b/include/linux/dynamic_queue_limits.h
>> index 5621547d631b..c0be7ff5ae97 100644
>> --- a/include/linux/dynamic_queue_limits.h
>> +++ b/include/linux/dynamic_queue_limits.h
>> @@ -83,6 +83,13 @@ static inline int dql_avail(const struct dql *dql)
>> return dql->adj_limit - dql->num_queued;
>> }
>>
>> +/* Returns true if a queue occupancy is less than half capacity */
>> +static inline bool dql_half_avail(const struct dql *dql)
>> +{
>> + return dql->adj_limit >= (dql->num_queued << 1);
>> +}
>> +
>> +
>> /* Record number of completed objects and recalculate the limit. */
>> void dql_completed(struct dql *dql, unsigned int count);
>>
>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>> index c8e388e5fccc..1f7541284b32 100644
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -2413,7 +2413,7 @@ static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
>> smp_mb();
>>
>> /* check again in case another CPU has just made room avail */
>> - if (unlikely(dql_avail(&dev_queue->dql) >= 0))
>> + if (unlikely(dql_half_avail(&dev_queue->dql)))
>> clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);
>> #endif
>> }
>> @@ -2448,7 +2448,7 @@ static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,
>> */
>> smp_mb();
>>
>> - if (dql_avail(&dev_queue->dql) < 0)
>> + if (!dql_half_avail(&dev_queue->dql))
>> return;
>>
>> if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state))
>>
>>
--
Dave Täht
https://www.bufferbloat.net/projects/make-wifi-fast
^ permalink raw reply
* Re: [net-next PATCH 1/1 V4] qdisc: bulk dequeue support for qdiscs with TCQ_F_ONETXQUEUE
From: Tom Herbert @ 2014-09-25 2:38 UTC (permalink / raw)
To: Eric Dumazet
Cc: Jesper Dangaard Brouer, Linux Netdev List, David S. Miller,
Alexander Duyck, Toke Høiland-Jørgensen,
Florian Westphal, Jamal Hadi Salim, Dave Taht, John Fastabend,
Daniel Borkmann, Hannes Frederic Sowa
In-Reply-To: <1411611140.16953.1.camel@edumazet-glaptop2.roam.corp.google.com>
On Wed, Sep 24, 2014 at 7:12 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Wed, 2014-09-24 at 12:22 -0700, Eric Dumazet wrote:
>> On Wed, 2014-09-24 at 11:34 -0700, Tom Herbert wrote:
>> > >
>> > I believe drivers typically use skb->len for BQL tracking. Since
>> > bytelimit is based on BQL here, it might be more correct to use
>> > skb->len.
>
> Speaking of BQL, I wonder if we now should try to not wakeup queues as
> soon some room was made, and instead have a 50% threshold ?
>
> This would probably increase probability to have bulk dequeues ;)
>
It would be good to have data on that. In the absence of TSO, I've
seen BQL limits at around 30K for "standard" interrupt rates on 10G.
This should mean that ~15K becomes available every interrupt period
(the math is actually straightforward), so that should already have 10
packet batches which isn't bad!
It's also probably true that we can tradeoff batching for latency in
many ways-- more batching increase latency, less batching helps
latency. For instance, the interrupt rate can be modulated to balance
between latency and batching (CPU utilization).
Tom
>
> diff --git a/include/linux/dynamic_queue_limits.h b/include/linux/dynamic_queue_limits.h
> index 5621547d631b..c0be7ff5ae97 100644
> --- a/include/linux/dynamic_queue_limits.h
> +++ b/include/linux/dynamic_queue_limits.h
> @@ -83,6 +83,13 @@ static inline int dql_avail(const struct dql *dql)
> return dql->adj_limit - dql->num_queued;
> }
>
> +/* Returns true if a queue occupancy is less than half capacity */
> +static inline bool dql_half_avail(const struct dql *dql)
> +{
> + return dql->adj_limit >= (dql->num_queued << 1);
> +}
> +
> +
> /* Record number of completed objects and recalculate the limit. */
> void dql_completed(struct dql *dql, unsigned int count);
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index c8e388e5fccc..1f7541284b32 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -2413,7 +2413,7 @@ static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
> smp_mb();
>
> /* check again in case another CPU has just made room avail */
> - if (unlikely(dql_avail(&dev_queue->dql) >= 0))
> + if (unlikely(dql_half_avail(&dev_queue->dql)))
> clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);
> #endif
> }
> @@ -2448,7 +2448,7 @@ static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,
> */
> smp_mb();
>
> - if (dql_avail(&dev_queue->dql) < 0)
> + if (!dql_half_avail(&dev_queue->dql))
> return;
>
> if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state))
>
>
^ permalink raw reply
* Re: [net-next PATCH 1/1 V4] qdisc: bulk dequeue support for qdiscs with TCQ_F_ONETXQUEUE
From: Eric Dumazet @ 2014-09-25 2:12 UTC (permalink / raw)
To: Tom Herbert
Cc: Jesper Dangaard Brouer, Linux Netdev List, David S. Miller,
Alexander Duyck, Toke Høiland-Jørgensen,
Florian Westphal, Jamal Hadi Salim, Dave Taht, John Fastabend,
Daniel Borkmann, Hannes Frederic Sowa
In-Reply-To: <1411586550.15395.46.camel@edumazet-glaptop2.roam.corp.google.com>
On Wed, 2014-09-24 at 12:22 -0700, Eric Dumazet wrote:
> On Wed, 2014-09-24 at 11:34 -0700, Tom Herbert wrote:
> > >
> > I believe drivers typically use skb->len for BQL tracking. Since
> > bytelimit is based on BQL here, it might be more correct to use
> > skb->len.
Speaking of BQL, I wonder if we now should try to not wakeup queues as
soon some room was made, and instead have a 50% threshold ?
This would probably increase probability to have bulk dequeues ;)
diff --git a/include/linux/dynamic_queue_limits.h b/include/linux/dynamic_queue_limits.h
index 5621547d631b..c0be7ff5ae97 100644
--- a/include/linux/dynamic_queue_limits.h
+++ b/include/linux/dynamic_queue_limits.h
@@ -83,6 +83,13 @@ static inline int dql_avail(const struct dql *dql)
return dql->adj_limit - dql->num_queued;
}
+/* Returns true if a queue occupancy is less than half capacity */
+static inline bool dql_half_avail(const struct dql *dql)
+{
+ return dql->adj_limit >= (dql->num_queued << 1);
+}
+
+
/* Record number of completed objects and recalculate the limit. */
void dql_completed(struct dql *dql, unsigned int count);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c8e388e5fccc..1f7541284b32 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2413,7 +2413,7 @@ static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
smp_mb();
/* check again in case another CPU has just made room avail */
- if (unlikely(dql_avail(&dev_queue->dql) >= 0))
+ if (unlikely(dql_half_avail(&dev_queue->dql)))
clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);
#endif
}
@@ -2448,7 +2448,7 @@ static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,
*/
smp_mb();
- if (dql_avail(&dev_queue->dql) < 0)
+ if (!dql_half_avail(&dev_queue->dql))
return;
if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state))
^ permalink raw reply related
* [PATCH] neigh: check error pointer instead of NULL for ipv4_neigh_lookup()
From: Cong Wang @ 2014-09-25 0:07 UTC (permalink / raw)
To: netdev; +Cc: Cong Wang, David S. Miller
Fixes: commit f187bc6efb7250afee0e2009b6106 ("ipv4: No need to set generic neighbour pointer")
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
net/ipv4/route.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 173e7ea..cbadb94 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -746,7 +746,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
}
n = ipv4_neigh_lookup(&rt->dst, NULL, &new_gw);
- if (n) {
+ if (!IS_ERR(n)) {
if (!(n->nud_state & NUD_VALID)) {
neigh_event_send(n, NULL);
} else {
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next 6/6] net: dsa: bcm_sf2: add support for controlling EEE
From: Florian Fainelli @ 2014-09-25 0:05 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
In-Reply-To: <1411603522-8384-1-git-send-email-f.fainelli@gmail.com>
When EEE is enabled, negotiate this feature with the PHY and make sure
that the capability checking, local EEE advertisement, link partner EEE
advertisement and auto-negotiation resolution returned by phy_init_eee()
is positive, and enable EEE at the switch level.
While querying the current EEE settings, verify the low-power indication
and indicate its status.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/dsa/bcm_sf2.c | 73 ++++++++++++++++++++++++++++++++++++++++++
drivers/net/dsa/bcm_sf2.h | 3 ++
drivers/net/dsa/bcm_sf2_regs.h | 3 ++
3 files changed, 79 insertions(+)
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 634e44ee8d0d..b9625968daac 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -220,6 +220,19 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
}
+static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ u32 reg;
+
+ reg = core_readl(priv, CORE_EEE_EN_CTRL);
+ if (enable)
+ reg |= 1 << port;
+ else
+ reg &= ~(1 << port);
+ core_writel(priv, reg, CORE_EEE_EN_CTRL);
+}
+
static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
struct phy_device *phy)
{
@@ -247,6 +260,10 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
bcm_sf2_imp_vlan_setup(ds, cpu_port);
+ /* If EEE was enabled, restore it */
+ if (priv->port_sts[port].eee.eee_enabled)
+ bcm_sf2_eee_enable_set(ds, port, true);
+
return 0;
}
@@ -279,6 +296,60 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
}
+/* Returns 0 if EEE was not enabled, or 1 otherwise
+ */
+static int bcm_sf2_eee_init(struct dsa_switch *ds, int port,
+ struct phy_device *phy)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ struct ethtool_eee *p = &priv->port_sts[port].eee;
+ int ret;
+
+ p->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full);
+
+ ret = phy_init_eee(phy, 0);
+ if (ret)
+ return 0;
+
+ bcm_sf2_eee_enable_set(ds, port, true);
+
+ return 1;
+}
+
+static int bcm_sf2_sw_get_eee(struct dsa_switch *ds, int port,
+ struct ethtool_eee *e)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ struct ethtool_eee *p = &priv->port_sts[port].eee;
+ u32 reg;
+
+ reg = core_readl(priv, CORE_EEE_LPI_INDICATE);
+ e->eee_enabled = p->eee_enabled;
+ e->eee_active = !!(reg & (1 << port));
+
+ return 0;
+}
+
+static int bcm_sf2_sw_set_eee(struct dsa_switch *ds, int port,
+ struct phy_device *phydev,
+ struct ethtool_eee *e)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ struct ethtool_eee *p = &priv->port_sts[port].eee;
+
+ p->eee_enabled = e->eee_enabled;
+
+ if (!p->eee_enabled) {
+ bcm_sf2_eee_enable_set(ds, port, false);
+ } else {
+ p->eee_enabled = bcm_sf2_eee_init(ds, port, phydev);
+ if (!p->eee_enabled)
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
{
struct bcm_sf2_priv *priv = dev_id;
@@ -792,6 +863,8 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
.set_wol = bcm_sf2_sw_set_wol,
.port_enable = bcm_sf2_port_setup,
.port_disable = bcm_sf2_port_disable,
+ .get_eee = bcm_sf2_sw_get_eee,
+ .set_eee = bcm_sf2_sw_set_eee,
};
static int __init bcm_sf2_init(void)
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index 8fd6c1451a84..ee9f650d5026 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/mii.h>
+#include <linux/ethtool.h>
#include <net/dsa.h>
@@ -43,6 +44,8 @@ struct bcm_sf2_hw_params {
struct bcm_sf2_port_status {
unsigned int link;
+
+ struct ethtool_eee eee;
};
struct bcm_sf2_priv {
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
index c65f138c777f..1bb49cb699ab 100644
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -225,4 +225,7 @@
#define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8))
#define PORT_VLAN_CTRL_MASK 0x1ff
+#define CORE_EEE_EN_CTRL 0x24800
+#define CORE_EEE_LPI_INDICATE 0x24810
+
#endif /* __BCM_SF2_REGS_H */
--
1.9.1
^ permalink raw reply related
* [PATCH net-next 5/6] net: dsa: allow switches driver to implement get/set EEE
From: Florian Fainelli @ 2014-09-25 0:05 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
In-Reply-To: <1411603522-8384-1-git-send-email-f.fainelli@gmail.com>
Allow switches driver to query and enable/disable EEE on a per-port
basis by implementing the ethtool_{get,set}_eee settings and delegating
these operations to the switch driver.
set_eee() will need to coordinate with the PHY driver to make sure that
EEE is enabled, the link-partner supports it and the auto-negotiation
result is satisfactory.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
include/net/dsa.h | 9 +++++++++
net/dsa/slave.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 4f664fe0e42c..58ad8c6492db 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -232,6 +232,15 @@ struct dsa_switch_driver {
struct phy_device *phy);
void (*port_disable)(struct dsa_switch *ds, int port,
struct phy_device *phy);
+
+ /*
+ * EEE setttings
+ */
+ int (*set_eee)(struct dsa_switch *ds, int port,
+ struct phy_device *phydev,
+ struct ethtool_eee *e);
+ int (*get_eee)(struct dsa_switch *ds, int port,
+ struct ethtool_eee *e);
};
void register_switch_driver(struct dsa_switch_driver *type);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 182d30ae6818..36953c84ff2d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -342,6 +342,44 @@ static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
return ret;
}
+static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+ int ret;
+
+ if (!ds->drv->set_eee)
+ return -EOPNOTSUPP;
+
+ ret = ds->drv->set_eee(ds, p->port, p->phy, e);
+ if (ret)
+ return ret;
+
+ if (p->phy)
+ ret = phy_ethtool_set_eee(p->phy, e);
+
+ return ret;
+}
+
+static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+ int ret;
+
+ if (!ds->drv->get_eee)
+ return -EOPNOTSUPP;
+
+ ret = ds->drv->get_eee(ds, p->port, e);
+ if (ret)
+ return ret;
+
+ if (p->phy)
+ ret = phy_ethtool_get_eee(p->phy, e);
+
+ return ret;
+}
+
static const struct ethtool_ops dsa_slave_ethtool_ops = {
.get_settings = dsa_slave_get_settings,
.set_settings = dsa_slave_set_settings,
@@ -353,6 +391,8 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
.get_sset_count = dsa_slave_get_sset_count,
.set_wol = dsa_slave_set_wol,
.get_wol = dsa_slave_get_wol,
+ .set_eee = dsa_slave_set_eee,
+ .get_eee = dsa_slave_get_eee,
};
static const struct net_device_ops dsa_slave_netdev_ops = {
--
1.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox