Netdev List
 help / color / mirror / Atom feed
* Re: [net PATCH] net: virtio: cap mtu when XDP programs are running
From: John Fastabend @ 2017-01-09 23:49 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Jason Wang, john.r.fastabend, netdev, alexei.starovoitov, daniel
In-Reply-To: <20170110012044-mutt-send-email-mst@kernel.org>

On 17-01-09 03:24 PM, Michael S. Tsirkin wrote:
> On Mon, Jan 09, 2017 at 03:13:15PM -0800, John Fastabend wrote:
>> On 17-01-09 03:05 PM, Michael S. Tsirkin wrote:
>>> On Thu, Jan 05, 2017 at 11:09:14AM +0800, Jason Wang wrote:
>>>>
>>>>
>>>> On 2017年01月05日 02:57, John Fastabend wrote:
>>>>> [...]
>>>>>
>>>>>> On 2017年01月04日 00:48, John Fastabend wrote:
>>>>>>> On 17-01-02 10:14 PM, Jason Wang wrote:
>>>>>>>> On 2017年01月03日 06:30, John Fastabend wrote:
>>>>>>>>> XDP programs can not consume multiple pages so we cap the MTU to
>>>>>>>>> avoid this case. Virtio-net however only checks the MTU at XDP
>>>>>>>>> program load and does not block MTU changes after the program
>>>>>>>>> has loaded.
>>>>>>>>>
>>>>>>>>> This patch sets/clears the max_mtu value at XDP load/unload time.
>>>>>>>>>
>>>>>>>>> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
>>>>>>>>> ---
>>>>> [...]
>>>>>
>>>>>>> OK so this logic is a bit too simply. When it resets the max_mtu I guess it
>>>>>>> needs to read the mtu via
>>>>>>>
>>>>>>>      virtio_cread16(vdev, ...)
>>>>>>>
>>>>>>> or we may break the negotiated mtu.
>>>>>> Yes, this is a problem (even use ETH_MAX_MTU). We may need a method to notify
>>>>>> the device about the mtu in this case which is not supported by virtio now.
>>>>> Note this is not really a XDP specific problem. The guest can change the MTU
>>>>> after init time even without XDP which I assume should ideally result in a
>>>>> notification if the MTU is negotiated.
>>>>
>>>> Yes, Michael, do you think we need add some mechanism to notify host about
>>>> MTU change in this case?
>>>>
>>>> Thanks
>>>
>>> Why does host care?
>>>
>>
>> Well the guest will drop packets after mtu has been reduced.
> 
> I didn't know. What place in code does this?
> 

hmm in many of the drivers it is convention to use the mtu to set the rx
buffer sizes and a receive side max length filter. For example in the Intel
drivers if a packet with length greater than MTU + some headroom is received we
drop it. I guess in the networking stack RX path though nothing forces this and
virtio doesn't have any code to drop packets on rx size.

In virtio I don't see any existing case currently. In the XDP case though we
need to ensure packets fit in a page for the time being which is why I was
looking at this code and generated this patch.

>> Although the guest
>> by reducing its MTU in some sense must expect this. Likewise if the host were
>> to change MTU after virtio_net probe time the guest would not learn about it.
> 
> The spec explicitly disallows this last one.

OK. By the way were do I get the latest source I see the published virtio1.0 at
the oasis-open.org site but it doesn't mention the MTU logic.

> 
>> I think at best negotiating the mtu is just a hint? If system _really_ cares
>> we could use lldp or some other out of band mechanism to learn/set/adjust MTU
>> on both systems and it would be more robust. I'm not actually convinced this
>> is a problem in bare metal systems we have the same issue with physical
>> switches and solve it out of band via configuration, protocols, etc.
>>
>> .John
> 
> ATM we don't have negotiation in virtio, just a max mtu limit.
> This doesn't free guest from configuring mtu correctly,
> just helps it avoid doing something clearly bogus.
> 

Yep. I'm fine with calling it a misconfiguration if the guest reduces the MTU
and the host continues to send packets @ advertised MTU.

^ permalink raw reply

* RE: Marvell Phy (1510) issue since v4.7 kernel
From: Kwok, WingMan @ 2017-01-09 23:48 UTC (permalink / raw)
  To: Andrew Lunn, Karicheri, Muralidharan; +Cc: netdev@vger.kernel.org
In-Reply-To: <20170109225641.GB22820@lunn.ch>


Hi Andrew,


> -----Original Message-----
> From: Andrew Lunn [mailto:andrew@lunn.ch]
> Sent: Monday, January 09, 2017 5:57 PM
> To: Karicheri, Muralidharan
> Cc: netdev@vger.kernel.org; Kwok, WingMan
> Subject: Re: Marvell Phy (1510) issue since v4.7 kernel
> 
> On Mon, Jan 09, 2017 at 05:38:39PM -0500, Murali Karicheri wrote:
> > Hello Charles-Antoine, Andrew,
> >
> > We have recently upgraded our kernel to v4.9 and started seeing an
> issue
> > on our Keystone EVMs (K2E/L) that uses Marvel Phy 1510. The issue is
> that
> > when we do a reboot command from the Linux console or do a SoC
> reset,
> > the DHCP times out at U-Boot due to Phy auto negotiation failure.
> This works
> > fine when the board is power cycled.
> 
> I've seen similar before. What version of kernel are you upgrading
> from?
> 
> The problem i've had is that on shutdown/reboot, linux powers the PHYs
> off. The uboot i have does not power them on again. Clearly a uboot
> issue, it should not assume the PHYs are powered on.
> 
> I work around this with a uboot command:
> 
> mii write 1 0 0x3100
> 
> where the PHY is at address 1 on the bus. This writes to register 0,
> and the import bit which needs setting to 0 is bit 11.
> 
> If mii read shows bit 11 is set, you know there uboot did not power up
> the PHY.
> 
>     Andrew

Thanks for the suggestion.

But when kernel is reboot into u-boot, "mii read 0 0" shows
0x1000, ie. bit 11 is 0, and still the phy auto-nego times out.

The "mii read 0 0" shows the same value 0x1000 if we power cycle
board and the phy auto-nego works fine.

Could there be some other registers that need to be re-configured?

We are upgrading from kernel v4.4 to v4.9. And the u-boot is 2016.05.

Regards,
WingMan

^ permalink raw reply

* [PATCH iproute2] Add support for rt_protos.d
From: David Ahern @ 2017-01-09 23:43 UTC (permalink / raw)
  To: netdev, stephen; +Cc: David Ahern

Add support for reading proto id/name mappings from rt_protos.d
directory. Allows users to have custom protocol values converted
to human friendly names.

Each file under rt_protos.d has the 'id name' format used by
rt_protos. Only .conf files are read and parsed.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
---
 etc/iproute2/rt_protos.d/README |  3 +++
 lib/rt_names.c                  | 27 +++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)
 create mode 100644 etc/iproute2/rt_protos.d/README

diff --git a/etc/iproute2/rt_protos.d/README b/etc/iproute2/rt_protos.d/README
new file mode 100644
index 000000000000..723509ce56b6
--- /dev/null
+++ b/etc/iproute2/rt_protos.d/README
@@ -0,0 +1,3 @@
+Each file in this directory is an rt_protos configuration file. iproute2
+commands scan this directory processing all files that end in '.conf'.
+
diff --git a/lib/rt_names.c b/lib/rt_names.c
index c66cb1e439e3..7553288eeb18 100644
--- a/lib/rt_names.c
+++ b/lib/rt_names.c
@@ -142,9 +142,36 @@ static int rtnl_rtprot_init;
 
 static void rtnl_rtprot_initialize(void)
 {
+	struct dirent *de;
+	DIR *d;
+
 	rtnl_rtprot_init = 1;
 	rtnl_tab_initialize(CONFDIR "/rt_protos",
 			    rtnl_rtprot_tab, 256);
+
+	d = opendir(CONFDIR "/rt_protos.d");
+	if (!d)
+		return;
+
+	while ((de = readdir(d)) != NULL) {
+		char path[PATH_MAX];
+		size_t len;
+
+		if (*de->d_name == '.')
+			continue;
+
+		/* only consider filenames ending in '.conf' */
+		len = strlen(de->d_name);
+		if (len <= 5)
+			continue;
+		if (strcmp(de->d_name + len - 5, ".conf"))
+			continue;
+
+		snprintf(path, sizeof(path), CONFDIR "/rt_protos.d/%s",
+			 de->d_name);
+		rtnl_tab_initialize(path, rtnl_rtprot_tab, 256);
+	}
+	closedir(d);
 }
 
 const char *rtnl_rtprot_n2a(int id, char *buf, int len)
-- 
2.1.4

^ permalink raw reply related

* Re: [net PATCH] net: virtio: cap mtu when XDP programs are running
From: Michael S. Tsirkin @ 2017-01-09 23:24 UTC (permalink / raw)
  To: John Fastabend
  Cc: Jason Wang, john.r.fastabend, netdev, alexei.starovoitov, daniel
In-Reply-To: <5874190B.9050505@gmail.com>

On Mon, Jan 09, 2017 at 03:13:15PM -0800, John Fastabend wrote:
> On 17-01-09 03:05 PM, Michael S. Tsirkin wrote:
> > On Thu, Jan 05, 2017 at 11:09:14AM +0800, Jason Wang wrote:
> >>
> >>
> >> On 2017年01月05日 02:57, John Fastabend wrote:
> >>> [...]
> >>>
> >>>> On 2017年01月04日 00:48, John Fastabend wrote:
> >>>>> On 17-01-02 10:14 PM, Jason Wang wrote:
> >>>>>> On 2017年01月03日 06:30, John Fastabend wrote:
> >>>>>>> XDP programs can not consume multiple pages so we cap the MTU to
> >>>>>>> avoid this case. Virtio-net however only checks the MTU at XDP
> >>>>>>> program load and does not block MTU changes after the program
> >>>>>>> has loaded.
> >>>>>>>
> >>>>>>> This patch sets/clears the max_mtu value at XDP load/unload time.
> >>>>>>>
> >>>>>>> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
> >>>>>>> ---
> >>> [...]
> >>>
> >>>>> OK so this logic is a bit too simply. When it resets the max_mtu I guess it
> >>>>> needs to read the mtu via
> >>>>>
> >>>>>      virtio_cread16(vdev, ...)
> >>>>>
> >>>>> or we may break the negotiated mtu.
> >>>> Yes, this is a problem (even use ETH_MAX_MTU). We may need a method to notify
> >>>> the device about the mtu in this case which is not supported by virtio now.
> >>> Note this is not really a XDP specific problem. The guest can change the MTU
> >>> after init time even without XDP which I assume should ideally result in a
> >>> notification if the MTU is negotiated.
> >>
> >> Yes, Michael, do you think we need add some mechanism to notify host about
> >> MTU change in this case?
> >>
> >> Thanks
> > 
> > Why does host care?
> > 
> 
> Well the guest will drop packets after mtu has been reduced.

I didn't know. What place in code does this?

> Although the guest
> by reducing its MTU in some sense must expect this. Likewise if the host were
> to change MTU after virtio_net probe time the guest would not learn about it.

The spec explicitly disallows this last one.

> I think at best negotiating the mtu is just a hint? If system _really_ cares
> we could use lldp or some other out of band mechanism to learn/set/adjust MTU
> on both systems and it would be more robust. I'm not actually convinced this
> is a problem in bare metal systems we have the same issue with physical
> switches and solve it out of band via configuration, protocols, etc.
> 
> .John

ATM we don't have negotiation in virtio, just a max mtu limit.
This doesn't free guest from configuring mtu correctly,
just helps it avoid doing something clearly bogus.

-- 
MST

^ permalink raw reply

* [PATCH net-next v3] net: dsa: make "label" property optional for dsa2
From: Vivien Didelot @ 2017-01-09 23:13 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
	Andrew Lunn, Jiri Pirko, Uwe Kleine-König, Andrey Smirnov,
	Vivien Didelot

In the new DTS bindings for DSA (dsa2), the "ethernet" and "link"
phandles are respectively mandatory and exclusive to CPU port and DSA
link device tree nodes.

Simplify dsa2.c a bit by checking the presence of such phandle instead
of checking the redundant "label" property.

Then the Linux philosophy for Ethernet switch ports is to expose them to
userspace as standard NICs by default. Thus use the standard enumerated
"eth%d" device name if no "label" property is provided for a user port.
This allows to save DTS files from subjective net device names.

If one wants to rename an interface, udev rules can be used as usual.

Of course the current behavior is unchanged, and the optional "label"
property for user ports has precedence over the enumerated name.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org>
---
 Documentation/devicetree/bindings/net/dsa/dsa.txt | 20 ++++++++-----------
 net/dsa/dsa2.c                                    | 24 ++++-------------------
 2 files changed, 12 insertions(+), 32 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt
index a4a570fb2494..cfe8f64eca4f 100644
--- a/Documentation/devicetree/bindings/net/dsa/dsa.txt
+++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt
@@ -34,13 +34,9 @@ Required properties:
 
 Each port children node must have the following mandatory properties:
 - reg			: Describes the port address in the switch
-- label			: Describes the label associated with this port, which
-                          will become the netdev name. Special labels are
-			  "cpu" to indicate a CPU port and "dsa" to
-			  indicate an uplink/downlink port between switches in
-			  the cluster.
 
-A port labelled "dsa" has the following mandatory property:
+An uplink/downlink port between switches in the cluster has the following
+mandatory property:
 
 - link			: Should be a list of phandles to other switch's DSA
 			  port. This port is used as the outgoing port
