All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vladimir Oltean <olteanv@gmail.com>
To: DENG Qingfang <dqfext@gmail.com>
Cc: netdev@vger.kernel.org, linux-mediatek@lists.infradead.org,
	Sean Wang <sean.wang@mediatek.com>,
	Landen Chao <Landen.Chao@mediatek.com>,
	Andrew Lunn <andrew@lunn.ch>,
	Vivien Didelot <vivien.didelot@gmail.com>,
	Florian Fainelli <f.fainelli@gmail.com>,
	"David S . Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Russell King <linux@armlinux.org.uk>,
	Frank Wunderlich <frank-w@public-files.de>
Subject: Re: [PATCH net-next] net: dsa: mt7530: support setting ageing time
Date: Tue, 8 Dec 2020 23:19:40 +0200	[thread overview]
Message-ID: <20201208211940.ep7lr7bvvuu2wqno@skbuf> (raw)
In-Reply-To: <20201208205621.2xxscilegk4k4t4g@skbuf>

On Tue, Dec 08, 2020 at 10:56:21PM +0200, Vladimir Oltean wrote:
> On Tue, Dec 08, 2020 at 03:00:28PM +0800, DENG Qingfang wrote:
> > MT7530 has a global address age control register, so use it to set
> > ageing time.
> > 
> > The applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds
> > 
> > Signed-off-by: DENG Qingfang <dqfext@gmail.com>
> > ---
> >  drivers/net/dsa/mt7530.c | 41 ++++++++++++++++++++++++++++++++++++++++
> >  drivers/net/dsa/mt7530.h | 13 +++++++++++++
> >  2 files changed, 54 insertions(+)
> > 
> > diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
> > index 6408402a44f5..99bf8fed6536 100644
> > --- a/drivers/net/dsa/mt7530.c
> > +++ b/drivers/net/dsa/mt7530.c
> > @@ -870,6 +870,46 @@ mt7530_get_sset_count(struct dsa_switch *ds, int port, int sset)
> >  	return ARRAY_SIZE(mt7530_mib);
> >  }
> >  
> > +static int
> > +mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
> > +{
> > +	struct mt7530_priv *priv = ds->priv;
> > +	unsigned int secs = msecs / 1000;
> > +	unsigned int tmp_age_count;
> > +	unsigned int error = -1;
> > +	unsigned int age_count;
> > +	unsigned int age_unit;
> > +
> > +	/* Applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds */
> > +	if (secs < 1 || secs > (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1))
> > +		return -ERANGE;
> > +
> > +	/* iterate through all possible age_count to find the closest pair */
> > +	for (tmp_age_count = 0; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
> > +		unsigned int tmp_age_unit = secs / (tmp_age_count + 1) - 1;
> > +
> > +		if (tmp_age_unit <= AGE_UNIT_MAX) {
> > +			unsigned int tmp_error = secs -
> > +				(tmp_age_count + 1) * (tmp_age_unit + 1);
> > +
> > +			/* found a closer pair */
> > +			if (error > tmp_error) {
> > +				error = tmp_error;
> > +				age_count = tmp_age_count;
> > +				age_unit = tmp_age_unit;
> > +			}
> 
> I feel that the error calculation is just snake oil. This would be enough:
> 
> 		if (tmp_age_unit <= AGE_UNIT_MAX)
> 			break;
> 
> Explanation:
> 
> You are given a number X, and must find A and B such that the error
> E = |(A x B) - X| should be minimum, with
> 1 <= A <= A_max
> 1 <= B <= B_max
> 
> It is logical to try with A=1 first. If X / A <= B_max, then of course,
> B = X / 1, and the error E is 0.
> 
> If that doesn't work out, and B > B_max, then you go to A=2. That gives
> you another B = X / 2, and the error E is 1. You check again if B <=
> B_max. If it is, that's your answer. B = X / 2, with an error E of 1.
> 
> You get my point. Iterating ascendingly through A, and calculating B as
> X / A, already gives you the smallest error as soon as it satisfies the
> B <= B_max requirement.
> 
> > +
> > +			/* found the exact match, so break the loop */
> > +			if (!error)
> > +				break;
> > +		}
> > +	}
> > +
> > +	mt7530_write(priv, MT7530_AAC, AGE_CNT(age_count) | AGE_UNIT(age_unit));
> > +
> > +	return 0;
> > +}

Thinking more about it, it's not snake oil but is actually correct.
Where I was wrong was the division giving you a certain error, but it
actually only gives a maximum error. Other, larger, divisors can still
give you an error of 0.
If the number you're searching for, X, is, say, a multiple of 3 but not
of 2, and is:
B_max * 1 < X < B_max * 2
then exiting the loop at A=2 would give you an error E=1. But if you
continued the loop, then A=3 would have yielded an error E=0, because X
is a multiple of 3 but not of 2. I should probably go and refresh my
basic arithmetic.

Reviewed-by: Vladimir Oltean <olteanv@gmail.com>

WARNING: multiple messages have this Message-ID (diff)
From: Vladimir Oltean <olteanv@gmail.com>
To: DENG Qingfang <dqfext@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>,
	Landen Chao <Landen.Chao@mediatek.com>,
	Florian Fainelli <f.fainelli@gmail.com>,
	Frank Wunderlich <frank-w@public-files.de>,
	netdev@vger.kernel.org, Sean Wang <sean.wang@mediatek.com>,
	Russell King <linux@armlinux.org.uk>,
	"David S . Miller" <davem@davemloft.net>,
	linux-mediatek@lists.infradead.org,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Jakub Kicinski <kuba@kernel.org>,
	Vivien Didelot <vivien.didelot@gmail.com>
