* Re: [PATCH 1/3] tuntap: rx batching
From: Jason Wang @ 2016-11-11 4:28 UTC (permalink / raw)
To: John Fastabend, Michael S. Tsirkin; +Cc: netdev, linux-kernel
In-Reply-To: <58254654.4000501@gmail.com>
On 2016年11月11日 12:17, John Fastabend wrote:
> On 16-11-10 07:31 PM, Michael S. Tsirkin wrote:
>> >On Fri, Nov 11, 2016 at 10:07:44AM +0800, Jason Wang wrote:
>>> >>
>>> >>
>>> >>On 2016年11月10日 00:38, Michael S. Tsirkin wrote:
>>>> >>>On Wed, Nov 09, 2016 at 03:38:31PM +0800, Jason Wang wrote:
>>>>> >>>>Backlog were used for tuntap rx, but it can only process 1 packet at
>>>>> >>>>one time since it was scheduled during sendmsg() synchronously in
>>>>> >>>>process context. This lead bad cache utilization so this patch tries
>>>>> >>>>to do some batching before call rx NAPI. This is done through:
>>>>> >>>>
>>>>> >>>>- accept MSG_MORE as a hint from sendmsg() caller, if it was set,
>>>>> >>>> batch the packet temporarily in a linked list and submit them all
>>>>> >>>> once MSG_MORE were cleared.
>>>>> >>>>- implement a tuntap specific NAPI handler for processing this kind of
>>>>> >>>> possible batching. (This could be done by extending backlog to
>>>>> >>>> support skb like, but using a tun specific one looks cleaner and
>>>>> >>>> easier for future extension).
>>>>> >>>>
>>>>> >>>>Signed-off-by: Jason Wang<jasowang@redhat.com>
>>>> >>>So why do we need an extra queue?
>>> >>
>>> >>The idea was borrowed from backlog to allow some kind of bulking and avoid
>>> >>spinlock on each dequeuing.
>>> >>
>>>> >>> This is not what hardware devices do.
>>>> >>>How about adding the packet to queue unconditionally, deferring
>>>> >>>signalling until we get sendmsg without MSG_MORE?
>>> >>
>>> >>Then you need touch spinlock when dequeuing each packet.
>> >
> Random thought, I have a cmpxchg ring I am using for the qdisc work that
> could possibly replace the spinlock implementation. I haven't figured
> out the resizing API yet because I did not need it but I assume it could
> help here and let you dequeue multiple skbs in one operation.
>
> I can post the latest version if useful or an older version is
> somewhere on patchworks as well.
>
> .John
>
>
Look useful here, and I can compare the performance if you post.
A question is can we extend the skb_array to support that?
Thanks
^ permalink raw reply
* Re: [PATCH 2/3] vhost: better detection of available buffers
From: Jason Wang @ 2016-11-11 4:18 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, linux-kernel
In-Reply-To: <20161111054021-mutt-send-email-mst@kernel.org>
On 2016年11月11日 11:41, Michael S. Tsirkin wrote:
> On Fri, Nov 11, 2016 at 10:18:37AM +0800, Jason Wang wrote:
>> >
>> >
>> >On 2016年11月10日 03:57, Michael S. Tsirkin wrote:
>>> > >On Wed, Nov 09, 2016 at 03:38:32PM +0800, Jason Wang wrote:
>>>> > > >We should use vq->last_avail_idx instead of vq->avail_idx in the
>>>> > > >checking of vhost_vq_avail_empty() since latter is the cached avail
>>>> > > >index from guest but we want to know if there's pending available
>>>> > > >buffers in the virtqueue.
>>>> > > >
>>>> > > >Signed-off-by: Jason Wang<jasowang@redhat.com>
>>> > >I'm not sure why is this patch here. Is it related to
>>> > >batching somehow?
>> >
>> >Yes, we need to know whether or not there's still buffers left in the
>> >virtqueue, so need to check last_avail_idx. Otherwise, we're checking if
>> >guest has submitted new buffers.
>> >
>>> > >
>>> > >
>>>> > > >---
>>>> > > > drivers/vhost/vhost.c | 2 +-
>>>> > > > 1 file changed, 1 insertion(+), 1 deletion(-)
>>>> > > >
>>>> > > >diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
>>>> > > >index c6f2d89..fdf4cdf 100644
>>>> > > >--- a/drivers/vhost/vhost.c
>>>> > > >+++ b/drivers/vhost/vhost.c
>>>> > > >@@ -2230,7 +2230,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
>>>> > > > if (r)
>>>> > > > return false;
>>>> > > >- return vhost16_to_cpu(vq, avail_idx) == vq->avail_idx;
>>>> > > >+ return vhost16_to_cpu(vq, avail_idx) == vq->last_avail_idx;
>>>> > > > }
>>>> > > > EXPORT_SYMBOL_GPL(vhost_vq_avail_empty);
>>> > >That might be OK for TX but it's probably wrong for RX
>>> > >where the fact that used != avail does not mean
>>> > >we have enough space to store the packet.
>> >
>> >Right, but it's no harm since it was just a hint, handle_rx() can handle
>> >this situation.
> Means busy polling will cause useless load on the CPU though.
>
Right, but,it's not easy to have 100% correct hint here. Needs more thought.
^ permalink raw reply
* Re: [PATCH 1/3] tuntap: rx batching
From: John Fastabend @ 2016-11-11 4:17 UTC (permalink / raw)
To: Michael S. Tsirkin, Jason Wang; +Cc: netdev, linux-kernel
In-Reply-To: <20161111053048-mutt-send-email-mst@kernel.org>
On 16-11-10 07:31 PM, Michael S. Tsirkin wrote:
> On Fri, Nov 11, 2016 at 10:07:44AM +0800, Jason Wang wrote:
>>
>>
>> On 2016年11月10日 00:38, Michael S. Tsirkin wrote:
>>> On Wed, Nov 09, 2016 at 03:38:31PM +0800, Jason Wang wrote:
>>>> Backlog were used for tuntap rx, but it can only process 1 packet at
>>>> one time since it was scheduled during sendmsg() synchronously in
>>>> process context. This lead bad cache utilization so this patch tries
>>>> to do some batching before call rx NAPI. This is done through:
>>>>
>>>> - accept MSG_MORE as a hint from sendmsg() caller, if it was set,
>>>> batch the packet temporarily in a linked list and submit them all
>>>> once MSG_MORE were cleared.
>>>> - implement a tuntap specific NAPI handler for processing this kind of
>>>> possible batching. (This could be done by extending backlog to
>>>> support skb like, but using a tun specific one looks cleaner and
>>>> easier for future extension).
>>>>
>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>> So why do we need an extra queue?
>>
>> The idea was borrowed from backlog to allow some kind of bulking and avoid
>> spinlock on each dequeuing.
>>
>>> This is not what hardware devices do.
>>> How about adding the packet to queue unconditionally, deferring
>>> signalling until we get sendmsg without MSG_MORE?
>>
>> Then you need touch spinlock when dequeuing each packet.
>
Random thought, I have a cmpxchg ring I am using for the qdisc work that
could possibly replace the spinlock implementation. I haven't figured
out the resizing API yet because I did not need it but I assume it could
help here and let you dequeue multiple skbs in one operation.
I can post the latest version if useful or an older version is
somewhere on patchworks as well.
.John
> It runs on the same CPU, right? Otherwise we should use skb_array...
>
>>>
>>>
>>>> ---
>>>> drivers/net/tun.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>>>> 1 file changed, 65 insertions(+), 6 deletions(-)
>>>>
>>
>> [...]
>>
>>>> rxhash = skb_get_hash(skb);
>>>> - netif_rx_ni(skb);
>>>> + skb_queue_tail(&tfile->socket.sk->sk_write_queue, skb);
>>>> +
>>>> + if (!more) {
>>>> + local_bh_disable();
>>>> + napi_schedule(&tfile->napi);
>>>> + local_bh_enable();
>>> Why do we need to disable bh here? I thought napi_schedule can
>>> be called from any context.
>>
>> Yes, it's unnecessary. Will remove.
>>
>> Thanks
^ permalink raw reply
* Re: [PATCH 1/3] tuntap: rx batching
From: Jason Wang @ 2016-11-11 4:10 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, linux-kernel
In-Reply-To: <20161111053048-mutt-send-email-mst@kernel.org>
On 2016年11月11日 11:31, Michael S. Tsirkin wrote:
> On Fri, Nov 11, 2016 at 10:07:44AM +0800, Jason Wang wrote:
>> >
>> >
>> >On 2016年11月10日 00:38, Michael S. Tsirkin wrote:
>>> > >On Wed, Nov 09, 2016 at 03:38:31PM +0800, Jason Wang wrote:
>>>> > > >Backlog were used for tuntap rx, but it can only process 1 packet at
>>>> > > >one time since it was scheduled during sendmsg() synchronously in
>>>> > > >process context. This lead bad cache utilization so this patch tries
>>>> > > >to do some batching before call rx NAPI. This is done through:
>>>> > > >
>>>> > > >- accept MSG_MORE as a hint from sendmsg() caller, if it was set,
>>>> > > > batch the packet temporarily in a linked list and submit them all
>>>> > > > once MSG_MORE were cleared.
>>>> > > >- implement a tuntap specific NAPI handler for processing this kind of
>>>> > > > possible batching. (This could be done by extending backlog to
>>>> > > > support skb like, but using a tun specific one looks cleaner and
>>>> > > > easier for future extension).
>>>> > > >
>>>> > > >Signed-off-by: Jason Wang<jasowang@redhat.com>
>>> > >So why do we need an extra queue?
>> >
>> >The idea was borrowed from backlog to allow some kind of bulking and avoid
>> >spinlock on each dequeuing.
>> >
>>> > > This is not what hardware devices do.
>>> > >How about adding the packet to queue unconditionally, deferring
>>> > >signalling until we get sendmsg without MSG_MORE?
>> >
>> >Then you need touch spinlock when dequeuing each packet.
> It runs on the same CPU, right? Otherwise we should use skb_array...
>
There could be multiple senders technically. Will try skb_array and see
if there's any difference.
Thanks
^ permalink raw reply
* Re: [PATCH 2/3] vhost: better detection of available buffers
From: Michael S. Tsirkin @ 2016-11-11 3:41 UTC (permalink / raw)
To: Jason Wang; +Cc: netdev, linux-kernel
In-Reply-To: <70cb5ad8-5266-b0c4-7b55-4aea4f5f01a6@redhat.com>
On Fri, Nov 11, 2016 at 10:18:37AM +0800, Jason Wang wrote:
>
>
> On 2016年11月10日 03:57, Michael S. Tsirkin wrote:
> > On Wed, Nov 09, 2016 at 03:38:32PM +0800, Jason Wang wrote:
> > > We should use vq->last_avail_idx instead of vq->avail_idx in the
> > > checking of vhost_vq_avail_empty() since latter is the cached avail
> > > index from guest but we want to know if there's pending available
> > > buffers in the virtqueue.
> > >
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > I'm not sure why is this patch here. Is it related to
> > batching somehow?
>
> Yes, we need to know whether or not there's still buffers left in the
> virtqueue, so need to check last_avail_idx. Otherwise, we're checking if
> guest has submitted new buffers.
>
> >
> >
> > > ---
> > > drivers/vhost/vhost.c | 2 +-
> > > 1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> > > index c6f2d89..fdf4cdf 100644
> > > --- a/drivers/vhost/vhost.c
> > > +++ b/drivers/vhost/vhost.c
> > > @@ -2230,7 +2230,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
> > > if (r)
> > > return false;
> > > - return vhost16_to_cpu(vq, avail_idx) == vq->avail_idx;
> > > + return vhost16_to_cpu(vq, avail_idx) == vq->last_avail_idx;
> > > }
> > > EXPORT_SYMBOL_GPL(vhost_vq_avail_empty);
> > That might be OK for TX but it's probably wrong for RX
> > where the fact that used != avail does not mean
> > we have enough space to store the packet.
>
> Right, but it's no harm since it was just a hint, handle_rx() can handle
> this situation.
Means busy polling will cause useless load on the CPU though.
> >
> > Maybe we should just rename this to vhost_vq_avail_unchanged
> > to clarify usage.
> >
>
> Ok.
>
> > > --
> > > 2.7.4
^ permalink raw reply
* Re: [PATCH 1/3] tuntap: rx batching
From: Michael S. Tsirkin @ 2016-11-11 3:31 UTC (permalink / raw)
To: Jason Wang; +Cc: netdev, linux-kernel
In-Reply-To: <c6cd619f-b9a6-784d-2c44-6106e64f5664@redhat.com>
On Fri, Nov 11, 2016 at 10:07:44AM +0800, Jason Wang wrote:
>
>
> On 2016年11月10日 00:38, Michael S. Tsirkin wrote:
> > On Wed, Nov 09, 2016 at 03:38:31PM +0800, Jason Wang wrote:
> > > Backlog were used for tuntap rx, but it can only process 1 packet at
> > > one time since it was scheduled during sendmsg() synchronously in
> > > process context. This lead bad cache utilization so this patch tries
> > > to do some batching before call rx NAPI. This is done through:
> > >
> > > - accept MSG_MORE as a hint from sendmsg() caller, if it was set,
> > > batch the packet temporarily in a linked list and submit them all
> > > once MSG_MORE were cleared.
> > > - implement a tuntap specific NAPI handler for processing this kind of
> > > possible batching. (This could be done by extending backlog to
> > > support skb like, but using a tun specific one looks cleaner and
> > > easier for future extension).
> > >
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > So why do we need an extra queue?
>
> The idea was borrowed from backlog to allow some kind of bulking and avoid
> spinlock on each dequeuing.
>
> > This is not what hardware devices do.
> > How about adding the packet to queue unconditionally, deferring
> > signalling until we get sendmsg without MSG_MORE?
>
> Then you need touch spinlock when dequeuing each packet.
It runs on the same CPU, right? Otherwise we should use skb_array...
> >
> >
> > > ---
> > > drivers/net/tun.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
> > > 1 file changed, 65 insertions(+), 6 deletions(-)
> > >
>
> [...]
>
> > > rxhash = skb_get_hash(skb);
> > > - netif_rx_ni(skb);
> > > + skb_queue_tail(&tfile->socket.sk->sk_write_queue, skb);
> > > +
> > > + if (!more) {
> > > + local_bh_disable();
> > > + napi_schedule(&tfile->napi);
> > > + local_bh_enable();
> > Why do we need to disable bh here? I thought napi_schedule can
> > be called from any context.
>
> Yes, it's unnecessary. Will remove.
>
> Thanks
^ permalink raw reply
* [PATCH net-next 00/11] Start adding support for mv88e6390 family
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
This is the first patchset implementing support for the mv88e6390
family. This is a new generation of switch devices and has numerous
incompatible changes to the registers. These patches allow the switch
to the detected during probe, and makes the statistics unit work.
These patches are insufficient to make the mv88e6390 functional. More
patches will follow.
Andrew Lunn (11):
net: dsa: mv88e6xxx: Take switch out of reset before probe
net: dsa: mv88e6xxx: Fix unused variable warning by using variable
net: dsa: mv88e6xxx: Add the mv88e6390 family
net: dsa: mv88e6xxx: Abstract stats_snapshot into ops structure
net: dsa: mv88e6xxx: Add comment about family a device belongs to
net: dsa: mv88e6xxx: Add mv88e6390 stats snapshot operation
net: dsa: mv88e6xxx: Add mv88e6390 statistics unit init
net: dsa: mv88e6xxx: Add stats_get_sset_count to ops structure
net: dsa: mv88e6xxx: Add stats_get_strings to ops structure
net: dsa: mv88e6xxx: Add stats_get_stats to ops structure
net: dsa: mv88e6xxx: Implement mv88e6390 get_stats
.../devicetree/bindings/net/dsa/marvell.txt | 3 +-
drivers/net/dsa/mv88e6xxx/chip.c | 550 ++++++++++++++++-----
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 53 +-
3 files changed, 487 insertions(+), 119 deletions(-)
--
2.10.1
^ permalink raw reply
* [PATCH net-next 01/11] net: dsa: mv88e6xxx: Take switch out of reset before probe
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
The switch needs to be taken out of reset before we can read its ID
register on the MDIO bus.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d6d9d66b81ce..2c5c37318e31 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3839,16 +3839,16 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
if (err)
return err;
+ chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(chip->reset))
+ return PTR_ERR(chip->reset);
+
err = mv88e6xxx_detect(chip);
if (err)
return err;
mv88e6xxx_phy_init(chip);
- chip->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
- if (IS_ERR(chip->reset))
- return PTR_ERR(chip->reset);
-
if (chip->info->ops->get_eeprom &&
!of_property_read_u32(np, "eeprom-length", &eeprom_len))
chip->eeprom_len = eeprom_len;
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 02/11] net: dsa: mv88e6xxx: Fix unused variable warning by using variable
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
_mv88e6xxx_stats_wait() did not check the return value from
mv88e6xxx_g1_read(), so the compiler complained about set but unused
err.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 2c5c37318e31..a4d52f0fdc90 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -771,6 +771,9 @@ static int _mv88e6xxx_stats_wait(struct mv88e6xxx_chip *chip)
for (i = 0; i < 10; i++) {
err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_OP, &val);
+ if (err)
+ return err;
+
if ((val & GLOBAL_STATS_OP_BUSY) == 0)
return 0;
}
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 03/11] net: dsa: mv88e6xxx: Add the mv88e6390 family
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
With the devices added to the tables, the probe will recognize the
switch. This however is not sufficient to make it work properly, other
changes are needed because of incompatibilities.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
.../devicetree/bindings/net/dsa/marvell.txt | 3 +-
drivers/net/dsa/mv88e6xxx/chip.c | 105 +++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 25 +++++
3 files changed, 132 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt
index 32025eb4b31b..f543483458a1 100644
--- a/Documentation/devicetree/bindings/net/dsa/marvell.txt
+++ b/Documentation/devicetree/bindings/net/dsa/marvell.txt
@@ -14,7 +14,8 @@ The properties described here are those specific to Marvell devices.
Additional required and optional properties can be found in dsa.txt.
Required properties:
-- compatible : Should be one of "marvell,mv88e6085",
+- compatible : Should be one of "marvell,mv88e6085" or
+ "marvell,mv88e6390"
- reg : Address on the MII bus for the switch.
Optional properties:
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index a4d52f0fdc90..066d9479c981 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3312,6 +3312,26 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_speed = mv88e6352_port_set_speed,
};
+static const struct mv88e6xxx_ops mv88e6390_ops = {
+ .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390_port_set_speed,
+};
+
+static const struct mv88e6xxx_ops mv88e6390x_ops = {
+ .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390x_port_set_speed,
+};
+
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
[MV88E6085] = {
.prod_num = PORT_SWITCH_ID_PROD_NUM_6085,
@@ -3467,6 +3487,47 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6185_ops,
},
+ [MV88E6190] = {
+ .prod_num = PORT_SWITCH_ID_PROD_NUM_6190,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6190",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .age_time_coeff = 15000,
+ .g1_irqs = 9,
+ .flags = MV88E6XXX_FLAGS_FAMILY_6390,
+ .ops = &mv88e6390_ops,
+ },
+
+ [MV88E6190X] = {
+ .prod_num = PORT_SWITCH_ID_PROD_NUM_6190X,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6190X",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .age_time_coeff = 15000,
+ .g1_irqs = 9,
+ .flags = MV88E6XXX_FLAGS_FAMILY_6390,
+ .ops = &mv88e6390x_ops,
+ },
+
+ [MV88E6191] = {
+ .prod_num = PORT_SWITCH_ID_PROD_NUM_6191,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6191",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .age_time_coeff = 15000,
+ .flags = MV88E6XXX_FLAGS_FAMILY_6390,
+ .ops = &mv88e6390_ops,
+ },
+
[MV88E6240] = {
.prod_num = PORT_SWITCH_ID_PROD_NUM_6240,
.family = MV88E6XXX_FAMILY_6352,
@@ -3481,6 +3542,20 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6240_ops,
},
+ [MV88E6290] = {
+ .prod_num = PORT_SWITCH_ID_PROD_NUM_6290,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6290",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .age_time_coeff = 15000,
+ .g1_irqs = 9,
+ .flags = MV88E6XXX_FLAGS_FAMILY_6390,
+ .ops = &mv88e6390_ops,
+ },
+
[MV88E6320] = {
.prod_num = PORT_SWITCH_ID_PROD_NUM_6320,
.family = MV88E6XXX_FAMILY_6320,
@@ -3550,6 +3625,32 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6352_ops,
},
+ [MV88E6390] = {
+ .prod_num = PORT_SWITCH_ID_PROD_NUM_6390,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6390",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .age_time_coeff = 15000,
+ .g1_irqs = 9,
+ .flags = MV88E6XXX_FLAGS_FAMILY_6390,
+ .ops = &mv88e6390_ops,
+ },
+ [MV88E6390X] = {
+ .prod_num = PORT_SWITCH_ID_PROD_NUM_6390X,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6390X",
+ .num_databases = 4096,
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global1_addr = 0x1b,
+ .age_time_coeff = 15000,
+ .g1_irqs = 9,
+ .flags = MV88E6XXX_FLAGS_FAMILY_6390,
+ .ops = &mv88e6390x_ops,
+ },
};
static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
@@ -3927,6 +4028,10 @@ static const struct of_device_id mv88e6xxx_of_match[] = {
.compatible = "marvell,mv88e6085",
.data = &mv88e6xxx_table[MV88E6085],
},
+ {
+ .compatible = "marvell,mv88e6390",
+ .data = &mv88e6xxx_table[MV88E6390],
+ },
{ /* sentinel */ },
};
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 929613021eff..48915e5e3a3d 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -91,11 +91,17 @@
#define PORT_SWITCH_ID_PROD_NUM_6175 0x175
#define PORT_SWITCH_ID_PROD_NUM_6176 0x176
#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7
+#define PORT_SWITCH_ID_PROD_NUM_6190 0x190
+#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0
+#define PORT_SWITCH_ID_PROD_NUM_6191 0x191
#define PORT_SWITCH_ID_PROD_NUM_6240 0x240
+#define PORT_SWITCH_ID_PROD_NUM_6290 0x290
#define PORT_SWITCH_ID_PROD_NUM_6321 0x310
#define PORT_SWITCH_ID_PROD_NUM_6352 0x352
#define PORT_SWITCH_ID_PROD_NUM_6350 0x371
#define PORT_SWITCH_ID_PROD_NUM_6351 0x375
+#define PORT_SWITCH_ID_PROD_NUM_6390 0x390
+#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1
#define PORT_CONTROL 0x04
#define PORT_CONTROL_USE_CORE_TAG BIT(15)
#define PORT_CONTROL_DROP_ON_LOCK BIT(14)
@@ -378,12 +384,18 @@ enum mv88e6xxx_model {
MV88E6175,
MV88E6176,
MV88E6185,
+ MV88E6190,
+ MV88E6190X,
+ MV88E6191,
MV88E6240,
+ MV88E6290,
MV88E6320,
MV88E6321,
MV88E6350,
MV88E6351,
MV88E6352,
+ MV88E6390,
+ MV88E6390X,
};
enum mv88e6xxx_family {
@@ -396,6 +408,7 @@ enum mv88e6xxx_family {
MV88E6XXX_FAMILY_6320, /* 6320 6321 */
MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
+ MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
};
enum mv88e6xxx_cap {
@@ -615,6 +628,18 @@ enum mv88e6xxx_cap {
struct mv88e6xxx_ops;
+#define MV88E6XXX_FLAGS_FAMILY_6390 \
+ (MV88E6XXX_FLAG_EEE | \
+ MV88E6XXX_FLAG_GLOBAL2 | \
+ MV88E6XXX_FLAG_PPU_ACTIVE | \
+ MV88E6XXX_FLAG_STU | \
+ MV88E6XXX_FLAG_TEMP | \
+ MV88E6XXX_FLAG_TEMP_LIMIT | \
+ MV88E6XXX_FLAG_VTU | \
+ MV88E6XXX_FLAGS_IRL | \
+ MV88E6XXX_FLAGS_MULTI_CHIP | \
+ MV88E6XXX_FLAGS_PVT)
+
struct mv88e6xxx_info {
enum mv88e6xxx_family family;
u16 prod_num;
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 08/11] net: dsa: mv88e6xxx: Add stats_get_sset_count to ops structure
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
Different families have different sets of statistics. Abstract this
using a stats_get_sset_count op. Each stat has a bitmap, and the ops
implementer uses a bit map mask to count the statistics which apply
for the family.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 185 +++++++++++++++++++++-------------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 11 +-
2 files changed, 119 insertions(+), 77 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index b20732616031..5d2c135b9175 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -860,76 +860,76 @@ static void _mv88e6xxx_stats_read(struct mv88e6xxx_chip *chip,
}
static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
- { "in_good_octets", 8, 0x00, BANK0, },
- { "in_bad_octets", 4, 0x02, BANK0, },
- { "in_unicast", 4, 0x04, BANK0, },
- { "in_broadcasts", 4, 0x06, BANK0, },
- { "in_multicasts", 4, 0x07, BANK0, },
- { "in_pause", 4, 0x16, BANK0, },
- { "in_undersize", 4, 0x18, BANK0, },
- { "in_fragments", 4, 0x19, BANK0, },
- { "in_oversize", 4, 0x1a, BANK0, },
- { "in_jabber", 4, 0x1b, BANK0, },
- { "in_rx_error", 4, 0x1c, BANK0, },
- { "in_fcs_error", 4, 0x1d, BANK0, },
- { "out_octets", 8, 0x0e, BANK0, },
- { "out_unicast", 4, 0x10, BANK0, },
- { "out_broadcasts", 4, 0x13, BANK0, },
- { "out_multicasts", 4, 0x12, BANK0, },
- { "out_pause", 4, 0x15, BANK0, },
- { "excessive", 4, 0x11, BANK0, },
- { "collisions", 4, 0x1e, BANK0, },
- { "deferred", 4, 0x05, BANK0, },
- { "single", 4, 0x14, BANK0, },
- { "multiple", 4, 0x17, BANK0, },
- { "out_fcs_error", 4, 0x03, BANK0, },
- { "late", 4, 0x1f, BANK0, },
- { "hist_64bytes", 4, 0x08, BANK0, },
- { "hist_65_127bytes", 4, 0x09, BANK0, },
- { "hist_128_255bytes", 4, 0x0a, BANK0, },
- { "hist_256_511bytes", 4, 0x0b, BANK0, },
- { "hist_512_1023bytes", 4, 0x0c, BANK0, },
- { "hist_1024_max_bytes", 4, 0x0d, BANK0, },
- { "sw_in_discards", 4, 0x10, PORT, },
- { "sw_in_filtered", 2, 0x12, PORT, },
- { "sw_out_filtered", 2, 0x13, PORT, },
- { "in_discards", 4, 0x00 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_filtered", 4, 0x01 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_accepted", 4, 0x02 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_bad_accepted", 4, 0x03 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_good_avb_class_a", 4, 0x04 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_good_avb_class_b", 4, 0x05 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_bad_avb_class_a", 4, 0x06 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_bad_avb_class_b", 4, 0x07 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "tcam_counter_0", 4, 0x08 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "tcam_counter_1", 4, 0x09 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "tcam_counter_2", 4, 0x0a | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "tcam_counter_3", 4, 0x0b | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_da_unknown", 4, 0x0e | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "in_management", 4, 0x0f | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_0", 4, 0x10 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_1", 4, 0x11 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_2", 4, 0x12 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_3", 4, 0x13 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_4", 4, 0x14 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_5", 4, 0x15 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_6", 4, 0x16 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_queue_7", 4, 0x17 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_cut_through", 4, 0x18 | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_octets_a", 4, 0x1a | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_octets_b", 4, 0x1b | GLOBAL_STATS_OP_BANK_1, BANK1, },
- { "out_management", 4, 0x1f | GLOBAL_STATS_OP_BANK_1, BANK1, },
+ { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, },
+ { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, },
+ { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, },
+ { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, },
+ { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, },
+ { "in_pause", 4, 0x16, STATS_TYPE_BANK0, },
+ { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, },
+ { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, },
+ { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, },
+ { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, },
+ { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, },
+ { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, },
+ { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, },
+ { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, },
+ { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, },
+ { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, },
+ { "out_pause", 4, 0x15, STATS_TYPE_BANK0, },
+ { "excessive", 4, 0x11, STATS_TYPE_BANK0, },
+ { "collisions", 4, 0x1e, STATS_TYPE_BANK0, },
+ { "deferred", 4, 0x05, STATS_TYPE_BANK0, },
+ { "single", 4, 0x14, STATS_TYPE_BANK0, },
+ { "multiple", 4, 0x17, STATS_TYPE_BANK0, },
+ { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, },
+ { "late", 4, 0x1f, STATS_TYPE_BANK0, },
+ { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, },
+ { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, },
+ { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, },
+ { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, },
+ { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, },
+ { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, },
+ { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, },
+ { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, },
+ { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, },
+ { "in_discards", 4, 0x00, STATS_TYPE_BANK1, },
+ { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, },
+ { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, },
+ { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, },
+ { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, },
+ { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, },
+ { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, },
+ { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, },
+ { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, },
+ { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, },
+ { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, },
+ { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, },
+ { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, },
+ { "in_management", 4, 0x0f, STATS_TYPE_BANK1, },
+ { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, },
+ { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, },
+ { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, },
+ { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, },
+ { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, },
+ { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, },
+ { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, },
+ { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, },
+ { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, },
+ { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, },
+ { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, },
+ { "out_management", 4, 0x1f, STATS_TYPE_BANK1, },
};
static bool mv88e6xxx_has_stat(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_hw_stat *stat)
{
switch (stat->type) {
- case BANK0:
+ case STATS_TYPE_BANK0:
return true;
- case BANK1:
+ case STATS_TYPE_BANK1:
return mv88e6xxx_6320_family(chip);
- case PORT:
+ case STATS_TYPE_PORT:
return mv88e6xxx_6095_family(chip) ||
mv88e6xxx_6185_family(chip) ||
mv88e6xxx_6097_family(chip) ||
@@ -946,12 +946,12 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
{
u32 low;
u32 high = 0;
+ u16 reg = 0;
int err;
- u16 reg;
u64 value;
switch (s->type) {
- case PORT:
+ case STATS_TYPE_PORT:
err = mv88e6xxx_port_read(chip, port, s->reg, ®);
if (err)
return UINT64_MAX;
@@ -964,11 +964,14 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
high = reg;
}
break;
- case BANK0:
- case BANK1:
- _mv88e6xxx_stats_read(chip, s->reg, &low);
+ case STATS_TYPE_BANK1:
+ reg = GLOBAL_STATS_OP_BANK_1;
+ /* fall through */
+ case STATS_TYPE_BANK0:
+ reg |= s->reg;
+ _mv88e6xxx_stats_read(chip, reg, &low);
if (s->sizeof_stat == 8)
- _mv88e6xxx_stats_read(chip, s->reg + 1, &high);
+ _mv88e6xxx_stats_read(chip, reg + 1, &high);
}
value = (((u64)high) << 16) | low;
return value;
@@ -991,20 +994,41 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
}
}
-static int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
+static int _mv88e6xxx_get_sset_count(struct mv88e6xxx_chip *chip, int types)
{
- struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_hw_stat *stat;
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
stat = &mv88e6xxx_hw_stats[i];
- if (mv88e6xxx_has_stat(chip, stat))
+ if (stat->type & types)
j++;
}
return j;
}
+static int mv88e6095_get_sset_count(struct mv88e6xxx_chip *chip)
+{
+ return _mv88e6xxx_get_sset_count(chip, STATS_TYPE_BANK0 |
+ STATS_TYPE_PORT);
+}
+
+static int mv88e6320_get_sset_count(struct mv88e6xxx_chip *chip)
+{
+ return _mv88e6xxx_get_sset_count(chip, STATS_TYPE_BANK0 |
+ STATS_TYPE_BANK1);
+}
+
+static int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+
+ if (chip->info->ops->stats_get_sset_count)
+ return chip->info->ops->stats_get_sset_count(chip);
+
+ return 0;
+}
+
static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
uint64_t *data)
{
@@ -3205,6 +3229,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -3216,6 +3241,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -3227,6 +3253,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -3238,6 +3265,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -3249,6 +3277,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -3260,6 +3289,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3272,6 +3302,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3286,6 +3317,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -3298,6 +3330,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3312,6 +3345,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3323,6 +3357,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3337,6 +3372,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3350,6 +3386,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
+ .stats_get_sset_count = mv88e6320_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3363,6 +3400,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
+ .stats_get_sset_count = mv88e6320_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3375,6 +3413,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3387,6 +3426,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3401,6 +3441,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
+ .stats_get_sset_count = mv88e6095_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3414,6 +3455,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.port_set_speed = mv88e6390_port_set_speed,
.stats_init = mv88e6390_stats_init,
.stats_snapshot = mv88e6390_stats_snapshot,
+ .stats_get_sset_count = mv88e6320_get_sset_count,
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3427,6 +3469,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.port_set_speed = mv88e6390x_port_set_speed,
.stats_init = mv88e6390_stats_init,
.stats_snapshot = mv88e6390_stats_snapshot,
+ .stats_get_sset_count = mv88e6320_get_sset_count,
};
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 86dbdc957f28..4ff674d0e248 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -802,19 +802,18 @@ struct mv88e6xxx_ops {
* be read back a leisure but still with a consistent view.
*/
int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port);
+ int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip);
};
-enum stat_type {
- BANK0,
- BANK1,
- PORT,
-};
+#define STATS_TYPE_PORT BIT(0)
+#define STATS_TYPE_BANK0 BIT(1)
+#define STATS_TYPE_BANK1 BIT(2)
struct mv88e6xxx_hw_stat {
char string[ETH_GSTRING_LEN];
int sizeof_stat;
int reg;
- enum stat_type type;
+ int type;
};
static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip,
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 07/11] net: dsa: mv88e6xxx: Add mv88e6390 statistics unit init
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
The statistics unit on the mv88e6390 needs to the configured in a
different register to the others as to what histogram statistics is
should return.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 31 +++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 2 ++
2 files changed, 33 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 82e57aac00f1..b20732616031 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1031,6 +1031,30 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
mutex_unlock(&chip->reg_lock);
}
+static int mv88e6390_stats_init(struct mv88e6xxx_chip *chip)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
+ if (err)
+ return err;
+
+ val |= GLOBAL_CONTROL_2_HIST_RX_TX;
+
+ err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
+
+ return err;
+}
+
+static int mv88e6xxx_stats_init(struct mv88e6xxx_chip *chip)
+{
+ if (chip->info->ops->stats_init)
+ return chip->info->ops->stats_init(chip);
+
+ return 0;
+}
+
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
{
return 32 * sizeof(u16);
@@ -2819,6 +2843,11 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
if (err)
return err;
+ /* Initialize the statistics unit */
+ err = mv88e6xxx_stats_init(chip);
+ if (err)
+ return err;
+
/* Clear the statistics counters for all ports */
err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
GLOBAL_STATS_OP_FLUSH_ALL);
@@ -3383,6 +3412,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
+ .stats_init = mv88e6390_stats_init,
.stats_snapshot = mv88e6390_stats_snapshot,
};
@@ -3395,6 +3425,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390x_port_set_speed,
+ .stats_init = mv88e6390_stats_init,
.stats_snapshot = mv88e6390_stats_snapshot,
};
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 147f1f3a817b..86dbdc957f28 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -796,6 +796,8 @@ struct mv88e6xxx_ops {
*/
int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed);
+ int (*stats_init)(struct mv88e6xxx_chip *chip);
+
/* Snapshot the statistics for a port. The statistics can then
* be read back a leisure but still with a consistent view.
*/
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 05/11] net: dsa: mv88e6xxx: Add comment about family a device belongs to
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
Knowing the family of device belongs to helps with picking the ops
implementation which is appropriate to the device. So add a comment to
each structure of ops.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 65f34f1999e7..d4fc12d7021a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3152,6 +3152,7 @@ static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
}
static const struct mv88e6xxx_ops mv88e6085_ops = {
+ /* MV88E6XXX_FAMILY_6097 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
.phy_read = mv88e6xxx_phy_ppu_read,
.phy_write = mv88e6xxx_phy_ppu_write,
@@ -3162,6 +3163,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
};
static const struct mv88e6xxx_ops mv88e6095_ops = {
+ /* MV88E6XXX_FAMILY_6095 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
.phy_read = mv88e6xxx_phy_ppu_read,
.phy_write = mv88e6xxx_phy_ppu_write,
@@ -3172,6 +3174,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
};
static const struct mv88e6xxx_ops mv88e6123_ops = {
+ /* MV88E6XXX_FAMILY_6165 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_read,
.phy_write = mv88e6xxx_write,
@@ -3182,6 +3185,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
};
static const struct mv88e6xxx_ops mv88e6131_ops = {
+ /* MV88E6XXX_FAMILY_6185 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
.phy_read = mv88e6xxx_phy_ppu_read,
.phy_write = mv88e6xxx_phy_ppu_write,
@@ -3192,6 +3196,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
};
static const struct mv88e6xxx_ops mv88e6161_ops = {
+ /* MV88E6XXX_FAMILY_6165 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_read,
.phy_write = mv88e6xxx_write,
@@ -3202,6 +3207,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
+ /* MV88E6XXX_FAMILY_6165 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_read,
.phy_write = mv88e6xxx_write,
@@ -3212,6 +3218,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_g2_smi_phy_read,
.phy_write = mv88e6xxx_g2_smi_phy_write,
@@ -3223,6 +3230,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
};
static const struct mv88e6xxx_ops mv88e6172_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
.get_eeprom = mv88e6xxx_g2_get_eeprom16,
.set_eeprom = mv88e6xxx_g2_set_eeprom16,
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
@@ -3236,6 +3244,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_g2_smi_phy_read,
.phy_write = mv88e6xxx_g2_smi_phy_write,
@@ -3247,6 +3256,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
};
static const struct mv88e6xxx_ops mv88e6176_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
.get_eeprom = mv88e6xxx_g2_get_eeprom16,
.set_eeprom = mv88e6xxx_g2_set_eeprom16,
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
@@ -3260,6 +3270,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
+ /* MV88E6XXX_FAMILY_6185 */
.set_switch_mac = mv88e6xxx_g1_set_switch_mac,
.phy_read = mv88e6xxx_phy_ppu_read,
.phy_write = mv88e6xxx_phy_ppu_write,
@@ -3270,6 +3281,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
.get_eeprom = mv88e6xxx_g2_get_eeprom16,
.set_eeprom = mv88e6xxx_g2_set_eeprom16,
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
@@ -3283,6 +3295,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
+ /* MV88E6XXX_FAMILY_6320 */
.get_eeprom = mv88e6xxx_g2_get_eeprom16,
.set_eeprom = mv88e6xxx_g2_set_eeprom16,
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
@@ -3295,6 +3308,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
};
static const struct mv88e6xxx_ops mv88e6321_ops = {
+ /* MV88E6XXX_FAMILY_6321 */
.get_eeprom = mv88e6xxx_g2_get_eeprom16,
.set_eeprom = mv88e6xxx_g2_set_eeprom16,
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
@@ -3307,6 +3321,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_g2_smi_phy_read,
.phy_write = mv88e6xxx_g2_smi_phy_write,
@@ -3318,6 +3333,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
};
static const struct mv88e6xxx_ops mv88e6351_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_g2_smi_phy_read,
.phy_write = mv88e6xxx_g2_smi_phy_write,
@@ -3329,6 +3345,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
};
static const struct mv88e6xxx_ops mv88e6352_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
.get_eeprom = mv88e6xxx_g2_get_eeprom16,
.set_eeprom = mv88e6xxx_g2_set_eeprom16,
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
@@ -3342,6 +3359,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_g2_smi_phy_read,
.phy_write = mv88e6xxx_g2_smi_phy_write,
@@ -3352,6 +3370,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
.phy_read = mv88e6xxx_g2_smi_phy_read,
.phy_write = mv88e6xxx_g2_smi_phy_write,
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 09/11] net: dsa: mv88e6xxx: Add stats_get_strings to ops structure
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
Different families have different sets of statistics. Abstract this
using a stats_get_strings op. Each stat has a bitmap, and the ops
implementer uses a bit map mask to return a list of strings for the
statistics which apply for the family.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 47 ++++++++++++++++++++++++++++++++---
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 1 +
2 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 5d2c135b9175..cfbf0f0ff0dd 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -977,16 +977,15 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
return value;
}
-static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
- uint8_t *data)
+static void _mv88e6xxx_get_strings(struct mv88e6xxx_chip *chip,
+ uint8_t *data, int types)
{
- struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_hw_stat *stat;
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
stat = &mv88e6xxx_hw_stats[i];
- if (mv88e6xxx_has_stat(chip, stat)) {
+ if (stat->type & types) {
memcpy(data + j * ETH_GSTRING_LEN, stat->string,
ETH_GSTRING_LEN);
j++;
@@ -994,6 +993,27 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
}
}
+static void mv88e6095_get_strings(struct mv88e6xxx_chip *chip, uint8_t *data)
+{
+ _mv88e6xxx_get_strings(chip, data,
+ STATS_TYPE_BANK0 | STATS_TYPE_PORT);
+}
+
+static void mv88e6320_get_strings(struct mv88e6xxx_chip *chip, uint8_t *data)
+{
+ _mv88e6xxx_get_strings(chip, data,
+ STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
+}
+
+static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
+ uint8_t *data)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+
+ if (chip->info->ops->stats_get_strings)
+ chip->info->ops->stats_get_strings(chip, data);
+}
+
static int _mv88e6xxx_get_sset_count(struct mv88e6xxx_chip *chip, int types)
{
struct mv88e6xxx_hw_stat *stat;
@@ -3230,6 +3250,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -3242,6 +3263,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -3254,6 +3276,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -3266,6 +3289,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -3278,6 +3302,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -3290,6 +3315,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3303,6 +3329,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3318,6 +3345,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -3331,6 +3359,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3346,6 +3375,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3358,6 +3388,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3373,6 +3404,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3387,6 +3419,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
+ .stats_get_strings = mv88e6320_get_strings,
};
static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3401,6 +3434,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
+ .stats_get_strings = mv88e6320_get_strings,
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3414,6 +3448,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3427,6 +3462,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.port_set_speed = mv88e6185_port_set_speed,
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3442,6 +3478,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_speed = mv88e6352_port_set_speed,
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
+ .stats_get_strings = mv88e6095_get_strings,
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3456,6 +3493,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_init = mv88e6390_stats_init,
.stats_snapshot = mv88e6390_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
+ .stats_get_strings = mv88e6320_get_strings,
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3470,6 +3508,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_init = mv88e6390_stats_init,
.stats_snapshot = mv88e6390_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
+ .stats_get_strings = mv88e6320_get_strings,
};
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 4ff674d0e248..d3b8eed109a6 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -803,6 +803,7 @@ struct mv88e6xxx_ops {
*/
int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port);
int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip);
+ void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data);
};
#define STATS_TYPE_PORT BIT(0)
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 11/11] net: dsa: mv88e6xxx: Implement mv88e6390 get_stats
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
The mv88e6390 uses a different bit to select between bank0 and bank1
of the statistics. So implement an ops function for this, and pass the
selector bit to the generic stats read function. Also, the histogram
selection has moved for the mv88e6390, so abstract its selection as
well.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 33 ++++++++++++++++++++++++---------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 3 ++-
2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ebef214eb1e3..9e3cdc356ae2 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -837,8 +837,7 @@ static void _mv88e6xxx_stats_read(struct mv88e6xxx_chip *chip,
*val = 0;
err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
- GLOBAL_STATS_OP_READ_CAPTURED |
- GLOBAL_STATS_OP_HIST_RX_TX | stat);
+ GLOBAL_STATS_OP_READ_CAPTURED | stat);
if (err)
return;
@@ -923,7 +922,8 @@ static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_hw_stat *s,
- int port)
+ int port, u16 bank1_select,
+ u16 histogram)
{
u32 low;
u32 high = 0;
@@ -946,10 +946,10 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
}
break;
case STATS_TYPE_BANK1:
- reg = GLOBAL_STATS_OP_BANK_1;
+ reg = bank1_select;
/* fall through */
case STATS_TYPE_BANK0:
- reg |= s->reg;
+ reg |= s->reg | histogram;
_mv88e6xxx_stats_read(chip, reg, &low);
if (s->sizeof_stat == 8)
_mv88e6xxx_stats_read(chip, reg + 1, &high);
@@ -1031,7 +1031,8 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
}
static void _mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data, int types)
+ uint64_t *data, int types, u16 bank1_select,
+ u16 histogram)
{
struct mv88e6xxx_hw_stat *stat;
int i, j;
@@ -1040,7 +1041,8 @@ static void _mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
stat = &mv88e6xxx_hw_stats[i];
if (stat->type & types) {
data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
- bank1_select);
+ bank1_select,
+ histogram);
j++;
}
}
@@ -1050,14 +1052,25 @@ static void mv88e6095_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{
return _mv88e6xxx_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_PORT);
+ STATS_TYPE_BANK0 | STATS_TYPE_PORT,
+ 0, GLOBAL_STATS_OP_HIST_RX_TX);
}
static void mv88e6320_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{
return _mv88e6xxx_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
+ STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
+ GLOBAL_STATS_OP_BANK_1_BIT_9,
+ GLOBAL_STATS_OP_HIST_RX_TX);
+}
+
+static void mv88e6390_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
+{
+ return _mv88e6xxx_get_stats(chip, port, data,
+ STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
+ GLOBAL_STATS_OP_BANK_1_BIT_10, 0);
}
static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
@@ -3522,6 +3535,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_snapshot = mv88e6390_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
.stats_get_strings = mv88e6320_get_strings,
+ .stats_get_stats = mv88e6390_get_stats,
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3537,6 +3551,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_snapshot = mv88e6390_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
.stats_get_strings = mv88e6320_get_strings,
+ .stats_get_stats = mv88e6390_get_stats,
};
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index e0196450e8a2..9ec1fbd94a3a 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -296,7 +296,8 @@
#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY)
#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY)
#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY)
-#define GLOBAL_STATS_OP_BANK_1 BIT(9)
+#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9)
+#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10)
#define GLOBAL_STATS_COUNTER_32 0x1e
#define GLOBAL_STATS_COUNTER_01 0x1f
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 04/11] net: dsa: mv88e6xxx: Abstract stats_snapshot into ops structure
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
Taking a stats snapshot differs between same families. Abstract this
into an ops member.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 37 +++++++++++++++++++++++++++++++----
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 5 +++++
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 066d9479c981..65f34f1999e7 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -785,9 +785,6 @@ static int _mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
{
int err;
- if (mv88e6xxx_6320_family(chip) || mv88e6xxx_6352_family(chip))
- port = (port + 1) << 5;
-
/* Snapshot the hardware statistics counters for this port. */
err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
GLOBAL_STATS_OP_CAPTURE_PORT |
@@ -799,6 +796,21 @@ static int _mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
return _mv88e6xxx_stats_wait(chip);
}
+static int mv88e6320_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
+{
+ port = (port + 1) << 5;
+
+ return _mv88e6xxx_stats_snapshot(chip, port);
+}
+
+static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
+{
+ if (!chip->info->ops->stats_snapshot)
+ return -EOPNOTSUPP;
+
+ return chip->info->ops->stats_snapshot(chip, port);
+}
+
static void _mv88e6xxx_stats_read(struct mv88e6xxx_chip *chip,
int stat, u32 *val)
{
@@ -987,7 +999,7 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
mutex_lock(&chip->reg_lock);
- ret = _mv88e6xxx_stats_snapshot(chip, port);
+ ret = mv88e6xxx_stats_snapshot(chip, port);
if (ret < 0) {
mutex_unlock(&chip->reg_lock);
return;
@@ -3146,6 +3158,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = _mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -3155,6 +3168,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = _mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -3164,6 +3178,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = _mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -3173,6 +3188,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = _mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -3182,6 +3198,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = _mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -3191,6 +3208,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = _mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3201,6 +3219,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3213,6 +3232,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .stats_snapshot = mv88e6320_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -3223,6 +3243,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3235,6 +3256,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .stats_snapshot = mv88e6320_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3244,6 +3266,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = _mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3256,6 +3279,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .stats_snapshot = mv88e6320_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3267,6 +3291,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = mv88e6320_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3278,6 +3303,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = mv88e6320_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3288,6 +3314,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3298,6 +3325,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .stats_snapshot = mv88e6xxx_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3310,6 +3338,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .stats_snapshot = mv88e6320_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 48915e5e3a3d..fd5352bf7625 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -793,6 +793,11 @@ struct mv88e6xxx_ops {
* Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value.
*/
int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed);
+
+ /* Snapshot the statistics for a port. The statistics can then
+ * be read back a leisure but still with a consistent view.
+ */
+ int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port);
};
enum stat_type {
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 10/11] net: dsa: mv88e6xxx: Add stats_get_stats to ops structure
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
Different families have different sets of statistics. Abstract this
using a stats_get_stats op. The mv88e6390 needs a different
implementation, which will be added later.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 84 +++++++++++++++++++++++------------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 2 +
2 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index cfbf0f0ff0dd..ebef214eb1e3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -921,25 +921,6 @@ static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
{ "out_management", 4, 0x1f, STATS_TYPE_BANK1, },
};
-static bool mv88e6xxx_has_stat(struct mv88e6xxx_chip *chip,
- struct mv88e6xxx_hw_stat *stat)
-{
- switch (stat->type) {
- case STATS_TYPE_BANK0:
- return true;
- case STATS_TYPE_BANK1:
- return mv88e6xxx_6320_family(chip);
- case STATS_TYPE_PORT:
- return mv88e6xxx_6095_family(chip) ||
- mv88e6xxx_6185_family(chip) ||
- mv88e6xxx_6097_family(chip) ||
- mv88e6xxx_6165_family(chip) ||
- mv88e6xxx_6351_family(chip) ||
- mv88e6xxx_6352_family(chip);
- }
- return false;
-}
-
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_hw_stat *s,
int port)
@@ -1049,13 +1030,48 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
return 0;
}
+static void _mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data, int types)
+{
+ struct mv88e6xxx_hw_stat *stat;
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
+ stat = &mv88e6xxx_hw_stats[i];
+ if (stat->type & types) {
+ data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
+ bank1_select);
+ j++;
+ }
+ }
+}
+
+static void mv88e6095_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
+{
+ return _mv88e6xxx_get_stats(chip, port, data,
+ STATS_TYPE_BANK0 | STATS_TYPE_PORT);
+}
+
+static void mv88e6320_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
+{
+ return _mv88e6xxx_get_stats(chip, port, data,
+ STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
+}
+
+static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
+{
+ if (chip->info->ops->stats_get_stats)
+ chip->info->ops->stats_get_stats(chip, port, data);
+}
+
static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
uint64_t *data)
{
struct mv88e6xxx_chip *chip = ds->priv;
- struct mv88e6xxx_hw_stat *stat;
int ret;
- int i, j;
mutex_lock(&chip->reg_lock);
@@ -1064,13 +1080,8 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
mutex_unlock(&chip->reg_lock);
return;
}
- for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
- stat = &mv88e6xxx_hw_stats[i];
- if (mv88e6xxx_has_stat(chip, stat)) {
- data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port);
- j++;
- }
- }
+
+ mv88e6xxx_get_stats(chip, port, data);
mutex_unlock(&chip->reg_lock);
}
@@ -3251,6 +3262,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -3264,6 +3276,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -3277,6 +3290,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -3290,6 +3304,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -3303,6 +3318,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -3316,6 +3332,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3330,6 +3347,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3346,6 +3364,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -3360,6 +3379,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3376,6 +3396,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3389,6 +3410,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_snapshot = _mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3405,6 +3427,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3420,6 +3443,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
.stats_get_strings = mv88e6320_get_strings,
+ .stats_get_stats = mv88e6320_get_stats,
};
static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3435,6 +3459,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6320_get_sset_count,
.stats_get_strings = mv88e6320_get_strings,
+ .stats_get_stats = mv88e6320_get_stats,
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3449,6 +3474,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3463,6 +3489,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.stats_snapshot = mv88e6xxx_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3479,6 +3506,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.stats_snapshot = mv88e6320_stats_snapshot,
.stats_get_sset_count = mv88e6095_get_sset_count,
.stats_get_strings = mv88e6095_get_strings,
+ .stats_get_stats = mv88e6095_get_stats,
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index d3b8eed109a6..e0196450e8a2 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -804,6 +804,8 @@ struct mv88e6xxx_ops {
int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port);
int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip);
void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data);
+ void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data);
};
#define STATS_TYPE_PORT BIT(0)
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 06/11] net: dsa: mv88e6xxx: Add mv88e6390 stats snapshot operation
From: Andrew Lunn @ 2016-11-11 2:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vivien Didelot, Andrew Lunn
In-Reply-To: <1478832823-31471-1-git-send-email-andrew@lunn.ch>
The MV88E6390 has a control register for what the histogram statistics
actually contain. This means the stat_snapshot method should not set
this information. So implement the 6390 stats_snapshot function without
these bits.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 18 ++++++++++++++++++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 4 +++-
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d4fc12d7021a..82e57aac00f1 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -803,6 +803,22 @@ static int mv88e6320_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
return _mv88e6xxx_stats_snapshot(chip, port);
}
+static int mv88e6390_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
+{
+ int err;
+
+ port = (port + 1) << 5;
+
+ /* Snapshot the hardware statistics counters for this port. */
+ err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
+ GLOBAL_STATS_OP_CAPTURE_PORT | port);
+ if (err)
+ return err;
+
+ /* Wait for the snapshotting to complete. */
+ return _mv88e6xxx_stats_wait(chip);
+}
+
static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
{
if (!chip->info->ops->stats_snapshot)
@@ -3367,6 +3383,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
+ .stats_snapshot = mv88e6390_stats_snapshot,
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3378,6 +3395,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390x_port_set_speed,
+ .stats_snapshot = mv88e6390_stats_snapshot,
};
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index fd5352bf7625..147f1f3a817b 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -283,7 +283,9 @@
#define GLOBAL_CONTROL_2 0x1c
#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000
#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000
-
+#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6)
+#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6)
+#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6)
#define GLOBAL_STATS_OP 0x1d
#define GLOBAL_STATS_OP_BUSY BIT(15)
#define GLOBAL_STATS_OP_NOP (0 << 12)
--
2.10.2
^ permalink raw reply related
* Re: [PATCH] net: phy: marvell: optimize logic for page changing during init
From: Florian Fainelli @ 2016-11-11 2:34 UTC (permalink / raw)
To: Uwe Kleine-König; +Cc: netdev, Andrew Lunn
In-Reply-To: <20161110140301.13381-1-uwe@kleine-koenig.org>
Le 10/11/2016 à 06:03, Uwe Kleine-König a écrit :
> Instead of remembering if the page was changed, just compare the current
> page to the saved one. This is easier and has the advantage to save a
> register write if the page was already restored.
Seems reasonable to me:
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
>
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
> ---
> drivers/net/phy/marvell.c | 6 ++----
> 1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
> index c2dcf02df202..fa31f50824d3 100644
> --- a/drivers/net/phy/marvell.c
> +++ b/drivers/net/phy/marvell.c
> @@ -361,7 +361,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev)
> static int marvell_of_reg_init(struct phy_device *phydev)
> {
> const __be32 *paddr;
> - int len, i, saved_page, current_page, page_changed, ret;
> + int len, i, saved_page, current_page, ret;
>
> if (!phydev->mdio.dev.of_node)
> return 0;
> @@ -374,7 +374,6 @@ static int marvell_of_reg_init(struct phy_device *phydev)
> saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
> if (saved_page < 0)
> return saved_page;
> - page_changed = 0;
> current_page = saved_page;
>
> ret = 0;
> @@ -388,7 +387,6 @@ static int marvell_of_reg_init(struct phy_device *phydev)
>
> if (reg_page != current_page) {
> current_page = reg_page;
> - page_changed = 1;
> ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
> if (ret < 0)
> goto err;
> @@ -411,7 +409,7 @@ static int marvell_of_reg_init(struct phy_device *phydev)
>
> }
> err:
> - if (page_changed) {
> + if (current_page != saved_page) {
> i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
> if (ret == 0)
> ret = i;
>
--
Florian
^ permalink raw reply
* Re: [PATCH 3/3] vhost_net: tx support batching
From: Jason Wang @ 2016-11-11 2:27 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, linux-kernel
In-Reply-To: <20161109215753-mutt-send-email-mst@kernel.org>
On 2016年11月10日 04:05, Michael S. Tsirkin wrote:
> On Wed, Nov 09, 2016 at 03:38:33PM +0800, Jason Wang wrote:
>> This patch tries to utilize tuntap rx batching by peeking the tx
>> virtqueue during transmission, if there's more available buffers in
>> the virtqueue, set MSG_MORE flag for a hint for tuntap to batch the
>> packets. The maximum number of batched tx packets were specified
>> through a module parameter: tx_bached.
>>
>> When use 16 as tx_batched:
> When using
>
>> Pktgen test shows 16% on tx pps in guest.
>> Netperf test does not show obvious regression.
> Why doesn't netperf benefit?
This is probably because the tests (4VCPU, 1queue, TCP, mlx4) does not
produce 100% stress on vhost thread. In pktgen test, 100% stress on
vhost thread is achieved easily.
>
>> For safety, 1 were used as the default value for tx_batched.
> s/were used/is used/
>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
> These tests unfortunately only run a single flow.
> The concern would be whether this increases latency when
> NIC is busy with other flows, so I think this is what
> you need to test.
Multiple flows were tested too, no obvious improvement/regression were
found.
>
>
>> ---
>> drivers/vhost/net.c | 15 ++++++++++++++-
>> drivers/vhost/vhost.c | 1 +
>> drivers/vhost/vhost.h | 1 +
>> 3 files changed, 16 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
>> index 5dc128a..51c378e 100644
>> --- a/drivers/vhost/net.c
>> +++ b/drivers/vhost/net.c
>> @@ -35,6 +35,10 @@ module_param(experimental_zcopytx, int, 0444);
>> MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
>> " 1 -Enable; 0 - Disable");
>>
>> +static int tx_batched = 1;
>> +module_param(tx_batched, int, 0444);
>> +MODULE_PARM_DESC(tx_batched, "Number of patches batched in TX");
>> +
>> /* Max number of bytes transferred before requeueing the job.
>> * Using this limit prevents one virtqueue from starving others. */
>> #define VHOST_NET_WEIGHT 0x80000
> I think we should do some tests and find a good default.
Ok, will test 4 and 32 to see if there's any difference. (Btw, 16 were
chosed since dpdk tends to batch 16 packet during TX).
Thanks
^ permalink raw reply
* Re: [PATCH 2/3] vhost: better detection of available buffers
From: Jason Wang @ 2016-11-11 2:18 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, linux-kernel
In-Reply-To: <20161109215513-mutt-send-email-mst@kernel.org>
On 2016年11月10日 03:57, Michael S. Tsirkin wrote:
> On Wed, Nov 09, 2016 at 03:38:32PM +0800, Jason Wang wrote:
>> We should use vq->last_avail_idx instead of vq->avail_idx in the
>> checking of vhost_vq_avail_empty() since latter is the cached avail
>> index from guest but we want to know if there's pending available
>> buffers in the virtqueue.
>>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
> I'm not sure why is this patch here. Is it related to
> batching somehow?
Yes, we need to know whether or not there's still buffers left in the
virtqueue, so need to check last_avail_idx. Otherwise, we're checking if
guest has submitted new buffers.
>
>
>> ---
>> drivers/vhost/vhost.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
>> index c6f2d89..fdf4cdf 100644
>> --- a/drivers/vhost/vhost.c
>> +++ b/drivers/vhost/vhost.c
>> @@ -2230,7 +2230,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
>> if (r)
>> return false;
>>
>> - return vhost16_to_cpu(vq, avail_idx) == vq->avail_idx;
>> + return vhost16_to_cpu(vq, avail_idx) == vq->last_avail_idx;
>> }
>> EXPORT_SYMBOL_GPL(vhost_vq_avail_empty);
> That might be OK for TX but it's probably wrong for RX
> where the fact that used != avail does not mean
> we have enough space to store the packet.
Right, but it's no harm since it was just a hint, handle_rx() can handle
this situation.
>
> Maybe we should just rename this to vhost_vq_avail_unchanged
> to clarify usage.
>
Ok.
>>
>> --
>> 2.7.4
^ permalink raw reply
* Re: [PATCH 1/3] tuntap: rx batching
From: Jason Wang @ 2016-11-11 2:07 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, linux-kernel
In-Reply-To: <20161109183259-mutt-send-email-mst@kernel.org>
On 2016年11月10日 00:38, Michael S. Tsirkin wrote:
> On Wed, Nov 09, 2016 at 03:38:31PM +0800, Jason Wang wrote:
>> Backlog were used for tuntap rx, but it can only process 1 packet at
>> one time since it was scheduled during sendmsg() synchronously in
>> process context. This lead bad cache utilization so this patch tries
>> to do some batching before call rx NAPI. This is done through:
>>
>> - accept MSG_MORE as a hint from sendmsg() caller, if it was set,
>> batch the packet temporarily in a linked list and submit them all
>> once MSG_MORE were cleared.
>> - implement a tuntap specific NAPI handler for processing this kind of
>> possible batching. (This could be done by extending backlog to
>> support skb like, but using a tun specific one looks cleaner and
>> easier for future extension).
>>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
> So why do we need an extra queue?
The idea was borrowed from backlog to allow some kind of bulking and
avoid spinlock on each dequeuing.
> This is not what hardware devices do.
> How about adding the packet to queue unconditionally, deferring
> signalling until we get sendmsg without MSG_MORE?
Then you need touch spinlock when dequeuing each packet.
>
>
>> ---
>> drivers/net/tun.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
>> 1 file changed, 65 insertions(+), 6 deletions(-)
>>
[...]
>> rxhash = skb_get_hash(skb);
>> - netif_rx_ni(skb);
>> + skb_queue_tail(&tfile->socket.sk->sk_write_queue, skb);
>> +
>> + if (!more) {
>> + local_bh_disable();
>> + napi_schedule(&tfile->napi);
>> + local_bh_enable();
> Why do we need to disable bh here? I thought napi_schedule can
> be called from any context.
Yes, it's unnecessary. Will remove.
Thanks
^ permalink raw reply
* RE: [patch net-next 5/8] Introduce sample tc action
From: Yotam Gigi @ 2016-11-10 19:58 UTC (permalink / raw)
To: John Fastabend, Jiri Pirko, netdev@vger.kernel.org
Cc: davem@davemloft.net, Ido Schimmel, Elad Raz, Nogah Frankel,
Or Gerlitz, jhs@mojatatu.com, geert+renesas@glider.be,
stephen@networkplumber.org, xiyou.wangcong@gmail.com,
linux@roeck-us.net, roopa@cumulusnetworks.com
In-Reply-To: <5824CCB0.4090302@gmail.com>
>-----Original Message-----
>From: John Fastabend [mailto:john.fastabend@gmail.com]
>Sent: Thursday, November 10, 2016 9:38 PM
>To: Jiri Pirko <jiri@resnulli.us>; netdev@vger.kernel.org
>Cc: davem@davemloft.net; Yotam Gigi <yotamg@mellanox.com>; Ido Schimmel
><idosch@mellanox.com>; Elad Raz <eladr@mellanox.com>; Nogah Frankel
><nogahf@mellanox.com>; Or Gerlitz <ogerlitz@mellanox.com>;
>jhs@mojatatu.com; geert+renesas@glider.be; stephen@networkplumber.org;
>xiyou.wangcong@gmail.com; linux@roeck-us.net; roopa@cumulusnetworks.com
>Subject: Re: [patch net-next 5/8] Introduce sample tc action
>
>On 16-11-10 11:35 AM, John Fastabend wrote:
>> On 16-11-10 03:23 AM, Jiri Pirko wrote:
>>> From: Yotam Gigi <yotamg@mellanox.com>
>>>
>>> This action allow the user to sample traffic matched by tc classifier.
>>> The sampling consists of choosing packets randomly, truncating them,
>>> adding some informative metadata regarding the interface and the original
>>> packet size and mark them with specific mark, to allow further tc rules to
>>> match and process. The marked sample packets are then injected into the
>>> device ingress qdisc using netif_receive_skb.
>>>
>>> The packets metadata is packed using the ife encapsulation protocol, and
>>> the outer packet's ethernet dest, source and eth_type, along with the
>>> rate, mark and the optional truncation size can be configured from
>>> userspace.
>>>
>>> Example:
>>> To sample ingress traffic from interface eth1, and redirect the sampled
>>> the sampled packets to interface dummy0, one may use the commands:
>>>
>>> tc qdisc add dev eth1 handle ffff: ingress
>>>
>>> tc filter add dev eth1 parent ffff: \
>>> matchall action sample rate 12 mark 17
>>>
>>> tc filter add parent ffff: dev eth1 protocol all \
>>> u32 match mark 17 0xff \
>>> action mirred egress redirect dev dummy0
>>>
>>> Where the first command adds an ingress qdisc and the second starts
>>> sampling every 12'th packet on dev eth1 and marks the sampled packets with
>>> 17. The third command catches the sampled packets, which are marked with
>>> 17, and redirects them to dev dummy0.
>>
>> The sampling algorithm was not randomized based on the above commit
>> log? It really needs to be for all the reasons Roopa mentioned earlier.
>> Did I miss some email on why it didn't get implemented?
>>
>> Also there was an indication the already is actually implemented
>> correctly so don't we need the hw/sw to behave the same. The whole
>> argument about sw/hw parity, etc.
>
>sorry bit of a typo there corrected 2nd paragraph here...
>
>Also there was an indication the hardware is already implemented \
>correctly so don't we need the hw/sw to behave the same. The argument
>about sw/hw parity, etc.
Our hardware currently does not support sampling with random behavior, so
we did implement it in software too.
But, the API is extensible and it is possible to add a random keyword to
the tc action to allow random sampling. In that case, the keyword will be
implemented in sw only and our driver will fail offloading it.
>
>>
>>>
>>> Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
>>> Signed-off-by: Jiri Pirko <jiri@mellanox.com>
>>> ---
>>
^ permalink raw reply
* Re: [PATCH] bpf: fix range arithmetic for bpf map access
From: David Miller @ 2016-11-11 0:46 UTC (permalink / raw)
To: jbacik; +Cc: jannh, daniel, ast, netdev
In-Reply-To: <1478823492-7335-1-git-send-email-jbacik@fb.com>
From: Josef Bacik <jbacik@fb.com>
Date: Thu, 10 Nov 2016 19:18:12 -0500
> ---
> Sorry Jann, I saw your response last night and then promptly forgot about it,
> here's the git-send-email version.
GIT will remove everything after the first "---" line from the commit message,
so you've essentially submitted an empty commit message here.
Put such "---" annotations after the commit message, not at the
beginning.
^ permalink raw reply
* [PATCH] bpf: fix range arithmetic for bpf map access
From: Josef Bacik @ 2016-11-11 0:18 UTC (permalink / raw)
To: jannh, daniel, ast, davem, netdev
In-Reply-To: <CAG48ez0DyDoySPEkNqYnSEZpTXuuP2xheSuc_EQ+ZzmSwOGy6Q@mail.gmail.com>
---
Sorry Jann, I saw your response last night and then promptly forgot about it,
here's the git-send-email version.
---
I made some invalid assumptions with BPF_AND and BPF_MOD that could result in
invalid accesses to bpf map entries. Fix this up by doing a few things
1) Kill BPF_MOD support. This doesn't actually get used by the compiler in real
life and just adds extra complexity.
2) Fix the logic for BPF_AND. If the min value is negative then that is the new
minimum, otherwise it is unconditionally 0.
3) Don't do operations on the ranges if they are set to the limits, as they are
by definition undefined, and allowing arithmetic operations on those values
could make them appear valid when they really aren't.
This fixes the testcase provided by Jann as well as a few other theoretical
problems.
Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
---
include/linux/bpf_verifier.h | 3 +-
kernel/bpf/verifier.c | 65 ++++++++++++++++++++++++++++----------------
2 files changed, 44 insertions(+), 24 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index ac5b393..15ceb7f 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -22,7 +22,8 @@ struct bpf_reg_state {
* Used to determine if any memory access using this register will
* result in a bad access.
*/
- u64 min_value, max_value;
+ s64 min_value;
+ u64 max_value;
u32 id;
union {
/* valid when type == CONST_IMM | PTR_TO_STACK | UNKNOWN_VALUE */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9002575..840533a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -234,8 +234,8 @@ static void print_verifier_state(struct bpf_verifier_state *state)
reg->map_ptr->value_size,
reg->id);
if (reg->min_value != BPF_REGISTER_MIN_RANGE)
- verbose(",min_value=%llu",
- (unsigned long long)reg->min_value);
+ verbose(",min_value=%lld",
+ (long long)reg->min_value);
if (reg->max_value != BPF_REGISTER_MAX_RANGE)
verbose(",max_value=%llu",
(unsigned long long)reg->max_value);
@@ -1490,7 +1490,7 @@ static void check_reg_overflow(struct bpf_reg_state *reg)
{
if (reg->max_value > BPF_REGISTER_MAX_RANGE)
reg->max_value = BPF_REGISTER_MAX_RANGE;
- if ((s64)reg->min_value < BPF_REGISTER_MIN_RANGE)
+ if (reg->min_value < BPF_REGISTER_MIN_RANGE)
reg->min_value = BPF_REGISTER_MIN_RANGE;
}
@@ -1498,7 +1498,8 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
struct bpf_insn *insn)
{
struct bpf_reg_state *regs = env->cur_state.regs, *dst_reg;
- u64 min_val = BPF_REGISTER_MIN_RANGE, max_val = BPF_REGISTER_MAX_RANGE;
+ s64 min_val = BPF_REGISTER_MIN_RANGE;
+ u64 max_val = BPF_REGISTER_MAX_RANGE;
bool min_set = false, max_set = false;
u8 opcode = BPF_OP(insn->code);
@@ -1534,22 +1535,45 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
return;
}
+ /* If one of our values was at the end of our ranges then we can't just
+ * do our normal operations to the register, we need to set the values
+ * to the min/max since they are undefined.
+ */
+ if (min_val == BPF_REGISTER_MIN_RANGE)
+ dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
+ if (max_val == BPF_REGISTER_MAX_RANGE)
+ dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+
switch (opcode) {
case BPF_ADD:
- dst_reg->min_value += min_val;
- dst_reg->max_value += max_val;
+ if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+ dst_reg->min_value += min_val;
+ if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+ dst_reg->max_value += max_val;
break;
case BPF_SUB:
- dst_reg->min_value -= min_val;
- dst_reg->max_value -= max_val;
+ if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+ dst_reg->min_value -= min_val;
+ if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+ dst_reg->max_value -= max_val;
break;
case BPF_MUL:
- dst_reg->min_value *= min_val;
- dst_reg->max_value *= max_val;
+ if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+ dst_reg->min_value *= min_val;
+ if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+ dst_reg->max_value *= max_val;
break;
case BPF_AND:
- /* & is special since it could end up with 0 bits set. */
- dst_reg->min_value &= min_val;
+ /* & is special since it's could be any value within our range,
+ * including 0. But if the thing we're AND'ing against is
+ * negative and we're negative then that's the minimum value,
+ * otherwise the minimum will always be 0.
+ */
+ if (min_val < 0 && dst_reg->min_value < 0)
+ dst_reg->min_value = min_t(s64, dst_reg->min_value,
+ min_val);
+ else
+ dst_reg->min_value = 0;
dst_reg->max_value = max_val;
break;
case BPF_LSH:
@@ -1559,24 +1583,19 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
*/
if (min_val > ilog2(BPF_REGISTER_MAX_RANGE))
dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
- else
+ else if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
dst_reg->min_value <<= min_val;
if (max_val > ilog2(BPF_REGISTER_MAX_RANGE))
dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
- else
+ else if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
dst_reg->max_value <<= max_val;
break;
case BPF_RSH:
- dst_reg->min_value >>= min_val;
- dst_reg->max_value >>= max_val;
- break;
- case BPF_MOD:
- /* % is special since it is an unsigned modulus, so the floor
- * will always be 0.
- */
- dst_reg->min_value = 0;
- dst_reg->max_value = max_val - 1;
+ if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+ dst_reg->min_value >>= min_val;
+ if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+ dst_reg->max_value >>= max_val;
break;
default:
reset_reg_range_values(regs, insn->dst_reg);
--
2.5.5
^ 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