@@ -48,12 +44,17 @@ A port labelled "dsa" has the following mandatory property:
 			  information must be given, not just the one hop
 			  routes to neighbouring switches.
 
-A port labelled "cpu" has the following mandatory property:
+A CPU port has the following mandatory property:
 
 - ethernet		: Should be a phandle to a valid Ethernet device node.
                           This host device is what the switch port is
 			  connected to.
 
+A user port has the following optional property:
+
+- label			: Describes the label associated with this port, which
+                          will become the netdev name.
+
 Port child nodes may also contain the following optional standardised
 properties, described in binding documents:
 
@@ -107,7 +108,6 @@ linked into one DSA cluster.
 
 			switch0port5: port@5 {
 				reg = <5>;
-				label = "dsa";
 				phy-mode = "rgmii-txid";
 				link = <&switch1port6
 					&switch2port9>;
@@ -119,7 +119,6 @@ linked into one DSA cluster.
 
 			port@6 {
 				reg = <6>;
-				label = "cpu";
 				ethernet = <&fec1>;
 				fixed-link {
 					speed = <100>;
@@ -165,7 +164,6 @@ linked into one DSA cluster.
 
 			switch1port5: port@5 {
 				reg = <5>;
-				label = "dsa";
 				link = <&switch2port9>;
 				phy-mode = "rgmii-txid";
 				fixed-link {
@@ -176,7 +174,6 @@ linked into one DSA cluster.
 
 			switch1port6: port@6 {
 				reg = <6>;
-				label = "dsa";
 				phy-mode = "rgmii-txid";
 				link = <&switch0port5>;
 				fixed-link {
@@ -255,7 +252,6 @@ linked into one DSA cluster.
 
 			switch2port9: port@9 {
 				reg = <9>;
-				label = "dsa";
 				phy-mode = "rgmii-txid";
 				link = <&switch1port5
 					&switch0port5>;
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index bad119cee2a3..9526bdf2a34a 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -81,30 +81,12 @@ static void dsa_dst_del_ds(struct dsa_switch_tree *dst,
 
 static bool dsa_port_is_dsa(struct device_node *port)
 {
-	const char *name;
-
-	name = of_get_property(port, "label", NULL);
-	if (!name)
-		return false;
-
-	if (!strcmp(name, "dsa"))
-		return true;
-
-	return false;
+	return !!of_parse_phandle(port, "link", 0);
 }
 
 static bool dsa_port_is_cpu(struct device_node *port)
 {
-	const char *name;
-
-	name = of_get_property(port, "label", NULL);
-	if (!name)
-		return false;
-
-	if (!strcmp(name, "cpu"))
-		return true;
-
-	return false;
+	return !!of_parse_phandle(port, "ethernet", 0);
 }
 
 static bool dsa_ds_find_port(struct dsa_switch *ds,
@@ -268,6 +250,8 @@ static int dsa_user_port_apply(struct device_node *port, u32 index,
 	int err;
 
 	name = of_get_property(port, "label", NULL);
+	if (!name)
+		name = "eth%d";
 
 	err = dsa_slave_create(ds, ds->dev, index, name);
 	if (err) {
-- 
2.11.0

^ permalink raw reply related

* Re: [net PATCH] net: virtio: cap mtu when XDP programs are running
From: John Fastabend @ 2017-01-09 23:13 UTC (permalink / raw)
  To: Michael S. Tsirkin, Jason Wang
  Cc: john.r.fastabend, netdev, alexei.starovoitov, daniel
In-Reply-To: <20170110010531-mutt-send-email-mst@kernel.org>

On 17-01-09 03:05 PM, Michael S. Tsirkin wrote:
> On Thu, Jan 05, 2017 at 11:09:14AM +0800, Jason Wang wrote:
>>
>>
>> On 2017年01月05日 02:57, John Fastabend wrote:
>>> [...]
>>>
>>>> On 2017年01月04日 00:48, John Fastabend wrote:
>>>>> On 17-01-02 10:14 PM, Jason Wang wrote:
>>>>>> On 2017年01月03日 06:30, John Fastabend wrote:
>>>>>>> XDP programs can not consume multiple pages so we cap the MTU to
>>>>>>> avoid this case. Virtio-net however only checks the MTU at XDP
>>>>>>> program load and does not block MTU changes after the program
>>>>>>> has loaded.
>>>>>>>
>>>>>>> This patch sets/clears the max_mtu value at XDP load/unload time.
>>>>>>>
>>>>>>> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
>>>>>>> ---
>>> [...]
>>>
>>>>> OK so this logic is a bit too simply. When it resets the max_mtu I guess it
>>>>> needs to read the mtu via
>>>>>
>>>>>      virtio_cread16(vdev, ...)
>>>>>
>>>>> or we may break the negotiated mtu.
>>>> Yes, this is a problem (even use ETH_MAX_MTU). We may need a method to notify
>>>> the device about the mtu in this case which is not supported by virtio now.
>>> Note this is not really a XDP specific problem. The guest can change the MTU
>>> after init time even without XDP which I assume should ideally result in a
>>> notification if the MTU is negotiated.
>>
>> Yes, Michael, do you think we need add some mechanism to notify host about
>> MTU change in this case?
>>
>> Thanks
> 
> Why does host care?
> 

Well the guest will drop packets after mtu has been reduced. Although the guest
by reducing its MTU in some sense must expect this. Likewise if the host were
to change MTU after virtio_net probe time the guest would not learn about it.

I think at best negotiating the mtu is just a hint? If system _really_ cares
we could use lldp or some other out of band mechanism to learn/set/adjust MTU
on both systems and it would be more robust. I'm not actually convinced this
is a problem in bare metal systems we have the same issue with physical
switches and solve it out of band via configuration, protocols, etc.

.John

^ permalink raw reply

* Re: [PATCH V4 net-next 3/3] tun: rx batching
From: Michael S. Tsirkin @ 2017-01-09 23:12 UTC (permalink / raw)
  To: Jason Wang; +Cc: kvm, netdev, virtualization, wexu, stefanha
In-Reply-To: <bff99f2f-8293-0dda-1db1-881e555f3623@redhat.com>

On Mon, Jan 09, 2017 at 10:39:55AM +0800, Jason Wang wrote:
> 
> 
> On 2017年01月07日 03:47, Michael S. Tsirkin wrote:
> > > +static int tun_get_coalesce(struct net_device *dev,
> > > +			    struct ethtool_coalesce *ec)
> > > +{
> > > +	struct tun_struct *tun = netdev_priv(dev);
> > > +
> > > +	ec->rx_max_coalesced_frames = tun->rx_batched;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int tun_set_coalesce(struct net_device *dev,
> > > +			    struct ethtool_coalesce *ec)
> > > +{
> > > +	struct tun_struct *tun = netdev_priv(dev);
> > > +
> > > +	if (ec->rx_max_coalesced_frames > NAPI_POLL_WEIGHT)
> > > +		return -EINVAL;
> > So what should userspace do? Keep trying until it succeeds?
> > I think it's better to just use NAPI_POLL_WEIGHT instead and DTRT here.
> > 
> 
> Well, looking at how set_coalesce is implemented in other drivers, -EINVAL
> is usually used when user give a value that exceeds the limitation. For
> tuntap, what missed here is probably just a documentation for coalescing in
> tuntap.txt. (Or extend ethtool to return the max value). This seems much
> better than silently reduce the value to the limitation.
> 
> Thanks


I don't think it's better, it's mostly that
1. there's a hardware limit so it does not change much
2. default is enabled and no one bothers changing

I don't see how will tuntap.txt help if we want to change it
in the future.

-- 
MST
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply

* Re: [PATCH net-next] bridge: multicast to unicast
From: Linus Lüssing @ 2017-01-09 23:12 UTC (permalink / raw)
  To: Johannes Berg
  Cc: netdev, bridge, linux-wireless, linux-kernel, Michael Braun,
	David S . Miller, Felix Fietkau
In-Reply-To: <1483965843.17582.37.camel@sipsolutions.net>

On Mon, Jan 09, 2017 at 10:42:46PM +0100, Johannes Berg wrote:
> On Mon, 2017-01-09 at 22:33 +0100, Linus Lüssing wrote:
> > On Mon, Jan 09, 2017 at 01:44:03PM +0100, Johannes Berg wrote:
> > > 
> > > > >          A host SHOULD silently discard a datagram that is
> > > > > received via
> > > > >          a link-layer broadcast (see Section 2.4) but does not
> > > > > specify
> > > > >          an IP multicast or broadcast destination address.
> > > > 
> > > > This example is the other way round. It specifies how the IP
> > > > destination should look like in case of link-layer broadcast. Not
> > > > how the link-layer destination should look like in case of a
> > > > multicast/broadcast IP destination.
> > > 
> > > You stopped reading too early - snipped the context part for you :)
> > 
> > Sorry for writing to you directly, but I still have some
> > difficulties. In pseudo-code that line says:
> > 
> > -----
> > if ll_dst(pkt) == bcast AND ip_dst(pkt) != mcast/bcast:
> > -> drop(pkt)
> > -----
> > 
> > But after multicast-to-unicast conversion, we have:
> > 
> > -----
> > ll_dst(pkt) == ucast AND ip_dst(pkt) == mcast
> > -----
> > 
> > So none of the two requirements for dropping are matched?
> > 
> 
> Exactly. My point is that this is breaking the expectation that hosts
> are actually able to drop such packets.

[readding CCs I removed earlier]

Ah! Thanks. I was worried about creating packetloss :D.

Hm, for this other other way round, I think it does not apply for
the bridge multicast-to-unicast patch if I'm not misreading the bridge code:

For a packet with a link-layer multicast address but a unicast IP
destination, the bridge MDB lookup will fail.
(http://lxr.free-electrons.com/source/net/bridge/br_multicast.c?v=4.8#L178
 returns NULL)

Case A): No multicast router on port:
-> bridge, br_multicast_flood(), will drop the packet already
   (no matter if multicast-to-unicast is enabled or not)

Case B): Multicast router present on port:
-> The new patch does not apply multicast-to-unicast but just floods
   packet unaltered
   ("else { port = rport; addr = NULL; }" branch)

Regards, Linus

^ permalink raw reply

* Re: [PATCH V4 net-next 1/3] vhost: better detection of available buffers
From: Michael S. Tsirkin @ 2017-01-09 23:10 UTC (permalink / raw)
  To: Jason Wang; +Cc: kvm, netdev, virtualization, wexu, stefanha
In-Reply-To: <e09ccb6a-87b8-d2b1-f64d-79ea7ea89954@redhat.com>

On Mon, Jan 09, 2017 at 10:59:16AM +0800, Jason Wang wrote:
> 
> 
> On 2017年01月07日 03:55, Michael S. Tsirkin wrote:
> > On Fri, Jan 06, 2017 at 10:13:15AM +0800, Jason Wang wrote:
> > > This patch tries to do several tweaks on vhost_vq_avail_empty() for a
> > > better performance:
> > > 
> > > - check cached avail index first which could avoid userspace memory access.
> > > - using unlikely() for the failure of userspace access
> > > - check vq->last_avail_idx instead of cached avail index as the last
> > >    step.
> > > 
> > > This patch is need for batching supports which needs to peek whether
> > > or not there's still available buffers in the ring.
> > > 
> > > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> > > ---
> > >   drivers/vhost/vhost.c | 8 ++++++--
> > >   1 file changed, 6 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> > > index d643260..9f11838 100644
> > > --- a/drivers/vhost/vhost.c
> > > +++ b/drivers/vhost/vhost.c
> > > @@ -2241,11 +2241,15 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
> > >   	__virtio16 avail_idx;
> > >   	int r;
> > > +	if (vq->avail_idx != vq->last_avail_idx)
> > > +		return false;
> > > +
> > >   	r = vhost_get_user(vq, avail_idx, &vq->avail->idx);
> > > -	if (r)
> > > +	if (unlikely(r))
> > >   		return false;
> > > +	vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
> > > -	return vhost16_to_cpu(vq, avail_idx) == vq->avail_idx;
> > > +	return vq->avail_idx == vq->last_avail_idx;
> > >   }
> > >   EXPORT_SYMBOL_GPL(vhost_vq_avail_empty);
> > So again, this did not address the issue I pointed out in v1:
> > if we have 1 buffer in RX queue and
> > that is not enough to store the whole packet,
> > vhost_vq_avail_empty returns false, then we re-read
> > the descriptors again and again.
> > 
> > You have saved a single index access but not the more expensive
> > descriptor access.
> 
> Looks not, if I understand the code correctly, in this case, get_rx_bufs()
> will return zero, and we will try to enable rx kick and exit the loop.
> 
> Thanks

I mean this:

                while (vhost_can_busy_poll(vq->dev, endtime) &&
                       vhost_vq_avail_empty(vq->dev, vq))
                        cpu_relax();
                preempt_enable();
                r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
                                      out_num, in_num, NULL, NULL);


vhost_vq_avail_empty returns false so we break out of the loop
and call vhost_get_vq_desc.


-- 
MST
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply

* [PATCH next v2] ipvlan: improvise dev_id generation logic in IPvlan
From: Mahesh Bandewar @ 2017-01-09 23:05 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, Mahesh Bandewar, Mahesh Bandewar, Eric Dumazet,
	David Miller

From: Mahesh Bandewar <maheshb@google.com>

The patch 009146d117b ("ipvlan: assign unique dev-id for each slave
device.") used ida_simple_get() to generate dev_ids assigned to the
slave devices. However (Eric has pointed out that) there is a shortcoming
with that approach as it always uses the first available ID. This
becomes a problem when a slave gets deleted and a new slave gets added.
The ID gets reassigned causing the new slave to get the same link-local
address. This side-effect is undesirable.

This patch adds a per-port variable that keeps track of the IDs
assigned and used as the stat-base for the IDR api. This base will be
wrapped around when it reaches the MAX (0xFFFE) value possibly on a
busy system where slaves are added and deleted routinely.

Fixes: 009146d117b ("ipvlan: assign unique dev-id for each slave device.")
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
CC: Eric Dumazet <edumazet@google.com>
CC: David Miller <davem@davemloft.org>
---
v1 -> v2
  Implemented Dave's comments and reinstated IDR API.

 drivers/net/ipvlan/ipvlan.h      |  1 +
 drivers/net/ipvlan/ipvlan_main.c | 13 ++++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h
index 0a9068fdee0f..406ae4ff0ae8 100644
--- a/drivers/net/ipvlan/ipvlan.h
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -94,6 +94,7 @@ struct ipvl_port {
 	struct hlist_head	hlhead[IPVLAN_HASH_SIZE];
 	struct list_head	ipvlans;
 	u16			mode;
+	u16			dev_id_start;
 	struct work_struct	wq;
 	struct sk_buff_head	backlog;
 	int			count;
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index ce7ca6a5aa8a..aca2885cf0b4 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -120,6 +120,7 @@ static int ipvlan_port_create(struct net_device *dev)
 	skb_queue_head_init(&port->backlog);
 	INIT_WORK(&port->wq, ipvlan_process_multicast);
 	ida_init(&port->ida);
+	port->dev_id_start = 1;
 
 	err = netdev_rx_handler_register(dev, ipvlan_handle_frame, port);
 	if (err)
@@ -535,15 +536,25 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
 	ipvlan_adjust_mtu(ipvlan, phy_dev);
 	INIT_LIST_HEAD(&ipvlan->addrs);
 
+	/* If the port-id base is at the MAX value, then wrap it around and
+	 * begin from 0x1 again. This may be due to a busy system where lots
+	 * of slaves are getting created and deleted.
+	 */
+	if (port->dev_id_start == 0xFFFE)
+		port->dev_id_start = 0x1;
+
 	/* Since L2 address is shared among all IPvlan slaves including
 	 * master, use unique 16 bit dev-ids to diffentiate among them.
 	 * Assign IDs between 0x1 and 0xFFFE (used by the master) to each
 	 * slave link [see addrconf_ifid_eui48()].
 	 */
-	err = ida_simple_get(&port->ida, 1, 0xFFFE, GFP_KERNEL);
+	err = ida_simple_get(&port->ida, port->dev_id_start, 0xFFFE,
+			     GFP_KERNEL);
 	if (err < 0)
 		goto destroy_ipvlan_port;
 	dev->dev_id = err;
+	/* Increment id-base to the next slot for the future assignment */
+	port->dev_id_start = err + 1;
 
 	/* TODO Probably put random address here to be presented to the
 	 * world but keep using the physical-dev address for the outgoing
-- 
2.11.0.390.gc69c2f50cf-goog

^ permalink raw reply related

* Re: [net PATCH] net: virtio: cap mtu when XDP programs are running
From: Michael S. Tsirkin @ 2017-01-09 23:05 UTC (permalink / raw)
  To: Jason Wang
  Cc: John Fastabend, john.r.fastabend, netdev, alexei.starovoitov,
	daniel
In-Reply-To: <068f0116-b37e-eb44-8c60-1781a9d5255e@redhat.com>

On Thu, Jan 05, 2017 at 11:09:14AM +0800, Jason Wang wrote:
> 
> 
> On 2017年01月05日 02:57, John Fastabend wrote:
> > [...]
> > 
> > > On 2017年01月04日 00:48, John Fastabend wrote:
> > > > On 17-01-02 10:14 PM, Jason Wang wrote:
> > > > > On 2017年01月03日 06:30, John Fastabend wrote:
> > > > > > XDP programs can not consume multiple pages so we cap the MTU to
> > > > > > avoid this case. Virtio-net however only checks the MTU at XDP
> > > > > > program load and does not block MTU changes after the program
> > > > > > has loaded.
> > > > > > 
> > > > > > This patch sets/clears the max_mtu value at XDP load/unload time.
> > > > > > 
> > > > > > Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
> > > > > > ---
> > [...]
> > 
> > > > OK so this logic is a bit too simply. When it resets the max_mtu I guess it
> > > > needs to read the mtu via
> > > > 
> > > >      virtio_cread16(vdev, ...)
> > > > 
> > > > or we may break the negotiated mtu.
> > > Yes, this is a problem (even use ETH_MAX_MTU). We may need a method to notify
> > > the device about the mtu in this case which is not supported by virtio now.
> > Note this is not really a XDP specific problem. The guest can change the MTU
> > after init time even without XDP which I assume should ideally result in a
> > notification if the MTU is negotiated.
> 
> Yes, Michael, do you think we need add some mechanism to notify host about
> MTU change in this case?
> 
> Thanks

Why does host care?

^ permalink raw reply

* Re: [PATCH] net: qrtr: Mark 'buf' as little endian
From: Bjorn Andersson @ 2017-01-09 23:02 UTC (permalink / raw)
  To: Stephen Boyd; +Cc: David S. Miller, linux-kernel, netdev
In-Reply-To: <20170109223158.29255-1-sboyd@codeaurora.org>

On Mon 09 Jan 14:31 PST 2017, Stephen Boyd wrote:

> Failure to mark this pointer as __le32 causes checkers like
> sparse to complain:
> 
> net/qrtr/qrtr.c:274:16: warning: incorrect type in assignment (different base types)
> net/qrtr/qrtr.c:274:16:    expected unsigned int [unsigned] [usertype] <noident>
> net/qrtr/qrtr.c:274:16:    got restricted __le32 [usertype] <noident>
> net/qrtr/qrtr.c:275:16: warning: incorrect type in assignment (different base types)
> net/qrtr/qrtr.c:275:16:    expected unsigned int [unsigned] [usertype] <noident>
> net/qrtr/qrtr.c:275:16:    got restricted __le32 [usertype] <noident>
> net/qrtr/qrtr.c:276:16: warning: incorrect type in assignment (different base types)
> net/qrtr/qrtr.c:276:16:    expected unsigned int [unsigned] [usertype] <noident>
> net/qrtr/qrtr.c:276:16:    got restricted __le32 [usertype] <noident>
> 
> Silence it.
> 
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>

Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org>

Regards,
Bjorn

> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  net/qrtr/qrtr.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
> index c985ecbe9bd6..ae5ac175b2be 100644
> --- a/net/qrtr/qrtr.c
> +++ b/net/qrtr/qrtr.c
> @@ -252,7 +252,7 @@ static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
>  	const int pkt_len = 20;
>  	struct qrtr_hdr *hdr;
>  	struct sk_buff *skb;
> -	u32 *buf;
> +	__le32 *buf;
>  
>  	skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL);
>  	if (!skb)
> @@ -269,7 +269,7 @@ static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
>  	hdr->dst_node_id = cpu_to_le32(dst_node);
>  	hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
>  
> -	buf = (u32 *)skb_put(skb, pkt_len);
> +	buf = (__le32 *)skb_put(skb, pkt_len);
>  	memset(buf, 0, pkt_len);
>  	buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX);
>  	buf[1] = cpu_to_le32(src_node);
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

^ permalink raw reply

* Re: Marvell Phy (1510) issue since v4.7 kernel
From: Andrew Lunn @ 2017-01-09 22:56 UTC (permalink / raw)
  To: Murali Karicheri; +Cc: netdev, Kwok, WingMan
In-Reply-To: <587410EF.5090607@ti.com>

On Mon, Jan 09, 2017 at 05:38:39PM -0500, Murali Karicheri wrote:
> Hello Charles-Antoine, Andrew,
> 
> We have recently upgraded our kernel to v4.9 and started seeing an issue
> on our Keystone EVMs (K2E/L) that uses Marvel Phy 1510. The issue is that
> when we do a reboot command from the Linux console or do a SoC reset,
> the DHCP times out at U-Boot due to Phy auto negotiation failure. This works
> fine when the board is power cycled.

I've seen similar before. What version of kernel are you upgrading
from?

The problem i've had is that on shutdown/reboot, linux powers the PHYs
off. The uboot i have does not power them on again. Clearly a uboot
issue, it should not assume the PHYs are powered on.

I work around this with a uboot command:

mii write 1 0 0x3100

where the PHY is at address 1 on the bus. This writes to register 0,
and the import bit which needs setting to 0 is bit 11.

If mii read shows bit 11 is set, you know there uboot did not power up
the PHY.

    Andrew

^ permalink raw reply

* [PATCH v2 net-next] liquidio: store the L4 hash of rx packets in skb
From: Felix Manlunas @ 2017-01-09 22:42 UTC (permalink / raw)
  To: davem
  Cc: netdev, raghu.vatsavayi, derek.chickles, satananda.burla,
	eric.dumazet

From: Prasad Kanneganti <prasad.kanneganti@cavium.com>

Store the L4 hash of received packets in the skb; the hash is computed in
the NIC firmware.

Signed-off-by: Prasad Kanneganti <prasad.kanneganti@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
Signed-off-by: Derek Chickles <derek.chickles@cavium.com>
Signed-off-by: Satanand Burla <satananda.burla@cavium.com>
---
Note: The location of the L4 hash within the 8-byte DHLEN unit is the first
      4 bytes; also that location is endian-independent.  The raw L4 hash
      (in its original form) is big endian.

Patch Changelog:
 v2: Fix two instances of sparse "warning: cast to restricted __be32":  one
     in lio_main.c and one in lio_vf_main.c.  The fix is to replace the
     cast to (u32 *) with a cast to (__be32 *).

 drivers/net/ethernet/cavium/liquidio/lio_main.c        | 18 ++++++++++++++++--
 drivers/net/ethernet/cavium/liquidio/lio_vf_main.c     | 16 +++++++++++++++-
 drivers/net/ethernet/cavium/liquidio/liquidio_common.h |  2 ++
 3 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index 13f67a3..b8b579d 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -2263,6 +2263,7 @@ liquidio_push_packet(u32 octeon_id __attribute__((unused)),
 	struct skb_shared_hwtstamps *shhwtstamps;
 	u64 ns;
 	u16 vtag = 0;
+	u32 r_dh_off;
 	struct net_device *netdev = (struct net_device *)arg;
 	struct octeon_droq *droq = container_of(param, struct octeon_droq,
 						napi);
@@ -2308,6 +2309,8 @@ liquidio_push_packet(u32 octeon_id __attribute__((unused)),
 			put_page(pg_info->page);
 		}
 
+		r_dh_off = (rh->r_dh.len - 1) * BYTES_PER_DHLEN_UNIT;
+
 		if (((oct->chip_id == OCTEON_CN66XX) ||
 		     (oct->chip_id == OCTEON_CN68XX)) &&
 		    ptp_enable) {
@@ -2320,16 +2323,27 @@ liquidio_push_packet(u32 octeon_id __attribute__((unused)),
 					/* Nanoseconds are in the first 64-bits
 					 * of the packet.
 					 */
-					memcpy(&ns, (skb->data), sizeof(ns));
+					memcpy(&ns, (skb->data + r_dh_off),
+					       sizeof(ns));
+					r_dh_off -= BYTES_PER_DHLEN_UNIT;
 					shhwtstamps = skb_hwtstamps(skb);
 					shhwtstamps->hwtstamp =
 						ns_to_ktime(ns +
 							    lio->ptp_adjust);
 				}
-				skb_pull(skb, sizeof(ns));
 			}
 		}
 
+		if (rh->r_dh.has_hash) {
+			__be32 *hash_be = (__be32 *)(skb->data + r_dh_off);
+			u32 hash = be32_to_cpu(*hash_be);
+
+			skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
+			r_dh_off -= BYTES_PER_DHLEN_UNIT;
+		}
+
+		skb_pull(skb, rh->r_dh.len * BYTES_PER_DHLEN_UNIT);
+
 		skb->protocol = eth_type_trans(skb, skb->dev);
 		if ((netdev->features & NETIF_F_RXCSUM) &&
 		    (((rh->r_dh.encap_on) &&
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
index 55846f2..ad2e72d 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
@@ -1497,6 +1497,7 @@ liquidio_push_packet(u32 octeon_id __attribute__((unused)),
 	struct net_device *netdev = (struct net_device *)arg;
 	struct sk_buff *skb = (struct sk_buff *)skbuff;
 	u16 vtag = 0;
+	u32 r_dh_off;
 
 	if (netdev) {
 		struct lio *lio = GET_LIO(netdev);
@@ -1540,7 +1541,20 @@ liquidio_push_packet(u32 octeon_id __attribute__((unused)),
 			put_page(pg_info->page);
 		}
 
-		skb_pull(skb, rh->r_dh.len * 8);
+		r_dh_off = (rh->r_dh.len - 1) * BYTES_PER_DHLEN_UNIT;
+
+		if (rh->r_dh.has_hwtstamp)
+			r_dh_off -= BYTES_PER_DHLEN_UNIT;
+
+		if (rh->r_dh.has_hash) {
+			__be32 *hash_be = (__be32 *)(skb->data + r_dh_off);
+			u32 hash = be32_to_cpu(*hash_be);
+
+			skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
+			r_dh_off -= BYTES_PER_DHLEN_UNIT;
+		}
+
+		skb_pull(skb, rh->r_dh.len * BYTES_PER_DHLEN_UNIT);
 		skb->protocol = eth_type_trans(skb, skb->dev);
 
 		if ((netdev->features & NETIF_F_RXCSUM) &&
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
index ba329f6..bc0af8a 100644
--- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
@@ -98,6 +98,8 @@ enum octeon_tag_type {
 #define CVM_DRV_INVALID_APP         (CVM_DRV_APP_START + 0x2)
 #define CVM_DRV_APP_END             (CVM_DRV_INVALID_APP - 1)
 
+#define BYTES_PER_DHLEN_UNIT        8
+
 static inline u32 incr_index(u32 index, u32 count, u32 max)
 {
 	if ((index + count) >= max)

^ permalink raw reply related

* Marvell Phy (1510) issue since v4.7 kernel
From: Murali Karicheri @ 2017-01-09 22:38 UTC (permalink / raw)
  To: Andrew Lunn, netdev; +Cc: Kwok, WingMan

Hello Charles-Antoine, Andrew,

We have recently upgraded our kernel to v4.9 and started seeing an issue
on our Keystone EVMs (K2E/L) that uses Marvel Phy 1510. The issue is that
when we do a reboot command from the Linux console or do a SoC reset,
the DHCP times out at U-Boot due to Phy auto negotiation failure. This works
fine when the board is power cycled.

This is traced back to v4.7 where following commits were introduced:-

3758be3dc162b56ea Marvell phy: add functions to suspend and resume both interfaces: fiber and copper links.
78301ebe9b5a2645d Marvell phy: add configuration of autonegociation for fiber link.
2170fef78a400ca3c Marvell phy: add field to get errors from fiber link.
6cfb3bcc064110995 Marvell phy: check link status in case of fiber link 

Specifically the commit 6cfb3bcc0641109951a124019cd2e0623107d18d which changed
the marvell_read_status() behavior

Once we add the below HACK, this works fine.

commit e5bd8bfe7f544df03772c094331bb27e1a5a5600
Author: Murali Karicheri <m-karicheri2@ti.com>
Date:   Fri Jan 6 12:22:13 2017 -0500

    TEMP: work around in marvel Phy driver for u-boot dhcp timeout
    
    Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index c2dcf02..e91bdd3 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -1194,7 +1194,7 @@ static int marvell_read_status(struct phy_device *phydev)
        int err;
 
        /* Check the fiber mode first */
-       if (phydev->supported & SUPPORTED_FIBRE) {
+       if (!(phydev->supported & SUPPORTED_FIBRE)) {
                err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER);
                if (err < 0)
                        goto error;


Also we see comments/logic in the code that contradicts with each other

For example in marvell_read_status(), it says "Check the fiber mode first and
uses the logic 
     if (phydev->supported & SUPPORTED_FIBRE)

Where as in  marvell_resume() comment says 'Resume the fiber mode first' and
uses the logic 

     if (!(phydev->supported & SUPPORTED_FIBRE))

Both are not symmetrical. Could you please explain?

-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply related

* [PATCH] net: qrtr: Mark 'buf' as little endian
From: Stephen Boyd @ 2017-01-09 22:31 UTC (permalink / raw)
  To: David S. Miller; +Cc: linux-kernel, netdev, Bjorn Andersson

Failure to mark this pointer as __le32 causes checkers like
sparse to complain:

net/qrtr/qrtr.c:274:16: warning: incorrect type in assignment (different base types)
net/qrtr/qrtr.c:274:16:    expected unsigned int [unsigned] [usertype] <noident>
net/qrtr/qrtr.c:274:16:    got restricted __le32 [usertype] <noident>
net/qrtr/qrtr.c:275:16: warning: incorrect type in assignment (different base types)
net/qrtr/qrtr.c:275:16:    expected unsigned int [unsigned] [usertype] <noident>
net/qrtr/qrtr.c:275:16:    got restricted __le32 [usertype] <noident>
net/qrtr/qrtr.c:276:16: warning: incorrect type in assignment (different base types)
net/qrtr/qrtr.c:276:16:    expected unsigned int [unsigned] [usertype] <noident>
net/qrtr/qrtr.c:276:16:    got restricted __le32 [usertype] <noident>

Silence it.

Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 net/qrtr/qrtr.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index c985ecbe9bd6..ae5ac175b2be 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -252,7 +252,7 @@ static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
 	const int pkt_len = 20;
 	struct qrtr_hdr *hdr;
 	struct sk_buff *skb;
-	u32 *buf;
+	__le32 *buf;
 
 	skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL);
 	if (!skb)
@@ -269,7 +269,7 @@ static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
 	hdr->dst_node_id = cpu_to_le32(dst_node);
 	hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
 
-	buf = (u32 *)skb_put(skb, pkt_len);
+	buf = (__le32 *)skb_put(skb, pkt_len);
 	memset(buf, 0, pkt_len);
 	buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX);
 	buf[1] = cpu_to_le32(src_node);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related

* [PATCH] netfilter: Fix typo in NF_CONNTRACK Kconfig option description
From: William Breathitt Gray @ 2017-01-09 22:24 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Patrick McHardy, Jozsef Kadlecsik
  Cc: David S. Miller, netfilter-devel, coreteam, netdev, linux-kernel

The NF_CONNTRACK Kconfig option description makes an incorrect reference
to the "meta" expression where the "ct" expression would be correct.This
patch fixes the respective typographical error.

Fixes: d497c6352736 ("netfilter: add help information to new nf_tables Kconfig options")
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 net/netfilter/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 63729b489c2c..bbc45f8a7b2d 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -494,7 +494,7 @@ config NFT_CT
 	depends on NF_CONNTRACK
 	tristate "Netfilter nf_tables conntrack module"
 	help
-	  This option adds the "meta" expression that you can use to match
+	  This option adds the "ct" expression that you can use to match
 	  connection tracking information such as the flow state.
 
 config NFT_SET_RBTREE
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH net-next] net: ipv6: put autoconf routes into per-interface tables
From: Andrey Jr. Melnikov @ 2017-01-09 21:53 UTC (permalink / raw)
  To: netdev
In-Reply-To: <37df3b18-d17b-5875-7b44-db40be7b459c@cumulusnetworks.com>

David Ahern <dsa@cumulusnetworks.com> wrote:
> On 1/6/17 8:30 AM, Lorenzo Colitti wrote:
> > This patch adds a per-interface sysctl to have the kernel put
> > autoconf routes into different tables. This allows each interface
> > to have its own routing table if desired.  Choosing the default
> > interface, or using different interfaces at the same time on a
> > per-socket or per-packet basis) can be done using policy routing
> > mechanisms that use as SO_BINDTODEVICE / IPV6_PKTINFO, mark-based
> > routing, or UID-based routing to select specific routing tables.

> Why not use the VRF capability then? create a VRF and assign the interface to it. 
> End result is the same -- separate tables and the need to use a bind-to-device API to hit those routes.

Show *really working* config with VRF & IPv6?

In my tests - kernel unable to accept DAD, fill logs with "ICMPv6: RA: ndisc_router_discovery failed to add default route"
and nothing work. VRF interface don't contains IPv6 address.

^ permalink raw reply

* Re: [PATCH net-next v2] net: dsa: select NET_SWITCHDEV
From: David Miller @ 2017-01-09 22:18 UTC (permalink / raw)
  To: vivien.didelot
  Cc: netdev, linux-kernel, kernel, f.fainelli, andrew, jiri, rdunlap
In-Reply-To: <20170109214926.20985-1-vivien.didelot@savoirfairelinux.com>

From: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Date: Mon,  9 Jan 2017 16:49:26 -0500

> The support for DSA Ethernet switch chips depends on TCP/IP networking,
> thus explicit that HAVE_NET_DSA depends on INET.
> 
> DSA uses SWITCHDEV, thus select it instead of depending on it.
> 
> Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
> Tested-by: Randy Dunlap <rdunlap@infradead.org>

Applied, thanks.

^ permalink raw reply

* [PATCH v2 13/13] net: ethernet: aquantia: Integrate AQtion 2.5/5 GB NIC driver
From: Alexander Loktionov @ 2017-01-09 22:16 UTC (permalink / raw)
  To: netdev, David VomLehn
  Cc: Simon Edelhaus, Alexander Loktionov, Dmitrii Tarakanov,
	Pavel Belous
In-Reply-To: <703b9184b3216032657a7895bd71929d2031bbc4.1483999588.git.vomlehn@texas.net>

From: David VomLehn <vomlehn@texas.net>

Modify the drivers/net/ethernet/{Makefile,Kconfig} file to make them a
part of the network drivers build.

Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Pavel Belous <Pavel.Belous@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
 drivers/net/ethernet/Kconfig  | 1 +
 drivers/net/ethernet/Makefile | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 8cc7467..d467c8b 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -28,6 +28,7 @@ source "drivers/net/ethernet/amazon/Kconfig"
 source "drivers/net/ethernet/amd/Kconfig"
 source "drivers/net/ethernet/apm/Kconfig"
 source "drivers/net/ethernet/apple/Kconfig"
+source "drivers/net/ethernet/aquantia/Kconfig"
 source "drivers/net/ethernet/arc/Kconfig"
 source "drivers/net/ethernet/atheros/Kconfig"
 source "drivers/net/ethernet/aurora/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index a09423d..123ef8e 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_NET_VENDOR_AMAZON) += amazon/
 obj-$(CONFIG_NET_VENDOR_AMD) += amd/
 obj-$(CONFIG_NET_XGENE) += apm/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
+obj-$(CONFIG_NET_VENDOR_AQUANTIA) += aquantia/
 obj-$(CONFIG_NET_VENDOR_ARC) += arc/
 obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
 obj-$(CONFIG_NET_VENDOR_AURORA) += aurora/
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 12/13] net: ethernet: aquantia: Receive side scaling
From: Alexander Loktionov @ 2017-01-09 22:16 UTC (permalink / raw)
  To: netdev, David VomLehn
  Cc: Simon Edelhaus, Alexander Loktionov, Dmitrii Tarakanov,
	Pavel Belous
In-Reply-To: <2a2056f13b975c8a4924b4f733d3cdc28a6b9422.1483999588.git.vomlehn@texas.net>

From: David VomLehn <vomlehn@texas.net>

Add definitions that support receive side scaling.

Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Pavel Belous <Pavel.Belous@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
 drivers/net/ethernet/aquantia/aq_rss.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 drivers/net/ethernet/aquantia/aq_rss.h

diff --git a/drivers/net/ethernet/aquantia/aq_rss.h b/drivers/net/ethernet/aquantia/aq_rss.h
new file mode 100644
index 0000000..5869844
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_rss.h
@@ -0,0 +1,27 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_rss.h: Receive Side Scaling definitions. */
+
+#ifndef AQ_RSS_H
+#define AQ_RSS_H
+
+#include "aq_common.h"
+#include "aq_cfg.h"
+
+struct aq_rss_parameters {
+	u16 base_cpu_number;
+	u16 indirection_table_size;
+	u16 hash_secret_key_size;
+	u32 hash_secret_key[AQ_CFG_RSS_HASHKEY_SIZE / sizeof(u32)];
+	u8 indirection_table[AQ_CFG_RSS_INDIRECTION_TABLE_MAX];
+};
+
+#endif /* AQ_RSS_H */
+
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 11/13] net: ethernet: aquantia: Ethtool support
From: Alexander Loktionov @ 2017-01-09 22:16 UTC (permalink / raw)
  To: netdev, David VomLehn
  Cc: Simon Edelhaus, Alexander Loktionov, Dmitrii Tarakanov,
	Pavel Belous
In-Reply-To: <7bc5005bb4345003d27e67df218fd4689aca0050.1483999588.git.vomlehn@texas.net>

From: David VomLehn <vomlehn@texas.net>

Add the driver interfaces required for support by the ethtool utility.

Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Pavel Belous <Pavel.Belous@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
 drivers/net/ethernet/aquantia/aq_ethtool.c | 251 +++++++++++++++++++++++++++++
 drivers/net/ethernet/aquantia/aq_ethtool.h |  20 +++
 2 files changed, 271 insertions(+)
 create mode 100644 drivers/net/ethernet/aquantia/aq_ethtool.c
 create mode 100644 drivers/net/ethernet/aquantia/aq_ethtool.h

diff --git a/drivers/net/ethernet/aquantia/aq_ethtool.c b/drivers/net/ethernet/aquantia/aq_ethtool.c
new file mode 100644
index 0000000..1b21f9f
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_ethtool.c
@@ -0,0 +1,251 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_ethtool.c: Definition of ethertool related functions. */
+
+#include "aq_ethtool.h"
+#include "aq_nic.h"
+
+static void aq_ethtool_get_regs(struct net_device *ndev,
+				struct ethtool_regs *regs, void *p)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+	u32 regs_count = aq_nic_get_regs_count(aq_nic);
+
+	memset(p, 0, regs_count * sizeof(u32));
+	aq_nic_get_regs(aq_nic, regs, p);
+}
+
+static int aq_ethtool_get_regs_len(struct net_device *ndev)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+	u32 regs_count = aq_nic_get_regs_count(aq_nic);
+
+	return regs_count * sizeof(u32);
+}
+
+static u32 aq_ethtool_get_link(struct net_device *ndev)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+
+	return aq_nic_get_link_speed(aq_nic) ? 1U : 0U;
+}
+
+static int aq_ethtool_get_settings(struct net_device *ndev,
+				   struct ethtool_cmd *cmd)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+
+	cmd->port = PORT_TP;
+	cmd->transceiver = XCVR_EXTERNAL;
+
+	ethtool_cmd_speed_set(cmd, netif_carrier_ok(ndev) ?
+				aq_nic_get_link_speed(aq_nic) : 0U);
+
+	cmd->duplex = DUPLEX_FULL;
+	aq_nic_get_link_settings(aq_nic, cmd);
+	return 0;
+}
+
+static int aq_ethtool_set_settings(struct net_device *ndev,
+				   struct ethtool_cmd *cmd)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+
+	return aq_nic_set_link_settings(aq_nic, cmd);
+}
+
+static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = {
+	"InPackets",
+	"InUCast",
+	"InMCast",
+	"InBCast",
+	"InErrors",
+	"OutPackets",
+	"OutUCast",
+	"OutMCast",
+	"OutBCast",
+	"InUCastOctects",
+	"OutUCastOctects",
+	"InMCastOctects",
+	"OutMCastOctects",
+	"InBCastOctects",
+	"OutBCastOctects",
+	"InOctects",
+	"OutOctects",
+	"InPacketsDma",
+	"OutPacketsDma",
+	"InOctetsDma",
+	"OutOctetsDma",
+	"InDroppedDma",
+	"Queue[0] InPackets",
+	"Queue[0] OutPackets",
+	"Queue[0] InJumboPackets",
+	"Queue[0] InLroPackets",
+	"Queue[0] InErrors",
+#if 1 < AQ_CFG_VECS_DEF
+	"Queue[1] InPackets",
+	"Queue[1] OutPackets",
+	"Queue[1] InJumboPackets",
+	"Queue[1] InLroPackets",
+	"Queue[1] InErrors",
+#endif
+#if 2 < AQ_CFG_VECS_DEF
+	"Queue[2] InPackets",
+	"Queue[2] OutPackets",
+	"Queue[2] InJumboPackets",
+	"Queue[2] InLroPackets",
+	"Queue[2] InErrors",
+#endif
+#if 3 < AQ_CFG_VECS_DEF
+	"Queue[3] InPackets",
+	"Queue[3] OutPackets",
+	"Queue[3] InJumboPackets",
+	"Queue[3] InLroPackets",
+	"Queue[3] InErrors",
+#endif
+#if 4 < AQ_CFG_VECS_DEF
+	"Queue[4] InPackets",
+	"Queue[4] OutPackets",
+	"Queue[4] InJumboPackets",
+	"Queue[4] InLroPackets",
+	"Queue[4] InErrors",
+#endif
+#if 5 < AQ_CFG_VECS_DEF
+	"Queue[5] InPackets",
+	"Queue[5] OutPackets",
+	"Queue[5] InJumboPackets",
+	"Queue[5] InLroPackets",
+	"Queue[5] InErrors",
+#endif
+#if 6 < AQ_CFG_VECS_DEF
+	"Queue[6] InPackets",
+	"Queue[6] OutPackets",
+	"Queue[6] InJumboPackets",
+	"Queue[6] InLroPackets",
+	"Queue[6] InErrors",
+#endif
+#if 7 < AQ_CFG_VECS_DEF
+	"Queue[7] InPackets",
+	"Queue[7] OutPackets",
+	"Queue[7] InJumboPackets",
+	"Queue[7] InLroPackets",
+	"Queue[7] InErrors",
+#endif
+};
+
+static void aq_ethtool_stats(struct net_device *ndev,
+			     struct ethtool_stats *stats, u64 *data)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+
+	memset(data, 0, ARRAY_SIZE(aq_ethtool_stat_names) * sizeof(u64));
+	aq_nic_get_stats(aq_nic, data);
+}
+
+static void aq_ethtool_get_drvinfo(struct net_device *ndev,
+				   struct ethtool_drvinfo *drvinfo)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+	u32 firmware_version = aq_nic_get_fw_version(aq_nic);
+	u32 regs_count = aq_nic_get_regs_count(aq_nic);
+
+	strlcat(drvinfo->driver, AQ_CFG_DRV_NAME, sizeof(drvinfo->driver));
+	strlcat(drvinfo->version, AQ_CFG_DRV_VERSION, sizeof(drvinfo->version));
+
+	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+		 "%u.%u.%u", firmware_version >> 24,
+		 (firmware_version >> 16) & 0xFFU, firmware_version & 0xFFFFU);
+
+	drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names);
+	drvinfo->testinfo_len = 0;
+	drvinfo->regdump_len = regs_count;
+	drvinfo->eedump_len = 0;
+}
+
+static void aq_ethtool_get_strings(struct net_device *ndev,
+				   u32 stringset, u8 *data)
+{
+	memcpy(data, *aq_ethtool_stat_names, sizeof(aq_ethtool_stat_names));
+}
+
+static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
+{
+	return ARRAY_SIZE(aq_ethtool_stat_names);
+}
+
+static u32 aq_ethtool_get_rss_indir_size(struct net_device *ndev)
+{
+	return AQ_CFG_RSS_INDIRECTION_TABLE_MAX;
+}
+
+static u32 aq_ethtool_get_rss_key_size(struct net_device *ndev)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+
+	return sizeof(cfg->aq_rss.hash_secret_key);
+}
+
+static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key,
+			      u8 *hfunc)
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+	unsigned int i = 0U;
+
+	if (hfunc)
+		*hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
+	if (indir) {
+		for (i = 0; i < AQ_CFG_RSS_INDIRECTION_TABLE_MAX; i++)
+			indir[i] = cfg->aq_rss.indirection_table[i];
+	}
+	if (key)
+		memcpy(key, cfg->aq_rss.hash_secret_key,
+		       sizeof(cfg->aq_rss.hash_secret_key));
+	return 0;
+}
+
+static int aq_ethtool_get_rxnfc(struct net_device *ndev,
+				struct ethtool_rxnfc *cmd, u32 *rule_locs)
+
+{
+	struct aq_nic_s *aq_nic = (struct aq_nic_s *)netdev_priv(ndev);
+	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+	int err = -EOPNOTSUPP;
+
+	switch (cmd->cmd) {
+	case ETHTOOL_GRXRINGS:
+		cmd->data = cfg->vecs;
+		err = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return err;
+}
+
+const struct ethtool_ops aq_ethtool_ops = {
+	.get_link            = aq_ethtool_get_link,
+	.get_regs_len        = aq_ethtool_get_regs_len,
+	.get_regs            = aq_ethtool_get_regs,
+	.get_settings        = aq_ethtool_get_settings,
+	.set_settings        = aq_ethtool_set_settings,
+	.get_drvinfo         = aq_ethtool_get_drvinfo,
+	.get_strings         = aq_ethtool_get_strings,
+	.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+	.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
+	.get_rxfh            = aq_ethtool_get_rss,
+	.get_rxnfc           = aq_ethtool_get_rxnfc,
+	.get_sset_count      = aq_ethtool_get_sset_count,
+	.get_ethtool_stats   = aq_ethtool_stats
+};
+
diff --git a/drivers/net/ethernet/aquantia/aq_ethtool.h b/drivers/net/ethernet/aquantia/aq_ethtool.h
new file mode 100644
index 0000000..186854b
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_ethtool.h
@@ -0,0 +1,20 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_ethtool.h: Declaration of ethertool related functions. */
+
+#ifndef AQ_ETHTOOL_H
+#define AQ_ETHTOOL_H
+
+#include "aq_common.h"
+
+extern const struct ethtool_ops aq_ethtool_ops;
+
+#endif /* AQ_ETHTOOL_H */
+
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 10/13] net: ethernet: aquantia: Hardware interface and utility functions
From: Alexander Loktionov @ 2017-01-09 22:16 UTC (permalink / raw)
  To: netdev, David VomLehn
  Cc: Simon Edelhaus, Alexander Loktionov, Dmitrii Tarakanov,
	Pavel Belous