Subject: Re: [PATCH net-next] net: dsa: mt7530: support setting ageing time
Date: Tue, 8 Dec 2020 23:19:40 +0200	[thread overview]
Message-ID: <20201208211940.ep7lr7bvvuu2wqno@skbuf> (raw)
In-Reply-To: <20201208205621.2xxscilegk4k4t4g@skbuf>

On Tue, Dec 08, 2020 at 10:56:21PM +0200, Vladimir Oltean wrote:
> On Tue, Dec 08, 2020 at 03:00:28PM +0800, DENG Qingfang wrote:
> > MT7530 has a global address age control register, so use it to set
> > ageing time.
> > 
> > The applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds
> > 
> > Signed-off-by: DENG Qingfang <dqfext@gmail.com>
> > ---
> >  drivers/net/dsa/mt7530.c | 41 ++++++++++++++++++++++++++++++++++++++++
> >  drivers/net/dsa/mt7530.h | 13 +++++++++++++
> >  2 files changed, 54 insertions(+)
> > 
> > diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
> > index 6408402a44f5..99bf8fed6536 100644
> > --- a/drivers/net/dsa/mt7530.c
> > +++ b/drivers/net/dsa/mt7530.c
> > @@ -870,6 +870,46 @@ mt7530_get_sset_count(struct dsa_switch *ds, int port, int sset)
> >  	return ARRAY_SIZE(mt7530_mib);
> >  }
> >  
> > +static int
> > +mt7530_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
> > +{
> > +	struct mt7530_priv *priv = ds->priv;
> > +	unsigned int secs = msecs / 1000;
> > +	unsigned int tmp_age_count;
> > +	unsigned int error = -1;
> > +	unsigned int age_count;
> > +	unsigned int age_unit;
> > +
> > +	/* Applied timer is (AGE_CNT + 1) * (AGE_UNIT + 1) seconds */
> > +	if (secs < 1 || secs > (AGE_CNT_MAX + 1) * (AGE_UNIT_MAX + 1))
> > +		return -ERANGE;
> > +
> > +	/* iterate through all possible age_count to find the closest pair */
> > +	for (tmp_age_count = 0; tmp_age_count <= AGE_CNT_MAX; ++tmp_age_count) {
> > +		unsigned int tmp_age_unit = secs / (tmp_age_count + 1) - 1;
> > +
> > +		if (tmp_age_unit <= AGE_UNIT_MAX) {
> > +			unsigned int tmp_error = secs -
> > +				(tmp_age_count + 1) * (tmp_age_unit + 1);
> > +
> > +			/* found a closer pair */
> > +			if (error > tmp_error) {
> > +				error = tmp_error;
> > +				age_count = tmp_age_count;
> > +				age_unit = tmp_age_unit;
> > +			}
> 
> I feel that the error calculation is just snake oil. This would be enough:
> 
> 		if (tmp_age_unit <= AGE_UNIT_MAX)
> 			break;
> 
> Explanation:
> 
> You are given a number X, and must find A and B such that the error
> E = |(A x B) - X| should be minimum, with
> 1 <= A <= A_max
> 1 <= B <= B_max
> 
> It is logical to try with A=1 first. If X / A <= B_max, then of course,
> B = X / 1, and the error E is 0.
> 
> If that doesn't work out, and B > B_max, then you go to A=2. That gives
> you another B = X / 2, and the error E is 1. You check again if B <=
> B_max. If it is, that's your answer. B = X / 2, with an error E of 1.
> 
> You get my point. Iterating ascendingly through A, and calculating B as
> X / A, already gives you the smallest error as soon as it satisfies the
> B <= B_max requirement.
> 
> > +
> > +			/* found the exact match, so break the loop */
> > +			if (!error)
> > +				break;
> > +		}
> > +	}
> > +
> > +	mt7530_write(priv, MT7530_AAC, AGE_CNT(age_count) | AGE_UNIT(age_unit));
> > +
> > +	return 0;
> > +}

Thinking more about it, it's not snake oil but is actually correct.
Where I was wrong was the division giving you a certain error, but it
actually only gives a maximum error. Other, larger, divisors can still
give you an error of 0.
If the number you're searching for, X, is, say, a multiple of 3 but not
of 2, and is:
B_max * 1 < X < B_max * 2
then exiting the loop at A=2 would give you an error E=1. But if you
continued the loop, then A=3 would have yielded an error E=0, because X
is a multiple of 3 but not of 2. I should probably go and refresh my
basic arithmetic.

Reviewed-by: Vladimir Oltean <olteanv@gmail.com>

_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek

  reply	other threads:[~2020-12-08 21:20 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-08  7:00 [PATCH net-next] net: dsa: mt7530: support setting ageing time DENG Qingfang
2020-12-08  7:00 ` DENG Qingfang
2020-12-08 14:17 ` Andrew Lunn
2020-12-08 14:17   ` Andrew Lunn
2020-12-08 20:56 ` Vladimir Oltean
2020-12-08 20:56   ` Vladimir Oltean
2020-12-08 21:19   ` Vladimir Oltean [this message]
2020-12-08 21:19     ` Vladimir Oltean
2020-12-08 22:01 ` Florian Fainelli
2020-12-08 22:01   ` Florian Fainelli
2020-12-09  0:19 ` David Miller
2020-12-09  0:19   ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201208211940.ep7lr7bvvuu2wqno@skbuf \
    --to=olteanv@gmail.com \
    --cc=Landen.Chao@mediatek.com \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=dqfext@gmail.com \
    --cc=f.fainelli@gmail.com \
    --cc=frank-w@public-files.de \
    --cc=kuba@kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=linux@armlinux.org.uk \
    --cc=matthias.bgg@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=sean.wang@mediatek.com \
    --cc=vivien.didelot@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.