In-Reply-To: <c2d259cedda86684baf77e04c83ea675ee040bda.1483999588.git.vomlehn@texas.net>

From: David VomLehn <vomlehn@texas.net>

Add functions to interface with the hardware and some utility functions.

Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Pavel Belous <Pavel.Belous@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
 drivers/net/ethernet/aquantia/aq_hw.h       | 170 ++++++++++++++++++++++++++++
 drivers/net/ethernet/aquantia/aq_hw_utils.c |  69 +++++++++++
 drivers/net/ethernet/aquantia/aq_hw_utils.h |  48 ++++++++
 3 files changed, 287 insertions(+)
 create mode 100644 drivers/net/ethernet/aquantia/aq_hw.h
 create mode 100644 drivers/net/ethernet/aquantia/aq_hw_utils.c
 create mode 100644 drivers/net/ethernet/aquantia/aq_hw_utils.h

diff --git a/drivers/net/ethernet/aquantia/aq_hw.h b/drivers/net/ethernet/aquantia/aq_hw.h
new file mode 100644
index 0000000..e9ac912
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_hw.h
@@ -0,0 +1,170 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_hw.h: Declaraion of abstract interface for NIC hardware specific
+ * functions.
+ */
+
+#ifndef AQ_HW_H
+#define AQ_HW_H
+
+#include "aq_common.h"
+
+/* NIC H/W capabilities */
+struct aq_hw_caps_s {
+	u64 hw_features;
+	u64 link_speed_msk;
+	unsigned int hw_priv_flags;
+	u32 rxds;
+	u32 txds;
+	u32 txhwb_alignment;
+	u32 irq_mask;
+	u32 vecs;
+	u32 mtu;
+	u32 mac_regs_count;
+	u8 ports;
+	u8 msix_irqs;
+	u8 tcs;
+	u8 rxd_alignment;
+	u8 rxd_size;
+	u8 txd_alignment;
+	u8 txd_size;
+	u8 tx_rings;
+	u8 rx_rings;
+	bool flow_control;
+	bool is_64_dma;
+};
+
+struct aq_hw_link_status_s {
+	u64 bps;
+};
+
+#define AQ_HW_POWER_STATE_D0   0U
+#define AQ_HW_POWER_STATE_D3   3U
+
+#define AQ_HW_FLAG_STARTED     0x00000004U
+#define AQ_HW_FLAG_STOPPING    0x00000008U
+#define AQ_HW_FLAG_RESETTING   0x00000010U
+#define AQ_HW_FLAG_CLOSING     0x00000020U
+#define AQ_HW_LINK_DOWN        0x04000000U
+#define AQ_HW_FLAG_ERR_UNPLUG  0x40000000U
+#define AQ_HW_FLAG_ERR_HW      0x80000000U
+
+#define AQ_HW_FLAG_ERRORS      (AQ_HW_FLAG_ERR_HW | AQ_HW_FLAG_ERR_UNPLUG)
+
+struct aq_hw_s {
+	AQ_OBJ_HEADER;
+	struct aq_nic_cfg_s *aq_nic_cfg;
+	struct aq_pci_func_s *aq_pci_func;
+	void __iomem *mmio;
+	unsigned int not_ff_addr;
+	struct aq_hw_link_status_s aq_link_status;
+};
+
+struct aq_ring_s;
+struct aq_ring_param_s;
+struct aq_nic_cfg_s;
+struct sk_buff;
+
+struct aq_hw_ops {
+	struct aq_hw_s *(*create)(struct aq_pci_func_s *aq_pci_func,
+				  unsigned int port, struct aq_hw_ops *ops);
+
+	void (*destroy)(struct aq_hw_s *self);
+
+	int (*get_hw_caps)(struct aq_hw_s *self,
+			   struct aq_hw_caps_s *aq_hw_caps);
+
+	int (*hw_ring_tx_xmit)(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
+			       unsigned int frags);
+
+	int (*hw_ring_rx_receive)(struct aq_hw_s *self,
+				  struct aq_ring_s *aq_ring);
+
+	int (*hw_ring_rx_fill)(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
+			       unsigned int sw_tail_old);
+
+	int (*hw_ring_tx_head_update)(struct aq_hw_s *self,
+				      struct aq_ring_s *aq_ring);
+
+	int (*hw_get_mac_permanent)(struct aq_hw_s *self, u8 *mac);
+
+	int (*hw_set_mac_address)(struct aq_hw_s *self, u8 *mac_addr);
+
+	int (*hw_get_link_status)(struct aq_hw_s *self,
+				  struct aq_hw_link_status_s *link_status);
+
+	int (*hw_set_link_speed)(struct aq_hw_s *self, u32 speed);
+
+	int (*hw_reset)(struct aq_hw_s *self);
+
+	int (*hw_init)(struct aq_hw_s *self, struct aq_nic_cfg_s *aq_nic_cfg,
+		       u8 *mac_addr);
+
+	int (*hw_start)(struct aq_hw_s *self);
+
+	int (*hw_stop)(struct aq_hw_s *self);
+
+	int (*hw_ring_tx_init)(struct aq_hw_s *self, struct aq_ring_s *aq_ring,
+			       struct aq_ring_param_s *aq_ring_param);
+
+	int (*hw_ring_tx_start)(struct aq_hw_s *self,
+				struct aq_ring_s *aq_ring);
+
+	int (*hw_ring_tx_stop)(struct aq_hw_s *self,
+			       struct aq_ring_s *aq_ring);
+
+	int (*hw_ring_rx_init)(struct aq_hw_s *self,
+			       struct aq_ring_s *aq_ring,
+			       struct aq_ring_param_s *aq_ring_param);
+
+	int (*hw_ring_rx_start)(struct aq_hw_s *self,
+				struct aq_ring_s *aq_ring);
+
+	int (*hw_ring_rx_stop)(struct aq_hw_s *self,
+			       struct aq_ring_s *aq_ring);
+
+	int (*hw_irq_enable)(struct aq_hw_s *self, u64 mask);
+
+	int (*hw_irq_disable)(struct aq_hw_s *self, u64 mask);
+
+	int (*hw_irq_read)(struct aq_hw_s *self, u64 *mask);
+
+	int (*hw_packet_filter_set)(struct aq_hw_s *self,
+				    unsigned int packet_filter);
+
+	int (*hw_multicast_list_set)(struct aq_hw_s *self,
+				     u8 ar_mac[AQ_CFG_MULTICAST_ADDRESS_MAX]
+				     [ETH_ALEN],
+				     u32 count);
+
+	int (*hw_interrupt_moderation_set)(struct aq_hw_s *self,
+					   bool itr_enabled);
+
+	int (*hw_rss_set)(struct aq_hw_s *self,
+			  struct aq_rss_parameters *rss_params);
+
+	int (*hw_rss_hash_set)(struct aq_hw_s *self,
+			       struct aq_rss_parameters *rss_params);
+
+	int (*hw_get_regs)(struct aq_hw_s *self,
+			   struct aq_hw_caps_s *aq_hw_caps, u32 *regs_buff);
+
+	int (*hw_get_hw_stats)(struct aq_hw_s *self, u64 *data,
+			       unsigned int *p_count);
+
+	int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
+
+	int (*hw_deinit)(struct aq_hw_s *self);
+
+	int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
+};
+
+#endif /* AQ_HW_H */
+
diff --git a/drivers/net/ethernet/aquantia/aq_hw_utils.c b/drivers/net/ethernet/aquantia/aq_hw_utils.c
new file mode 100644
index 0000000..cc64d58
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_hw_utils.c
@@ -0,0 +1,69 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_hw_utils.c: Definitions of helper functions used across
+ * hardware layer.
+ */
+
+#include "aq_hw_utils.h"
+#include "aq_hw.h"
+
+void aq_hw_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
+			 u32 shift, u32 val)
+{
+	if (msk ^ ~0) {
+		u32 reg_old, reg_new;
+
+		reg_old = aq_hw_read_reg(aq_hw, addr);
+		reg_new = (reg_old & (~msk)) | (val << shift);
+
+		if (reg_old != reg_new)
+			aq_hw_write_reg(aq_hw, addr, reg_new);
+	} else {
+		aq_hw_write_reg(aq_hw, addr, val);
+	}
+}
+
+u32 aq_hw_read_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk, u32 shift)
+{
+	return ((aq_hw_read_reg(aq_hw, addr) & msk) >> shift);
+}
+
+u32 aq_hw_read_reg(struct aq_hw_s *hw, u32 reg)
+{
+	u32 value = readl(hw->mmio + reg);
+
+	if ((~0U) == value && (~0U) == readl(hw->mmio + hw->not_ff_addr))
+		AQ_OBJ_SET(hw, AQ_HW_FLAG_ERR_UNPLUG);
+
+	return value;
+}
+
+inline void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value)
+{
+	writel(value, hw->mmio + reg);
+}
+
+int aq_hw_err_from_flags(struct aq_hw_s *hw)
+{
+	int err = 0;
+
+	if (AQ_OBJ_TST(hw, AQ_HW_FLAG_ERR_UNPLUG)) {
+		err = -ENXIO;
+		goto err_exit;
+	}
+	if (AQ_OBJ_TST(hw, AQ_HW_FLAG_ERR_HW)) {
+		err = -EIO;
+		goto err_exit;
+	}
+
+err_exit:
+	return err;
+}
+
diff --git a/drivers/net/ethernet/aquantia/aq_hw_utils.h b/drivers/net/ethernet/aquantia/aq_hw_utils.h
new file mode 100644
index 0000000..8a16707
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_hw_utils.h
@@ -0,0 +1,48 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_hw_utils.h: Declaration of helper functions used across hardware
+ * layer.
+ */
+
+#ifndef AQ_HW_UTILS_H
+#define AQ_HW_UTILS_H
+
+#include "aq_common.h"
+
+#ifndef HIDWORD
+#define LODWORD(_qw)    ((u32)(_qw))
+#define HIDWORD(_qw)    ((u32)(((_qw) >> 32) & 0xffffffff))
+#endif
+
+#define AQ_HW_SLEEP(_US_) mdelay(_US_)
+
+#define AQ_HW_WAIT_FOR(_B_, _US_, _N_) \
+do { \
+	unsigned int AQ_HW_WAIT_FOR_i; \
+	for (AQ_HW_WAIT_FOR_i = _N_; (!(_B_)) && (AQ_HW_WAIT_FOR_i);\
+	--AQ_HW_WAIT_FOR_i) {\
+		udelay(_US_); \
+	} \
+	if (!AQ_HW_WAIT_FOR_i) {\
+		err = ETIME; \
+	} \
+} while (0)
+
+struct aq_hw_s;
+
+void aq_hw_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
+			 u32 shift, u32 val);
+u32 aq_hw_read_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk, u32 shift);
+u32 aq_hw_read_reg(struct aq_hw_s *hw, u32 reg);
+void aq_hw_write_reg(struct aq_hw_s *hw, u32 reg, u32 value);
+int aq_hw_err_from_flags(struct aq_hw_s *hw);
+
+#endif /* AQ_HW_UTILS_H */
+
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 09/13] net: ethernet: aquantia: Atlantic hardware abstraction layer
From: Alexander Loktionov @ 2017-01-09 22:16 UTC (permalink / raw)
  To: netdev, David VomLehn
  Cc: Simon Edelhaus, Alexander Loktionov, Dmitrii Tarakanov,
	Pavel Belous
In-Reply-To: <68bda8ddca6d16001ea990a5197cdcdaa4efa107.1483999588.git.vomlehn@texas.net>

From: David VomLehn <vomlehn@texas.net>

Add common functions for Atlantic hardware abstraction layer.

Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Pavel Belous <Pavel.Belous@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
 .../net/ethernet/aquantia/hw_atl/hw_atl_utils.c    | 548 +++++++++++++++++++++
 .../net/ethernet/aquantia/hw_atl/hw_atl_utils.h    | 211 ++++++++
 2 files changed, 759 insertions(+)
 create mode 100644 drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.c
 create mode 100644 drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.h

diff --git a/drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.c
new file mode 100644
index 0000000..122cd25
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.c
@@ -0,0 +1,548 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
+ * abstraction layer.
+ */
+
+#include "../aq_hw.h"
+#include "../aq_hw_utils.h"
+#include "../aq_pci_func.h"
+#include "../aq_ring.h"
+#include "../aq_vec.h"
+#include "hw_atl_utils.h"
+#include "hw_atl_llh.h"
+
+#include <linux/random.h>
+
+#define HW_ATL_UCP_0X370_REG    0x0370U
+
+#define HW_ATL_FW_SM_RAM        0x2U
+#define HW_ATL_MPI_CONTROL_ADR  0x0368U
+#define HW_ATL_MPI_STATE_ADR    0x036CU
+
+#define HW_ATL_MPI_STATE_MSK    0x00FFU
+#define HW_ATL_MPI_STATE_SHIFT  0U
+#define HW_ATL_MPI_SPEED_MSK    0xFFFFU
+#define HW_ATL_MPI_SPEED_SHIFT  16U
+
+static int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
+					 u32 *p, u32 cnt)
+{
+	int err = 0;
+
+	AQ_HW_WAIT_FOR(reg_glb_cpu_sem_get(self,
+					   HW_ATL_FW_SM_RAM) == 1U, 1U, 1000U);
+
+	if (err < 0) {
+		bool is_locked;
+
+		reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
+		is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
+		if (!is_locked) {
+			err = ETIME;
+			goto err_exit;
+		}
+	}
+
+	aq_hw_write_reg(self, 0x00000208U, a);
+
+	for (++cnt; --cnt;) {
+		u32 i = 0U;
+
+		aq_hw_write_reg(self, 0x00000200U, 0x00008000U);
+
+		for (i = 1024U;
+			(0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
+		}
+
+		*(p++) = aq_hw_read_reg(self, 0x0000020CU);
+	}
+
+	reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
+
+err_exit:
+	return err;
+}
+
+static void hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
+					  u32 cnt)
+{
+	int err = 0;
+	bool is_locked;
+
+	is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
+	if (!is_locked) {
+		err = ETIME;
+		goto err_exit;
+	}
+
+	aq_hw_write_reg(self, 0x00000208U, a);
+
+	for (++cnt; --cnt;) {
+		u32 i = 0U;
+
+		aq_hw_write_reg(self, 0x0000020CU, *(p++));
+		aq_hw_write_reg(self, 0x00000200U, 0xC000U);
+
+		for (i = 1024U;
+			(0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
+		}
+	}
+
+	reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
+
+err_exit:;
+	(void)err;
+}
+
+static int hw_atl_utils_init_ucp(struct aq_hw_s *self)
+{
+	int err = 0;
+
+	if (!aq_hw_read_reg(self, 0x370U)) {
+		unsigned int rnd = 0U;
+		unsigned int ucp_0x370 = 0U;
+
+		get_random_bytes(&rnd, sizeof(unsigned int));
+
+		ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
+		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
+	}
+
+	reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
+
+	/* check 10 times by 1ms */
+	AQ_HW_WAIT_FOR(0U != (PHAL_ATLANTIC_A0->mbox_addr =
+			aq_hw_read_reg(self, 0x360U)), 1000U, 10U);
+
+	return err;
+}
+
+#define HW_ATL_RPC_CONTROL_ADR 0x0338U
+#define HW_ATL_RPC_STATE_ADR   0x033CU
+
+struct aq_hw_atl_utils_fw_rpc_tid_s {
+	union {
+		u32 val;
+		struct {
+			u16 tid;
+			u16 len;
+		};
+	};
+};
+
+#define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
+
+static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
+{
+	int err = 0;
+	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
+
+	if (!IS_CHIP_FEATURE(MIPS)) {
+		err = -1;
+		goto err_exit;
+	}
+	hw_atl_utils_fw_upload_dwords(self, PHAL_ATLANTIC->rpc_addr,
+				      (u32 *)(void *)&PHAL_ATLANTIC->rpc,
+				      (rpc_size + sizeof(u32) -
+				      sizeof(u8)) / sizeof(u32));
+
+	sw.tid = 0xFFFFU & (++PHAL_ATLANTIC->rpc_tid);
+	sw.len = (u16)rpc_size;
+	aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
+
+err_exit:
+	return err;
+}
+
+static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
+				    struct hw_aq_atl_utils_fw_rpc **rpc)
+{
+	int err = 0;
+	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
+	struct aq_hw_atl_utils_fw_rpc_tid_s fw;
+
+	if (IS_CHIP_FEATURE(MIPS)) {
+		if (rpc) {
+			PHAL_ATLANTIC->rpc.msg_id = 0U;
+			*rpc = &PHAL_ATLANTIC->rpc;
+		}
+		goto err_exit;
+	}
+
+	do {
+		sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
+
+		PHAL_ATLANTIC->rpc_tid = sw.tid;
+
+		AQ_HW_WAIT_FOR(sw.tid ==
+				(fw.val =
+				aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR),
+				fw.tid), 10000U, 10U);
+		if (err < 0)
+			goto err_exit;
+
+		if (fw.len == 0xFFFFU) {
+			err = hw_atl_utils_fw_rpc_call(self, sw.len);
+			if (err < 0)
+				goto err_exit;
+		}
+	} while (sw.tid != fw.tid || 0xFFFFU == fw.len);
+	if (err < 0)
+		goto err_exit;
+
+	if (rpc) {
+		if (fw.len)
+			hw_atl_utils_fw_downld_dwords(self,
+						      PHAL_ATLANTIC->rpc_addr,
+						      (u32 *)(void *)
+						      &PHAL_ATLANTIC->rpc,
+						      (fw.len + sizeof(u32) -
+						      sizeof(u8)) /
+						      sizeof(u32));
+
+		*rpc = &PHAL_ATLANTIC->rpc;
+	}
+
+err_exit:
+	return err;
+}
+
+int hw_atl_utils_mpi_create(struct aq_hw_s *self)
+{
+	int err = 0;
+
+	err = hw_atl_utils_init_ucp(self);
+	if (err < 0)
+		goto err_exit;
+
+	err = hw_atl_utils_fw_rpc_init(self);
+	if (err < 0)
+		goto err_exit;
+
+err_exit:
+	return err;
+}
+
+void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
+				 struct hw_aq_atl_utils_mbox *pmbox)
+{
+	int err = 0;
+
+	err = hw_atl_utils_fw_downld_dwords(self,
+					    PHAL_ATLANTIC->mbox_addr,
+					    (u32 *)(void *)pmbox,
+					    sizeof(*pmbox) / sizeof(u32));
+	if (err < 0)
+		goto err_exit;
+
+	if (pmbox != &PHAL_ATLANTIC->mbox)
+		memcpy(pmbox, &PHAL_ATLANTIC->mbox, sizeof(*pmbox));
+
+	if (IS_CHIP_FEATURE(REVISION_A0)) {
+		unsigned int mtu = self->aq_nic_cfg ?
+					self->aq_nic_cfg->mtu : 1514U;
+		pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
+		pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
+		pmbox->stats.dpc = atomic_read(&PHAL_ATLANTIC_A0->dpc);
+	} else {
+		pmbox->stats.dpc = reg_rx_dma_stat_counter7get(self);
+	}
+
+err_exit:;
+}
+
+int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed,
+			       enum hal_atl_utils_fw_state_e state)
+{
+	u32 ucp_0x368 = 0;
+
+	ucp_0x368 = (speed << HW_ATL_MPI_SPEED_SHIFT) | state;
+	aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, ucp_0x368);
+
+	return 0;
+}
+
+void hw_atl_utils_mpi_set(struct aq_hw_s *self,
+			  enum hal_atl_utils_fw_state_e state, u32 speed)
+{
+	int err = 0;
+	u32 transaction_id = 0;
+
+	if (state == MPI_RESET) {
+		hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
+
+		transaction_id = PHAL_ATLANTIC->mbox.transaction_id;
+
+		AQ_HW_WAIT_FOR(transaction_id !=
+				(hw_atl_utils_mpi_read_stats
+					(self, &PHAL_ATLANTIC->mbox),
+					PHAL_ATLANTIC->mbox.transaction_id),
+					1000, 10);
+		if (err < 0)
+			goto err_exit;
+	}
+
+	err = hw_atl_utils_mpi_set_speed(self, speed, state);
+
+err_exit:;
+}
+
+int hw_atl_utils_mpi_get_link_state(struct aq_hw_s *self,
+				    struct aq_hw_link_status_s *link_status)
+{
+	u32 cp0x036C = aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
+	u32 link_speed_mask = cp0x036C >> HW_ATL_MPI_SPEED_SHIFT;
+
+	if (!link_speed_mask) {
+		link_status->bps = 0U;
+	} else {
+		u64 link_speed;
+
+		switch (link_speed_mask) {
+		case HAL_ATLANTIC_RATE_10G:
+			link_speed = 10 * GBIT;
+			break;
+
+		case HAL_ATLANTIC_RATE_5G:
+		case HAL_ATLANTIC_RATE_5GSR:
+			link_speed = 5 * GBIT;
+			break;
+
+		case HAL_ATLANTIC_RATE_2GS:
+			link_speed = 2500 * MBIT;
+			break;
+
+		case HAL_ATLANTIC_RATE_1G:
+			link_speed = 1 * GBIT;
+			break;
+
+		case HAL_ATLANTIC_RATE_100M:
+			link_speed = 100 * MBIT;
+			break;
+
+		default:
+			link_speed = 0U;
+			break;
+		}
+
+		link_status->bps = link_speed;
+	}
+
+	return 0;
+}
+
+int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
+{
+	int err = 0;
+	u32 h = 0U;
+	u32 l = 0U;
+	u32 mac_addr[2];
+
+	self->mmio = aq_pci_func_get_mmio(self->aq_pci_func);
+
+	hw_atl_utils_hw_chip_features_init(self,
+					   &PHAL_ATLANTIC_A0->chip_features);
+
+	err = hw_atl_utils_mpi_create(self);
+	if (err < 0)
+		goto err_exit;
+
+	if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
+		unsigned int rnd = 0;
+		unsigned int ucp_0x370 = 0;
+
+		get_random_bytes(&rnd, sizeof(unsigned int));
+
+		ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
+		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
+	}
+
+	hw_atl_utils_fw_downld_dwords(self, aq_hw_read_reg(self, 0x00000374U) +
+				      (40U * 4U),
+				      mac_addr,
+				      AQ_DIMOF(mac_addr));
+	mac_addr[0] = __swab32(mac_addr[0]);
+	mac_addr[1] = __swab32(mac_addr[1]);
+
+	ether_addr_copy(mac, (u8 *)mac_addr);
+
+	if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
+		/* chip revision */
+		l = 0xE3000000U
+			| (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG))
+			| (0x00 << 16);
+		h = 0x8001300EU;
+
+		mac[5] = (u8)(0xFFU & l);
+		l >>= 8;
+		mac[4] = (u8)(0xFFU & l);
+		l >>= 8;
+		mac[3] = (u8)(0xFFU & l);
+		l >>= 8;
+		mac[2] = (u8)(0xFFU & l);
+		mac[1] = (u8)(0xFFU & h);
+		h >>= 8;
+		mac[0] = (u8)(0xFFU & h);
+	}
+
+err_exit:
+	return err;
+}
+
+int hw_atl_utils_bps_2_speed_index(u64 bps)
+{
+	unsigned int ret = 0U;
+
+	switch (bps) {
+	case 100 * MBIT:
+		ret = 5U;
+		break;
+
+	case 1 * GBIT:
+		ret = 4U;
+		break;
+
+	case 2500 * MBIT:
+		ret = 3U;
+		break;
+
+	case 5 * GBIT:
+		ret = 1U;
+		break;
+
+	case 10 * GBIT:
+		ret = 0U;
+		break;
+
+	default:
+		break;
+	}
+	return ret;
+}
+
+void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
+{
+	u32 chip_features = 0U;
+	u32 val = reg_glb_mif_id_get(self);
+	u32 mif_rev = val & 0xFFU;
+
+	if ((3U & mif_rev) == 1U) {
+		chip_features |=
+			HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
+			HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
+			HAL_ATLANTIC_UTILS_CHIP_MIPS;
+	} else if ((3U & mif_rev) == 2U) {
+		chip_features |=
+			HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
+			HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
+			HAL_ATLANTIC_UTILS_CHIP_MIPS |
+			HAL_ATLANTIC_UTILS_CHIP_TPO2 |
+			HAL_ATLANTIC_UTILS_CHIP_RPF2;
+	}
+
+	*p = chip_features;
+}
+
+int hw_atl_utils_hw_deinit(struct aq_hw_s *self)
+{
+	hw_atl_utils_mpi_set(self, MPI_DEINIT, 0x0U);
+	return 0;
+}
+
+int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
+			      unsigned int power_state)
+{
+	hw_atl_utils_mpi_set(self, MPI_POWER, 0x0U);
+	return 0;
+}
+
+int hw_atl_utils_get_hw_stats(struct aq_hw_s *self,
+			      u64 *data, unsigned int *p_count)
+{
+	struct hw_atl_stats_s *stats = NULL;
+	int i = 0;
+
+	hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
+
+	stats = &PHAL_ATLANTIC->mbox.stats;
+
+	data[i] = stats->uprc + stats->mprc + stats->bprc;
+	data[++i] = stats->uprc;
+	data[++i] = stats->mprc;
+	data[++i] = stats->bprc;
+	data[++i] = stats->erpt;
+	data[++i] = stats->uptc + stats->mptc + stats->bptc;
+	data[++i] = stats->uptc;
+	data[++i] = stats->mptc;
+	data[++i] = stats->bptc;
+	data[++i] = stats->ubrc;
+	data[++i] = stats->ubtc;
+	data[++i] = stats->mbrc;
+	data[++i] = stats->mbtc;
+	data[++i] = stats->bbrc;
+	data[++i] = stats->bbtc;
+	data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
+	data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
+	data[++i] = stats_rx_dma_good_pkt_counterlsw_get(self);
+	data[++i] = stats_tx_dma_good_pkt_counterlsw_get(self);
+	data[++i] = stats_rx_dma_good_octet_counterlsw_get(self);
+	data[++i] = stats_tx_dma_good_octet_counterlsw_get(self);
+	data[++i] = stats->dpc;
+
+	if (p_count)
+		*p_count = ++i;
+
+	return 0;
+}
+
+static const u32 hw_atl_utils_hw_mac_regs[] = {
+	0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
+	0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
+	0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
+	0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
+	0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
+	0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
+	0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
+	0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
+	0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
+	0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
+	0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
+	0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
+	0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
+	0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
+	0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
+	0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
+	0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
+	0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
+	0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
+	0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
+	0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
+	0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
+};
+
+int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
+			     struct aq_hw_caps_s *aq_hw_caps,
+			     u32 *regs_buff)
+{
+	unsigned int i = 0U;
+
+	for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
+		regs_buff[i] = aq_hw_read_reg(self,
+			hw_atl_utils_hw_mac_regs[i]);
+	return 0;
+}
+
+int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
+{
+	*fw_version = aq_hw_read_reg(self, 0x18U);
+	return 0;
+}
+
diff --git a/drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.h
new file mode 100644
index 0000000..8029cb1
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/hw_atl/hw_atl_utils.h
@@ -0,0 +1,211 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File hw_atl_utils.h: Declaration of common functions for Atlantic hardware
+ * abstraction layer.
+ */
+
+#ifndef HW_ATL_UTILS_H
+#define HW_ATL_UTILS_H
+
+#include "../aq_common.h"
+
+#define HW_ATL_FLUSH() { (void)aq_hw_read_reg(self, 0x10); }
+
+struct __packed hw_atl_stats_s {
+	u32 uprc;
+	u32 mprc;
+	u32 bprc;
+	u32 erpt;
+	u32 uptc;
+	u32 mptc;
+	u32 bptc;
+	u32 erpr;
+	u32 mbtc;
+	u32 bbtc;
+	u32 mbrc;
+	u32 bbrc;
+	u32 ubrc;
+	u32 ubtc;
+	u32 dpc;
+};
+
+union __packed ip_addr {
+	struct {
+		u8 addr[16];
+	} v6;
+	struct {
+		u8 padding[12];
+		u8 addr[4];
+	} v4;
+};
+
+struct __packed hw_aq_atl_utils_fw_rpc {
+	u32 msg_id;
+
+	union {
+		struct {
+			u32 pong;
+		} msg_ping;
+
+		struct {
+			u8 mac_addr[6];
+			u32 ip_addr_cnt;
+
+			struct {
+				union ip_addr addr;
+				union ip_addr mask;
+			} ip[1];
+		} msg_arp;
+
+		struct {
+			u32 len;
+			u8 packet[1514U];
+		} msg_inject;
+
+		struct {
+			u32 priority;
+			u32 wol_packet_type;
+			u16 friendly_name_len;
+			u16 friendly_name[65];
+			u32 pattern_id;
+			u32 next_wol_pattern_offset;
+
+			union {
+				struct {
+					u32 flags;
+					u8 ipv4_source_address[4];
+					u8 ipv4_dest_address[4];
+					u16 tcp_source_port_number;
+					u16 tcp_dest_port_number;
+				} ipv4_tcp_syn_parameters;
+
+				struct {
+					u32 flags;
+					u8 ipv6_source_address[16];
+					u8 ipv6_dest_address[16];
+					u16 tcp_source_port_number;
+					u16 tcp_dest_port_number;
+				} ipv6_tcp_syn_parameters;
+
+				struct {
+					u32 flags;
+				} eapol_request_id_message_parameters;
+
+				struct {
+					u32 flags;
+					u32 mask_offset;
+					u32 mask_size;
+					u32 pattern_offset;
+					u32 pattern_size;
+				} wol_bit_map_pattern;
+			} wol_pattern;
+		} msg_wol;
+
+		struct {
+			u32 is_wake_on_link_down;
+			u32 is_wake_on_link_up;
+		} msg_wolink;
+	};
+};
+
+struct __packed hw_aq_atl_utils_mbox {
+	u32 version;
+	u32 transaction_id;
+	int error;
+	struct hw_atl_stats_s stats;
+};
+
+struct __packed hw_atl_s {
+	struct aq_hw_s base;
+	struct hw_aq_atl_utils_mbox mbox;
+	u64 speed;
+	u32 itr_tx;
+	u32 itr_rx;
+	unsigned int chip_features;
+	u32 fw_ver_actual;
+	atomic_t dpc;
+	u32 mbox_addr;
+	u32 rpc_addr;
+	u32 rpc_tid;
+	struct hw_aq_atl_utils_fw_rpc rpc;
+};
+
+#define SELF ((struct hw_atl_s *)self)
+
+#define PHAL_ATLANTIC ((struct hw_atl_s *)((void *)(self)))
+#define PHAL_ATLANTIC_A0 ((struct hw_atl_s *)((void *)(self)))
+#define PHAL_ATLANTIC_B0 ((struct hw_atl_s *)((void *)(self)))
+
+#define HAL_ATLANTIC_UTILS_CHIP_MIPS         0x00000001U
+#define HAL_ATLANTIC_UTILS_CHIP_TPO2         0x00000002U
+#define HAL_ATLANTIC_UTILS_CHIP_RPF2         0x00000004U
+#define HAL_ATLANTIC_UTILS_CHIP_MPI_AQ       0x00000010U
+#define HAL_ATLANTIC_UTILS_CHIP_REVISION_A0  0x01000000U
+#define HAL_ATLANTIC_UTILS_CHIP_REVISION_B0  0x02000000U
+
+#define IS_CHIP_FEATURE(_F_) (HAL_ATLANTIC_UTILS_CHIP_##_F_ & \
+				PHAL_ATLANTIC->chip_features)
+
+enum hal_atl_utils_fw_state_e {
+	MPI_DEINIT = 0,
+	MPI_RESET = 1,
+	MPI_INIT = 2,
+	MPI_POWER = 4,
+};
+
+#define HAL_ATLANTIC_RATE_10G        BIT(0)
+#define HAL_ATLANTIC_RATE_5G         BIT(1)
+#define HAL_ATLANTIC_RATE_5GSR       BIT(2)
+#define HAL_ATLANTIC_RATE_2GS        BIT(3)
+#define HAL_ATLANTIC_RATE_1G         BIT(4)
+#define HAL_ATLANTIC_RATE_100M       BIT(5)
+#define HAL_ATLANTIC_RATE_INVALID    BIT(6)
+
+int hw_atl_utils_mpi_create(struct aq_hw_s *self);
+
+void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p);
+
+void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
+				 struct hw_aq_atl_utils_mbox *pmbox);
+
+void hw_atl_utils_mpi_set(struct aq_hw_s *self,
+			  enum hal_atl_utils_fw_state_e state,
+			  u32 speed);
+
+int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed,
+			       enum hal_atl_utils_fw_state_e state);
+
+int hw_atl_utils_mpi_get_link_state(struct aq_hw_s *self,
+				    struct aq_hw_link_status_s *link_status);
+
+int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, u8 *mac);
+
+int hw_atl_utils_bps_2_speed_index(u64 bps);
+
+int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
+			     struct aq_hw_caps_s *aq_hw_caps,
+			     u32 *regs_buff);
+
+int hw_atl_utils_hw_get_settings(struct aq_hw_s *self,
+				 struct ethtool_cmd *cmd);
+
+int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
+			      unsigned int power_state);
+
+int hw_atl_utils_hw_deinit(struct aq_hw_s *self);
+
+int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version);
+
+int hw_atl_utils_get_hw_stats(struct aq_hw_s *self,
+			      u64 *data,
+			      unsigned int *p_count);
+
+#endif /* HW_ATL_UTILS_H */
+
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 08/13] net: ethernet: aquantia: PCI operations
From: Alexander Loktionov @ 2017-01-09 22:16 UTC (permalink / raw)
  To: netdev, David VomLehn
  Cc: Simon Edelhaus, Alexander Loktionov, Dmitrii Tarakanov,
	Pavel Belous
In-Reply-To: <5cf2494bfdb3e327dec2fdc7c50ae56fdac83a2f.1483999588.git.vomlehn@texas.net>

From: David VomLehn <vomlehn@texas.net>

Add functions that handle the PCI bus interface.

Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Pavel Belous <Pavel.Belous@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
 drivers/net/ethernet/aquantia/aq_pci_func.c | 348 ++++++++++++++++++++++++++++
 drivers/net/ethernet/aquantia/aq_pci_func.h |  35 +++
 2 files changed, 383 insertions(+)
 create mode 100644 drivers/net/ethernet/aquantia/aq_pci_func.c
 create mode 100644 drivers/net/ethernet/aquantia/aq_pci_func.h

diff --git a/drivers/net/ethernet/aquantia/aq_pci_func.c b/drivers/net/ethernet/aquantia/aq_pci_func.c
new file mode 100644
index 0000000..18c427d
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_pci_func.c
@@ -0,0 +1,348 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_pci_func.c: Definition of PCI functions. */
+
+#include "aq_pci_func.h"
+#include "aq_nic.h"
+#include "aq_vec.h"
+#include "aq_hw.h"
+#include <linux/interrupt.h>
+
+struct aq_pci_func_s {
+	struct pci_dev *pdev;
+	struct aq_nic_s *port[AQ_CFG_PCI_FUNC_PORTS];
+	void __iomem *mmio;
+	void *aq_vec[AQ_CFG_PCI_FUNC_MSIX_IRQS];
+	resource_size_t mmio_pa;
+	unsigned int msix_entry_mask;
+	unsigned int irq_type;
+	unsigned int ports;
+	bool is_pci_enabled;
+	bool is_regions;
+	bool is_pci_using_dac;
+	struct aq_hw_caps_s aq_hw_caps;
+	struct msix_entry msix_entry[AQ_CFG_PCI_FUNC_MSIX_IRQS];
+};
+
+struct aq_pci_func_s *aq_pci_func_alloc(struct aq_hw_ops *aq_hw_ops,
+					struct pci_dev *pdev,
+					const struct net_device_ops *ndev_ops,
+					const struct ethtool_ops *eth_ops)
+{
+	struct aq_pci_func_s *self = NULL;
+	int err = 0;
+	unsigned int port = 0U;
+
+	if (!aq_hw_ops) {
+		err = -EFAULT;
+		goto err_exit;
+	}
+	self = kzalloc(sizeof(*self), GFP_KERNEL);
+	if (!self) {
+		err = -ENOMEM;
+		goto err_exit;
+	}
+
+	pci_set_drvdata(pdev, self);
+	self->pdev = pdev;
+
+	err = aq_hw_ops->get_hw_caps(NULL, &self->aq_hw_caps);
+	if (err < 0)
+		goto err_exit;
+
+	self->ports = self->aq_hw_caps.ports;
+
+	for (port = 0; port < self->ports; ++port) {
+		struct aq_nic_s *aq_nic = aq_nic_alloc_cold(ndev_ops, eth_ops,
+							    &pdev->dev, self,
+							    port, aq_hw_ops);
+
+		if (!aq_nic) {
+			err = -ENOMEM;
+			goto err_exit;
+		}
+		self->port[port] = aq_nic;
+	}
+
+err_exit:
+	if (err < 0) {
+		if (self)
+			aq_pci_func_free(self);
+		self = NULL;
+	}
+
+	(void)err;
+	return self;
+}
+
+int aq_pci_func_init(struct aq_pci_func_s *self)
+{
+	int err = 0;
+	unsigned int bar = 0U;
+	unsigned int port = 0U;
+	unsigned int i = 0U;
+
+	err = pci_enable_device(self->pdev);
+	if (err < 0)
+		goto err_exit;
+
+	self->is_pci_enabled = true;
+
+	err = pci_set_dma_mask(self->pdev, DMA_BIT_MASK(64));
+	if (!err) {
+		err = pci_set_consistent_dma_mask(self->pdev, DMA_BIT_MASK(64));
+		self->is_pci_using_dac = 1;
+	}
+	if (err) {
+		err = pci_set_dma_mask(self->pdev, DMA_BIT_MASK(32));
+		if (!err)
+			err = pci_set_consistent_dma_mask(self->pdev,
+							  DMA_BIT_MASK(32));
+		self->is_pci_using_dac = 0;
+	}
+	if (err != 0) {
+		err = -ENOSR;
+		goto err_exit;
+	}
+
+	err = pci_request_regions(self->pdev, AQ_CFG_DRV_NAME "_mmio");
+	if (err < 0)
+		goto err_exit;
+
+	self->is_regions = true;
+
+	pci_set_master(self->pdev);
+
+	for (bar = 0; bar < 4; ++bar) {
+		if (IORESOURCE_MEM & pci_resource_flags(self->pdev, bar)) {
+			resource_size_t reg_sz;
+
+			self->mmio_pa = pci_resource_start(self->pdev, bar);
+			if (self->mmio_pa == 0U) {
+				err = -EIO;
+				goto err_exit;
+			}
+
+			reg_sz = pci_resource_len(self->pdev, bar);
+			if ((reg_sz <= 24 /*ATL_REGS_SIZE*/)) {
+				err = -EIO;
+				goto err_exit;
+			}
+
+			self->mmio = ioremap_nocache(self->mmio_pa, reg_sz);
+			if (!self->mmio) {
+				err = -EIO;
+				goto err_exit;
+			}
+			break;
+		}
+	}
+
+	if (err < 0)
+		goto err_exit;
+	for (i = 0; i < self->aq_hw_caps.msix_irqs; i++)
+		self->msix_entry[i].entry = i;
+
+	/*enable interrupts */
+#if AQ_CFG_FORCE_LEGACY_INT
+	self->irq_type = AQ_IRQ_LEGACY;
+#else
+	err = pci_enable_msix(self->pdev, self->msix_entry,
+			      self->aq_hw_caps.msix_irqs);
+
+	if (err >= 0) {
+		self->irq_type = AQ_IRQ_MSIX;
+	} else {
+		err = pci_enable_msi(self->pdev);
+
+		if (err >= 0) {
+			self->irq_type = AQ_IRQ_MSI;
+		} else {
+			self->irq_type = AQ_IRQ_LEGACY;
+			err = 0;
+		}
+	}
+#endif
+
+	/* net device init */
+	for (port = 0; port < self->ports; ++port) {
+		if (!self->port[port])
+			continue;
+
+		aq_nic_cfg_start(self->port[port]);
+		aq_nic_ndev_init(self->port[port]);
+
+		err = aq_nic_ndev_register(self->port[port]);
+		if (err < 0)
+			goto err_exit;
+	}
+
+err_exit:
+	if (err < 0)
+		aq_pci_func_deinit(self);
+	return err;
+}
+
+int aq_pci_func_alloc_irq(struct aq_pci_func_s *self, unsigned int i,
+			  char *name, void *aq_vec, cpumask_t *affinity_mask)
+{
+	int err = 0;
+
+	switch (self->irq_type) {
+	case AQ_IRQ_MSIX:
+		err = request_irq(self->msix_entry[i].vector, aq_vec_isr, 0,
+				  name, aq_vec);
+		break;
+
+	case AQ_IRQ_MSI:
+		err = request_irq(self->pdev->irq, aq_vec_isr, 0, name, aq_vec);
+		break;
+
+	case AQ_IRQ_LEGACY:
+		err = request_irq(self->pdev->irq, aq_vec_isr_legacy,
+				  IRQF_SHARED, name, aq_vec);
+		break;
+
+	default:
+		err = -EFAULT;
+		break;
+	}
+
+	if (err >= 0) {
+		self->msix_entry_mask |= (1 << i);
+		self->aq_vec[i] = aq_vec;
+
+		if (self->irq_type == AQ_IRQ_MSIX)
+			irq_set_affinity_hint(self->msix_entry[i].vector,
+					      affinity_mask);
+	}
+
+	return err;
+}
+
+void aq_pci_func_free_irqs(struct aq_pci_func_s *self)
+{
+	unsigned int i = 0U;
+
+	for (i = 32U; i--;) {
+		if (!((1U << i) & self->msix_entry_mask))
+			continue;
+
+		switch (self->irq_type) {
+		case AQ_IRQ_MSIX:
+			irq_set_affinity_hint(self->msix_entry[i].vector, NULL);
+			free_irq(self->msix_entry[i].vector, self->aq_vec[i]);
+			break;
+
+		case AQ_IRQ_MSI:
+			free_irq(self->pdev->irq, self->aq_vec[i]);
+			break;
+
+		case AQ_IRQ_LEGACY:
+			free_irq(self->pdev->irq, self->aq_vec[i]);
+			break;
+
+		default:
+			break;
+		}
+
+		self->msix_entry_mask &= ~(1U << i);
+	}
+}
+
+void __iomem *aq_pci_func_get_mmio(struct aq_pci_func_s *self)
+{
+	return self->mmio;
+}
+
+unsigned int aq_pci_func_get_irq_type(struct aq_pci_func_s *self)
+{
+	return self->irq_type;
+}
+
+int aq_pci_func_deinit(struct aq_pci_func_s *self)
+{
+	int err = 0;
+
+	if (!self) {
+		err = -EFAULT;
+		goto err_exit;
+	}
+	aq_pci_func_free_irqs(self);
+
+	switch (self->irq_type) {
+	case AQ_IRQ_MSI:
+		pci_disable_msi(self->pdev);
+		break;
+
+	case AQ_IRQ_MSIX:
+		pci_disable_msix(self->pdev);
+		break;
+
+	case AQ_IRQ_LEGACY:
+		break;
+
+	default:
+		break;
+	}
+
+	if (self->is_regions)
+		pci_release_regions(self->pdev);
+
+	if (self->is_pci_enabled)
+		pci_disable_device(self->pdev);
+
+err_exit:
+	return err;
+}
+
+void aq_pci_func_free(struct aq_pci_func_s *self)
+{
+	int err = 0;
+	unsigned int port = 0U;
+
+	if (!self) {
+		err = -EFAULT;
+		goto err_exit;
+	}
+	for (port = 0; port < self->ports; ++port) {
+		if (!self->port[port])
+			continue;
+
+		aq_nic_ndev_free(self->port[port]);
+	}
+
+	kfree(self);
+
+err_exit:
+	(void)err;
+}
+
+int aq_pci_func_change_pm_state(struct aq_pci_func_s *self,
+				pm_message_t *pm_msg)
+{
+	int err = 0;
+	unsigned int port = 0U;
+
+	if (!self) {
+		err = -EFAULT;
+		goto err_exit;
+	}
+	for (port = 0; port < self->ports; ++port) {
+		if (!self->port[port])
+			continue;
+
+		aq_nic_change_pm_state(self->port[port], pm_msg);
+	}
+
+err_exit:
+	return err;
+}
+
diff --git a/drivers/net/ethernet/aquantia/aq_pci_func.h b/drivers/net/ethernet/aquantia/aq_pci_func.h
new file mode 100644
index 0000000..d5b3510
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/aq_pci_func.h
@@ -0,0 +1,35 @@
+/*
+ * aQuantia Corporation Network Driver
+ * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+/* File aq_pci_func.h: Declaration of PCI functions. */
+
+#ifndef AQ_PCI_FUNC_H
+#define AQ_PCI_FUNC_H
+
+#include "aq_common.h"
+
+struct aq_pci_func_s *aq_pci_func_alloc(struct aq_hw_ops *hw_ops,
+					struct pci_dev *pdev,
+					const struct net_device_ops *ndev_ops,
+					const struct ethtool_ops *eth_ops);
+int aq_pci_func_init(struct aq_pci_func_s *self);
+int aq_pci_func_alloc_irq(struct aq_pci_func_s *self, unsigned int i,
+			  char *name, void *aq_vec,
+			  cpumask_t *affinity_mask);
+void aq_pci_func_free_irqs(struct aq_pci_func_s *self);
+int aq_pci_func_start(struct aq_pci_func_s *self);
+void __iomem *aq_pci_func_get_mmio(struct aq_pci_func_s *self);
+unsigned int aq_pci_func_get_irq_type(struct aq_pci_func_s *self);
+int aq_pci_func_deinit(struct aq_pci_func_s *self);
+void aq_pci_func_free(struct aq_pci_func_s *self);
+int aq_pci_func_change_pm_state(struct aq_pci_func_s *self,
+				pm_message_t *pm_msg);
+
+#endif /* AQ_PCI_FUNC_H */
+
-- 
2.7.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox