* [PATCH] net: fix incorrect original ingress device index in PKTINFO
From: Wei Zhang @ 2016-12-27 7:52 UTC (permalink / raw)
To: davem, kuznet, jmorris, yoshfuji, kaber; +Cc: netdev, linux-kernel
When we send a packet for our own local address on a non-loopback interface
(e.g. eth0), due to the change had been introduced from commit 0b922b7a829c
("net: original ingress device index in PKTINFO"), the original ingress
device index would be set as the loopback interface. However, the packet
should be considered as if it is being arrived via the sending interface
(eth0), otherwise it would break the expectation of the userspace
application (e.g. the DHCPRELEASE message from dhcp_release binary would
be ignored by the dnsmasq daemon)
Signed-off-by: Wei Zhang <asuka.com@163.com>
---
net/ipv4/ip_sockglue.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index b8a2d63..b6a6d35 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1202,8 +1202,13 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
* which has interface index (iif) as the first member of the
* underlying inet{6}_skb_parm struct. This code then overlays
* PKTINFO_SKB_CB and in_pktinfo also has iif as the first
- * element so the iif is picked up from the prior IPCB
+ * element so the iif is picked up from the prior IPCB except
+ * iif is loopback interface which the packet should be
+ * considered as if it is being arrived via the sending interface
*/
+ if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX) {
+ pktinfo->ipi_ifindex = inet_iif(skb);
+ }
pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
} else {
pktinfo->ipi_ifindex = 0;
--
1.8.3.1
^ permalink raw reply related
* [PATCH] net: dev_weight: TX/RX orthogonality
From: Matthias Tafelmeier @ 2016-12-27 8:25 UTC (permalink / raw)
To: netdev; +Cc: hagen, fw, edumazet, daniel
In-Reply-To: <20161226.115818.1691666598003246082.davem@davemloft.net>
Oftenly, introducing side effects on packet processing on the other half
of the stack by adjusting one of TX/RX via sysctl is not desirable.
There are cases of demand for asymmetric, orthogonal configurability.
This holds true especially for nodes where RPS for RFS usage on top is
configured and therefore use the 'old dev_weight'. This is quite a
common base configuration setup nowadays, even with NICs of superior processing
support (e.g. aRFS).
A good example use case are nodes acting as noSQL data bases with a
large number of tiny requests and rather fewer but large packets as responses.
It's affordable to have large budget and rx dev_weights for the
requests. But as a side effect having this large a number on TX
processed in one run can overwhelm drivers.
This patch therefore introduces an independent configurability via sysctl to
userland.
---
include/linux/netdevice.h | 2 ++
net/core/dev.c | 4 +++-
net/core/sysctl_net_core.c | 14 ++++++++++++++
net/sched/sch_generic.c | 2 +-
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 994f742..bb331e0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3795,6 +3795,8 @@ void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
extern int netdev_max_backlog;
extern int netdev_tstamp_prequeue;
extern int weight_p;
+extern int dev_w_rx_bias;
+extern int dev_w_tx_bias;
bool netdev_has_upper_dev(struct net_device *dev, struct net_device *upper_dev);
struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
diff --git a/net/core/dev.c b/net/core/dev.c
index 8db5a0b..0dcbd28 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3428,6 +3428,8 @@ EXPORT_SYMBOL(netdev_max_backlog);
int netdev_tstamp_prequeue __read_mostly = 1;
int netdev_budget __read_mostly = 300;
int weight_p __read_mostly = 64; /* old backlog weight */
+int dev_w_rx_bias __read_mostly = 1; /* bias for backlog weight */
+int dev_w_tx_bias __read_mostly = 1; /* bias for output_queue quota */
/* Called with irq disabled */
static inline void ____napi_schedule(struct softnet_data *sd,
@@ -4833,7 +4835,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
net_rps_action_and_irq_enable(sd);
}
- napi->weight = weight_p;
+ napi->weight = weight_p * dev_w_rx_bias;
while (again) {
struct sk_buff *skb;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 2a46e40..a2ab149 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -276,6 +276,20 @@ static struct ctl_table net_core_table[] = {
.proc_handler = proc_dointvec
},
{
+ .procname = "dev_w_rx_bias",
+ .data = &dev_w_rx_bias,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .procname = "dev_w_tx_bias",
+ .data = &dev_w_tx_bias,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
.procname = "netdev_max_backlog",
.data = &netdev_max_backlog,
.maxlen = sizeof(int),
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 6eb9c8e..4c07780 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -247,7 +247,7 @@ static inline int qdisc_restart(struct Qdisc *q, int *packets)
void __qdisc_run(struct Qdisc *q)
{
- int quota = weight_p;
+ int quota = weight_p * dev_w_tx_bias;
int packets;
while (qdisc_restart(q, &packets)) {
--
2.7.4
^ permalink raw reply related
* Re:[PATCH] net: fix incorrect original ingress device index in PKTINFO
From: wei zhang @ 2016-12-27 8:29 UTC (permalink / raw)
To: kuznet, davem, jmorris, yoshfuji, kaber; +Cc: netdev, linux-kernel
In-Reply-To: <1482825138-2125-1-git-send-email-asuka.com@163.com>
At 2016-12-27 15:52:18, "Wei Zhang" <asuka.com@163.com> wrote:
>When we send a packet for our own local address on a non-loopback interface
>(e.g. eth0), due to the change had been introduced from commit 0b922b7a829c
>("net: original ingress device index in PKTINFO"), the original ingress
>device index would be set as the loopback interface. However, the packet
>should be considered as if it is being arrived via the sending interface
>(eth0), otherwise it would break the expectation of the userspace
>application (e.g. the DHCPRELEASE message from dhcp_release binary would
>be ignored by the dnsmasq daemon)
>
>Signed-off-by: Wei Zhang <asuka.com@163.com>
>---
> net/ipv4/ip_sockglue.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
>diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
>index b8a2d63..b6a6d35 100644
>--- a/net/ipv4/ip_sockglue.c
>+++ b/net/ipv4/ip_sockglue.c
>@@ -1202,8 +1202,13 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
> * which has interface index (iif) as the first member of the
> * underlying inet{6}_skb_parm struct. This code then overlays
> * PKTINFO_SKB_CB and in_pktinfo also has iif as the first
>- * element so the iif is picked up from the prior IPCB
>+ * element so the iif is picked up from the prior IPCB except
>+ * iif is loopback interface which the packet should be
>+ * considered as if it is being arrived via the sending interface
> */
>+ if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX) {
>+ pktinfo->ipi_ifindex = inet_iif(skb);
>+ }
> pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
> } else {
> pktinfo->ipi_ifindex = 0;
>--
>1.8.3.1
>
When I upgrade to the 4.9, the dhcp_release could not release the dhcp
lease, the dnsmasq ignored all the DHCPRELEASE message which it think come
from lo. I think this is due to the commit 0b922b7a829c, which set the
IPCB(skb)->iif = skb->skb_iif in the ip_rcv()!
And I'm very sorry about forgetting checkpatch, I will resend the patch,
hope I'm not bothering you!
Thanks,
Wei Zhang
^ permalink raw reply
* [PATCH net-next] r8169: add support for RTL8168 series add-on card.
From: Chun-Hao Lin @ 2016-12-27 8:29 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, Chun-Hao Lin
This chip is the same as RTL8168, but its device id is 0x8161.
Signed-off-by: Chun-Hao Lin <hau@realtek.com>
---
drivers/net/ethernet/realtek/r8169.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index f9b97f5..44389c9 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -326,6 +326,7 @@ enum cfg_version {
static const struct pci_device_id rtl8169_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161), 0, 0, RTL_CFG_1 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
--
2.7.4
^ permalink raw reply related
* Re: [PATCH net] net: xdp: remove unused bfp_warn_invalid_xdp_buffer()
From: Daniel Borkmann @ 2016-12-27 9:29 UTC (permalink / raw)
To: Jason Wang, davem, linux-kernel, netdev; +Cc: John Fastabend
In-Reply-To: <1482806994-14649-1-git-send-email-jasowang@redhat.com>
On 12/27/2016 03:49 AM, Jason Wang wrote:
> After commit 73b62bd085f4737679ea9afc7867fa5f99ba7d1b ("virtio-net:
> remove the warning before XDP linearizing"), there's no users for
> bpf_warn_invalid_xdp_buffer(), so remove it. This is a revert for
> commit f23bc46c30ca5ef58b8549434899fcbac41b2cfc.
>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: John Fastabend <john.r.fastabend@intel.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
Thanks for following up.
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
^ permalink raw reply
* [PATCH] net: fix incorrect original ingress device index in PKTINFO
From: Wei Zhang @ 2016-12-27 9:52 UTC (permalink / raw)
To: davem, kuznet, jmorris, yoshfuji, kaber; +Cc: netdev, linux-kernel
When we send a packet for our own local address on a non-loopback
interface (e.g. eth0), due to the change had been introduced from
commit 0b922b7a829c ("net: original ingress device index in PKTINFO"), the
original ingress device index would be set as the loopback interface.
However, the packet should be considered as if it is being arrived via the
sending interface (eth0), otherwise it would break the expectation of the
userspace application (e.g. the DHCPRELEASE message from dhcp_release
binary would be ignored by the dnsmasq daemon, since it come from lo which
is not the interface dnsmasq bind to)
Signed-off-by: Wei Zhang <asuka.com@163.com>
---
net/ipv4/ip_sockglue.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index b8a2d63..76d78a7 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1202,8 +1202,14 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
* which has interface index (iif) as the first member of the
* underlying inet{6}_skb_parm struct. This code then overlays
* PKTINFO_SKB_CB and in_pktinfo also has iif as the first
- * element so the iif is picked up from the prior IPCB
+ * element so the iif is picked up from the prior IPCB except
+ * iif is loopback interface which the packet should be
+ * considered as if it is being arrived via the sending
+ * interface
*/
+ if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX)
+ pktinfo->ipi_ifindex = inet_iif(skb);
+
pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
} else {
pktinfo->ipi_ifindex = 0;
--
1.8.3.1
^ permalink raw reply related
* Greetings From Mr. Hamidou Kader.
From: Mr. Hamidou Kader @ 2016-12-27 9:50 UTC (permalink / raw)
In-Reply-To: <1424159083.2117965.1482832245161.ref@mail.yahoo.com>
Greetings From Mr. Hamidou Kader.
I have a Mutual/Beneficial Business Project that would be beneficial to you. I only have two questions to ask of you,if you are interested.
1. Can you handle this project?
2. Can I give you this trust ?
Please note that the deal requires high level of maturity, honesty and secrecy. This will involve moving some money from my office, on trust to your hands or bank account. Also note that i will do everything to make sure that the money is moved as a purely legitimate fund, so you will not be exposed to any risk.
I request for your full co-operation. I will give you details and procedure when I receive your reply, To commence this transaction, I require you to immediately indicate your interest by a return reply.
I will be waiting for your response in a timely manner.
please contact me through my private email address: hamidoukader@barid.com
Best Regard,
Mr. Hamidou Kader
^ permalink raw reply
* Re: [RFC PATCH 4.10 1/6] crypto/sha256: Refactor the API so it can be used without shash
From: Herbert Xu @ 2016-12-27 9:58 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Ard Biesheuvel, Andy Lutomirski, Daniel Borkmann, Netdev, LKML,
Linux Crypto Mailing List, Jason A. Donenfeld,
Hannes Frederic Sowa, Alexei Starovoitov, Eric Dumazet,
Eric Biggers, Tom Herbert, David S. Miller
In-Reply-To: <CALCETrXFTQ2AXgbQzPnRcDRHK81=FS1R0zqfoTqGjUsqZy2PvQ@mail.gmail.com>
On Mon, Dec 26, 2016 at 10:08:48AM -0800, Andy Lutomirski wrote:
>
> According to Daniel, the networking folks want to let embedded systems
> include BPF without requiring the crypto core.
Last I checked the IPv4 stack depended on the crypto API so this
sounds bogus.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] net: fix incorrect original ingress device index in PKTINFO
From: Sergei Shtylyov @ 2016-12-27 10:01 UTC (permalink / raw)
To: Wei Zhang, davem, kuznet, jmorris, yoshfuji, kaber; +Cc: netdev, linux-kernel
In-Reply-To: <1482825138-2125-1-git-send-email-asuka.com@163.com>
Hello!
On 12/27/2016 10:52 AM, Wei Zhang wrote:
> When we send a packet for our own local address on a non-loopback interface
> (e.g. eth0), due to the change had been introduced from commit 0b922b7a829c
> ("net: original ingress device index in PKTINFO"), the original ingress
> device index would be set as the loopback interface. However, the packet
> should be considered as if it is being arrived via the sending interface
> (eth0), otherwise it would break the expectation of the userspace
> application (e.g. the DHCPRELEASE message from dhcp_release binary would
> be ignored by the dnsmasq daemon)
>
> Signed-off-by: Wei Zhang <asuka.com@163.com>
> ---
> net/ipv4/ip_sockglue.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
> index b8a2d63..b6a6d35 100644
> --- a/net/ipv4/ip_sockglue.c
> +++ b/net/ipv4/ip_sockglue.c
> @@ -1202,8 +1202,13 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
> * which has interface index (iif) as the first member of the
> * underlying inet{6}_skb_parm struct. This code then overlays
> * PKTINFO_SKB_CB and in_pktinfo also has iif as the first
> - * element so the iif is picked up from the prior IPCB
> + * element so the iif is picked up from the prior IPCB except
> + * iif is loopback interface which the packet should be
Tail space.
> + * considered as if it is being arrived via the sending interface
> */
> + if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX) {
> + pktinfo->ipi_ifindex = inet_iif(skb);
> + }
{} not needed here.
> pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
> } else {
> pktinfo->ipi_ifindex = 0;
MBR, Sergei
^ permalink raw reply
* Re: [PATCH v2] net: stmmac: bug fix to synchronize stmmac_open and stmmac_dvr_probe
From: Pavel Machek @ 2016-12-27 10:48 UTC (permalink / raw)
To: Kweh, Hock Leong
Cc: David S. Miller, Joao Pinto, Giuseppe CAVALLARO,
seraphin.bonnaffe, f.fainelli, Alexandre TORGUE, Joachim Eastwood,
Niklas Cassel, Johan Hovold, Ong Boon Leong, weifeng.voon,
lars.persson, Netdev list, LKML
In-Reply-To: <1482849756-21817-1-git-send-email-hock.leong.kweh@intel.com>
[-- Attachment #1: Type: text/plain, Size: 2190 bytes --]
On Tue 2016-12-27 22:42:36, Kweh, Hock Leong wrote:
> From: "Kweh, Hock Leong" <hock.leong.kweh@intel.com>
>
> If kernel module stmmac driver being loaded after OS booted, there is a
> race condition between stmmac_open() and stmmac_mdio_register(), which is
> invoked inside stmmac_dvr_probe(), and the error is showed in dmesg log as
> PHY not found and stmmac_open() failed:
> [ 473.919358] stmmaceth 0000:01:00.0 (unnamed net_device) (uninitialized):
> stmmac_dvr_probe: warning: cannot get CSR clock
> [ 473.919382] stmmaceth 0000:01:00.0: no reset control found
> [ 473.919412] stmmac - user ID: 0x10, Synopsys ID: 0x42
> [ 473.919429] stmmaceth 0000:01:00.0: DMA HW capability register supported
> [ 473.919436] stmmaceth 0000:01:00.0: RX Checksum Offload Engine supported
> [ 473.919443] stmmaceth 0000:01:00.0: TX Checksum insertion supported
> [ 473.919451] stmmaceth 0000:01:00.0 (unnamed net_device) (uninitialized):
> Enable RX Mitigation via HW Watchdog Timer
> [ 473.921395] libphy: PHY stmmac-1:00 not found
> [ 473.921417] stmmaceth 0000:01:00.0 eth0: Could not attach to PHY
> [ 473.921427] stmmaceth 0000:01:00.0 eth0: stmmac_open: Cannot attach to
> PHY (error: -19)
> [ 473.959710] libphy: stmmac: probed
> [ 473.959724] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 0 IRQ POLL
> (stmmac-1:00) active
> [ 473.959728] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 1 IRQ POLL
> (stmmac-1:01)
> [ 473.959731] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 2 IRQ POLL
> (stmmac-1:02)
> [ 473.959734] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 3 IRQ POLL
> (stmmac-1:03)
>
> The resolution moved the register_netdev() function call to the end of
> stmmac_dvr_probe() after stmmac_mdio_register().
>
> Suggested-by: Florian Fainelli <f.fainelli@gmail.com>
> Signed-off-by: Kweh, Hock Leong <hock.leong.kweh@intel.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* [PATCH] net: stmmac: synchronize stmmac_open and stmmac_dvr_probe
From: Kweh, Hock Leong @ 2016-12-27 11:44 UTC (permalink / raw)
To: David S. Miller, Joao Pinto, Giuseppe CAVALLARO,
seraphin.bonnaffe
Cc: Alexandre TORGUE, Joachim Eastwood, Niklas Cassel, Johan Hovold,
pavel, Kweh, Hock Leong, Ong Boon Leong, netdev, LKML,
weifeng.voon, Lars Persson
From: "Kweh, Hock Leong" <hock.leong.kweh@intel.com>
If kernel module stmmac driver being loaded after OS booted, there is a
race condition between stmmac_open() and stmmac_mdio_register(), which is
invoked inside stmmac_dvr_probe(), and the error is showed in dmesg log as
PHY not found and stmmac_open() failed:
[ 473.919358] stmmaceth 0000:01:00.0 (unnamed net_device) (uninitialized):
stmmac_dvr_probe: warning: cannot get CSR clock
[ 473.919382] stmmaceth 0000:01:00.0: no reset control found
[ 473.919412] stmmac - user ID: 0x10, Synopsys ID: 0x42
[ 473.919429] stmmaceth 0000:01:00.0: DMA HW capability register supported
[ 473.919436] stmmaceth 0000:01:00.0: RX Checksum Offload Engine supported
[ 473.919443] stmmaceth 0000:01:00.0: TX Checksum insertion supported
[ 473.919451] stmmaceth 0000:01:00.0 (unnamed net_device) (uninitialized):
Enable RX Mitigation via HW Watchdog Timer
[ 473.921395] libphy: PHY stmmac-1:00 not found
[ 473.921417] stmmaceth 0000:01:00.0 eth0: Could not attach to PHY
[ 473.921427] stmmaceth 0000:01:00.0 eth0: stmmac_open: Cannot attach to
PHY (error: -19)
[ 473.959710] libphy: stmmac: probed
[ 473.959724] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 0 IRQ POLL
(stmmac-1:00) active
[ 473.959728] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 1 IRQ POLL
(stmmac-1:01)
[ 473.959731] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 2 IRQ POLL
(stmmac-1:02)
[ 473.959734] stmmaceth 0000:01:00.0 eth0: PHY ID 01410cc2 at 3 IRQ POLL
(stmmac-1:03)
The resolution used wait_for_completion_interruptible() to synchronize
stmmac_open() and stmmac_dvr_probe() to prevent the race condition
happening.
Signed-off-by: Kweh, Hock Leong <hock.leong.kweh@intel.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 10 ++++++++++
2 files changed, 11 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index eab04ae..5daf8a5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -131,6 +131,7 @@ struct stmmac_priv {
u32 rx_tail_addr;
u32 tx_tail_addr;
u32 mss;
+ struct completion probe_done;
#ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index bb40382..28e85f6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1770,6 +1770,14 @@ static int stmmac_open(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
int ret;
+ ret = wait_for_completion_interruptible(&priv->probe_done);
+ if (ret) {
+ netdev_err(priv->dev,
+ "%s: Interrupted while waiting probe completion\n",
+ __func__);
+ return ret;
+ }
+
stmmac_check_ether_addr(priv);
if (priv->hw->pcs != STMMAC_PCS_RGMII &&
@@ -3226,6 +3234,7 @@ int stmmac_dvr_probe(struct device *device,
priv = netdev_priv(ndev);
priv->device = device;
priv->dev = ndev;
+ init_completion(&priv->probe_done);
stmmac_set_ethtool_ops(ndev);
priv->pause = pause;
@@ -3372,6 +3381,7 @@ int stmmac_dvr_probe(struct device *device,
}
}
+ complete_all(&priv->probe_done);
return 0;
error_mdio_register:
--
1.7.9.5
^ permalink raw reply related
* Platform init code in stmmac_main
From: Joao Pinto @ 2016-12-27 11:47 UTC (permalink / raw)
To: pavel@ucw.cz, Niklas Cassel, Giuseppe CAVALLARO, Florian Fainelli,
netdev
Hello,
I spotted in stmmac_main.c, *_dvr_probe() function, some clocks initializations
that are related with platform based setups:
priv->pclk = devm_clk_get(priv->device, "pclk");
if (IS_ERR(priv->pclk)) {
if (PTR_ERR(priv->pclk) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto error_pclk_get;
}
priv->pclk = NULL;
}
clk_prepare_enable(priv->pclk);
priv->stmmac_rst = devm_reset_control_get(priv->device,
STMMAC_RESOURCE_NAME);
if (IS_ERR(priv->stmmac_rst)) {
if (PTR_ERR(priv->stmmac_rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto error_hw_init;
}
dev_info(priv->device, "no reset control found\n");
priv->stmmac_rst = NULL;
}
if (priv->stmmac_rst)
reset_control_deassert(priv->stmmac_rst);
I am using PCI based setup, so these initializations are executed since they are
in common space in stmmac_main.c. Wouldn't be better to map these clocks in
stmmac_platform? This hasn't any problem for me, but I think it would improve
code readbility.
I would like to have your opinion about the subject!
Thanks,
Joao
^ permalink raw reply
* [PATCH] net: stmmac: fix incorrect bit set in gmac4 mdio addr register
From: Kweh, Hock Leong @ 2016-12-27 20:07 UTC (permalink / raw)
To: David S. Miller, Joao Pinto, Giuseppe CAVALLARO,
seraphin.bonnaffe, f.fainelli
Cc: Alexandre TORGUE, Joachim Eastwood, Niklas Cassel, Johan Hovold,
pavel, Ong Boon Leong, Kweh, Hock Leong, weifeng.voon,
lars.persson, netdev, LKML
From: "Kweh, Hock Leong" <hock.leong.kweh@intel.com>
Fixing the gmac4 mdio write access to use MII_GMAC4_WRITE only instead of
OR together with MII_WRITE.
Signed-off-by: Kweh, Hock Leong <hock.leong.kweh@intel.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index fda01f7..b0344c2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -116,7 +116,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
- u32 value = MII_WRITE | MII_BUSY;
+ u32 value = MII_BUSY;
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -126,6 +126,8 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
& priv->hw->mii.clk_csr_mask;
if (priv->plat->has_gmac4)
value |= MII_GMAC4_WRITE;
+ else
+ value |= MII_WRITE;
/* Wait until any existing MII operation is complete */
if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH] net: stmmac: fix incorrect bit set in gmac4 mdio addr register
From: Joao Pinto @ 2016-12-27 12:11 UTC (permalink / raw)
To: Kweh, Hock Leong, David S. Miller, Joao Pinto, Giuseppe CAVALLARO,
seraphin.bonnaffe, f.fainelli
Cc: Alexandre TORGUE, Joachim Eastwood, Niklas Cassel, Johan Hovold,
pavel, Ong Boon Leong, weifeng.voon, lars.persson, netdev, LKML
In-Reply-To: <1482869261-23803-1-git-send-email-hock.leong.kweh@intel.com>
Às 8:07 PM de 12/27/2016, Kweh, Hock Leong escreveu:
> From: "Kweh, Hock Leong" <hock.leong.kweh@intel.com>
>
> Fixing the gmac4 mdio write access to use MII_GMAC4_WRITE only instead of
> OR together with MII_WRITE.
>
> Signed-off-by: Kweh, Hock Leong <hock.leong.kweh@intel.com>
> ---
> drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> index fda01f7..b0344c2 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
> @@ -116,7 +116,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
> unsigned int mii_address = priv->hw->mii.addr;
> unsigned int mii_data = priv->hw->mii.data;
>
> - u32 value = MII_WRITE | MII_BUSY;
> + u32 value = MII_BUSY;
>
> value |= (phyaddr << priv->hw->mii.addr_shift)
> & priv->hw->mii.addr_mask;
> @@ -126,6 +126,8 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
> & priv->hw->mii.clk_csr_mask;
> if (priv->plat->has_gmac4)
> value |= MII_GMAC4_WRITE;
> + else
> + value |= MII_WRITE;
>
> /* Wait until any existing MII operation is complete */
> if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
>
Acked-By: Joao Pinto <jpinto@synopsys.com>
^ permalink raw reply
* [PATCH 01/12] Make and configuration files.
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
Patches to create the make and configuration files.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
drivers/net/ethernet/aquantia/atlantic/Kconfig | 9 ++++++
drivers/net/ethernet/aquantia/atlantic/Makefile | 40 +++++++++++++++++++++++++
drivers/net/ethernet/aquantia/atlantic/ver.h | 18 +++++++++++
3 files changed, 67 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/Kconfig
create mode 100644 drivers/net/ethernet/aquantia/atlantic/Makefile
create mode 100644 drivers/net/ethernet/aquantia/atlantic/ver.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/Kconfig b/drivers/net/ethernet/aquantia/atlantic/Kconfig
new file mode 100644
index 0000000..33f1eb6
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/Kconfig
@@ -0,0 +1,9 @@
+#
+# Aquantia device configuration
+#
+
+config AQTION
+ tristate "Aquantia AQtion Support"
+ depends on PCI
+ ---help---
+ This enables the support for the Aquantia AQtion Ethernet card.
\ No newline at end of file
diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile
new file mode 100644
index 0000000..f0d961f
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/Makefile
@@ -0,0 +1,40 @@
+TARGET:=atlantic
+
+CC = gcc
+
+ifeq "$(CC)" "gcc"
+ ccflags-y := -Wall
+endif
+
+ifneq ($(KERNELRELEASE),)
+ $(TARGET)-objs:=aq_main.o aq_nic.o aq_pci_func.o aq_nic.o aq_vec.o \
+ aq_ring.o aq_hw_utils.o aq_ethtool.o hw_atl/hw_atl_a0.o \
+ hw_atl/hw_atl_utils.o hw_atl/hw_atl_llh.o
+
+ obj-m:=$(TARGET).o
+else
+ ifndef KDIR
+ BUILD_DIR:=/lib/modules/$(shell uname -r)/build
+ else
+ BUILD_DIR:=$(KDIR)
+ endif
+
+ PWD:=$(shell pwd)
+
+all:
+ $(MAKE) -j4 CC=$(CC) -C $(BUILD_DIR) M=$(PWD) modules
+
+dox: .doxygen
+ @doxygen $<
+
+clean:
+ $(MAKE) -j4 -C $(BUILD_DIR) M=$(PWD) clean
+ @-rm -rdf doc/html 2 > /dev/null
+
+load:
+ insmod ./$(TARGET).ko
+
+unload:
+ rmmod ./$(TARGET).ko
+
+endif
diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h b/drivers/net/ethernet/aquantia/atlantic/ver.h
new file mode 100644
index 0000000..225f561
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -0,0 +1,18 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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.
+ */
+
+#ifndef VER_H
+#define VER_H
+
+#define NIC_MAJOR_DRIVER_VERSION 1
+#define NIC_MINOR_DRIVER_VERSION 4
+#define NIC_BUILD_DRIVER_VERSION 1671
+#define NIC_REVISION_DRIVER_VERSION 0
+
+#endif /* VER_H */
--
2.7.4
^ permalink raw reply related
* [PATCH 07/12] Vector operations
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <726fb213b0f282fc4a6b997721c3022551783fe6.1482844668.git.vomlehn@texas.net>
Add functions to manululate the vector of receive and transmit rings.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
drivers/net/ethernet/aquantia/atlantic/aq_vec.c | 375 ++++++++++++++++++++++++
drivers/net/ethernet/aquantia/atlantic/aq_vec.h | 40 +++
2 files changed, 415 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_vec.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_vec.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
new file mode 100644
index 0000000..c8340d7
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
@@ -0,0 +1,375 @@
+//err_exit:
+//err_exit:
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_vec.c: Definition of common structure for vector of Rx and Tx rings.
+ * Definition of functions for Rx and Tx rings. Friendly module for aq_nic.
+ */
+
+#include "aq_vec.h"
+#include "aq_nic.h"
+#include "aq_ring.h"
+#include "aq_hw.h"
+
+#include <linux/netdevice.h>
+
+struct aq_vec_s {
+ AQ_OBJ_HEADER;
+ struct aq_hw_ops *aq_hw_ops;
+ struct aq_hw_s *aq_hw;
+ struct aq_nic_s *aq_nic;
+ unsigned int tx_rings;
+ unsigned int rx_rings;
+ struct aq_ring_param_s aq_ring_param;
+ struct napi_struct napi;
+ struct aq_ring_s ring[AQ_CFG_TCS_MAX][2];
+};
+
+#define AQ_VEC_TX_ID 0
+#define AQ_VEC_RX_ID 1
+
+struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg)
+{
+ struct aq_vec_s *self = NULL;
+ struct aq_ring_s *ring = NULL;
+ unsigned int i = 0U;
+ int err = 0;
+
+ self = kzalloc(sizeof(*self), GFP_KERNEL);
+ if (!self) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+ self->aq_nic = aq_nic;
+ self->aq_ring_param.vec_idx = idx;
+ self->aq_ring_param.cpu =
+ idx + aq_nic_cfg->aq_rss.base_cpu_number;
+
+ cpumask_set_cpu(self->aq_ring_param.cpu,
+ &self->aq_ring_param.affinity_mask);
+
+ self->tx_rings = 0;
+ self->rx_rings = 0;
+
+ netif_napi_add(aq_nic_get_ndev(aq_nic), &self->napi,
+ aq_vec_poll, AQ_CFG_NAPI_WEIGHT);
+
+ for (i = 0; i < aq_nic_cfg->tcs; ++i) {
+ unsigned int idx_ring = AQ_NIC_TCVEC2RING(self->nic,
+ self->tx_rings,
+ self->aq_ring_param.vec_idx);
+
+ ring = aq_ring_tx_alloc(&self->ring[i][AQ_VEC_TX_ID], aq_nic,
+ idx_ring, aq_nic_cfg);
+ if (!ring) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+ ++self->tx_rings;
+
+ aq_nic_set_tx_ring(aq_nic, idx_ring, ring);
+
+ ring = aq_ring_rx_alloc(&self->ring[i][AQ_VEC_RX_ID], aq_nic,
+ idx_ring, aq_nic_cfg);
+ if (!ring) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+ ++self->rx_rings;
+ }
+
+err_exit:
+ if (err < 0) {
+ aq_vec_free(self);
+ self = NULL;
+ }
+ return self;
+}
+
+int aq_vec_init(struct aq_vec_s *self, struct aq_hw_ops *aq_hw_ops,
+ struct aq_hw_s *aq_hw)
+{
+ struct aq_ring_s *ring = NULL;
+ unsigned int i = 0U;
+ int err = 0;
+
+ self->aq_hw_ops = aq_hw_ops;
+ self->aq_hw = aq_hw;
+
+ spin_lock_init(&self->lock);
+
+ for (i = 0U, ring = self->ring[0];
+ self->tx_rings > i; ++i, ring = self->ring[i]) {
+ err = aq_ring_init(&ring[AQ_VEC_TX_ID]);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops->hw_ring_tx_init(self->aq_hw,
+ &ring[AQ_VEC_TX_ID],
+ &self->aq_ring_param);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_ring_init(&ring[AQ_VEC_RX_ID]);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops->hw_ring_rx_init(self->aq_hw,
+ &ring[AQ_VEC_RX_ID],
+ &self->aq_ring_param);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops->hw_ring_rx_fill(self->aq_hw,
+ &ring[AQ_VEC_RX_ID], 0U);
+ if (err < 0)
+ goto err_exit;
+ }
+
+err_exit:
+ return err;
+}
+
+int aq_vec_start(struct aq_vec_s *self)
+{
+ struct aq_ring_s *ring = NULL;
+ unsigned int i = 0U;
+ int err = 0;
+
+ for (i = 0U, ring = self->ring[0];
+ self->tx_rings > i; ++i, ring = self->ring[i]) {
+ err = self->aq_hw_ops->hw_ring_tx_start(self->aq_hw,
+ &ring[AQ_VEC_TX_ID]);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops->hw_ring_rx_start(self->aq_hw,
+ &ring[AQ_VEC_RX_ID]);
+ if (err < 0)
+ goto err_exit;
+ }
+
+ napi_enable(&self->napi);
+
+err_exit:
+ return err;
+}
+
+int aq_vec_stop(struct aq_vec_s *self)
+{
+ struct aq_ring_s *ring = NULL;
+ unsigned int i = 0U;
+ int err = 0;
+
+ for (i = 0U, ring = self->ring[0];
+ self->tx_rings > i; ++i, ring = self->ring[i]) {
+ err = self->aq_hw_ops->hw_ring_tx_stop(self->aq_hw,
+ &ring[AQ_VEC_TX_ID]);
+
+ err = self->aq_hw_ops->hw_ring_rx_stop(self->aq_hw,
+ &ring[AQ_VEC_RX_ID]);
+ }
+
+ napi_disable(&self->napi);
+ return err;
+}
+
+int aq_vec_deinit(struct aq_vec_s *self)
+{
+ struct aq_ring_s *ring = NULL;
+ unsigned int i = 0U;
+ int err = 0;
+
+ for (i = 0U, ring = self->ring[0];
+ self->tx_rings > i; ++i, ring = self->ring[i]) {
+ err = aq_ring_tx_drop(&ring[AQ_VEC_TX_ID]);
+
+ err = aq_ring_deinit(&ring[AQ_VEC_TX_ID]);
+
+ err = aq_ring_rx_drop(&ring[AQ_VEC_RX_ID]);
+
+ err = aq_ring_deinit(&ring[AQ_VEC_RX_ID]);
+ }
+ return err;
+}
+
+void aq_vec_free(struct aq_vec_s *self)
+{
+ struct aq_ring_s *ring = NULL;
+ unsigned int i = 0U;
+
+ if (!self)
+ goto err_exit;
+
+ for (i = 0U, ring = self->ring[0];
+ self->tx_rings > i; ++i, ring = self->ring[i]) {
+ aq_ring_free(&ring[AQ_VEC_TX_ID]);
+ aq_ring_free(&ring[AQ_VEC_RX_ID]);
+ }
+
+ netif_napi_del(&self->napi);
+
+ kfree(self);
+
+err_exit:;
+}
+
+int aq_vec_poll(struct napi_struct *napi, int budget)
+{
+ struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi);
+ struct aq_ring_s *ring = NULL;
+ int work_done = 0;
+ int err = 0;
+ unsigned int i = 0U;
+ unsigned int sw_tail_old = 0U;
+ bool was_tx_cleaned = false;
+ bool is_locked = false;
+
+ if (!self) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+ is_locked = spin_trylock(&self->lock);
+ if (!(is_locked)) {
+ err = -EBUSY;
+ goto err_exit;
+ }
+
+ for (i = 0U, ring = self->ring[0];
+ self->tx_rings > i; ++i, ring = self->ring[i]) {
+ if (self->aq_hw_ops->hw_ring_tx_head_update) {
+ err = self->aq_hw_ops->hw_ring_tx_head_update(self->aq_hw,
+ &ring[AQ_VEC_TX_ID]);
+ if (err < 0)
+ goto err_exit;
+ }
+
+ if (ring[AQ_VEC_TX_ID].sw_head != ring[AQ_VEC_TX_ID].hw_head) {
+ err = aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
+ if (err < 0)
+ goto err_exit;
+ was_tx_cleaned = true;
+ }
+
+ err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw,
+ &ring[AQ_VEC_RX_ID]);
+ if (err < 0)
+ goto err_exit;
+
+ if (ring[AQ_VEC_RX_ID].sw_head != ring[AQ_VEC_RX_ID].hw_head) {
+ err = aq_ring_rx_clean(&ring[AQ_VEC_RX_ID], &work_done,
+ budget - work_done);
+ if (err < 0)
+ goto err_exit;
+
+ sw_tail_old = ring[AQ_VEC_RX_ID].sw_tail;
+
+ err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops->hw_ring_rx_fill(self->aq_hw,
+ &ring[AQ_VEC_RX_ID], sw_tail_old);
+ if (err < 0)
+ goto err_exit;
+ }
+ }
+
+ spin_unlock(&self->lock);
+
+ if (was_tx_cleaned)
+ work_done = budget;
+
+ if (work_done < budget) {
+ napi_complete_done(napi, work_done);
+ self->aq_hw_ops->hw_irq_enable(self->aq_hw,
+ 1U << self->aq_ring_param.vec_idx);
+ }
+
+err_exit:
+ if (is_locked)
+ spin_unlock(&self->lock);
+ return work_done;
+}
+
+irqreturn_t aq_vec_isr(int irq, void *private)
+{
+ struct aq_vec_s *self = (struct aq_vec_s *)private;
+ int err = 0;
+
+ if (!self) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+ napi_schedule(&self->napi);
+
+err_exit:
+ return err >= 0 ? IRQ_HANDLED : IRQ_NONE;
+}
+
+irqreturn_t aq_vec_isr_legacy(int irq, void *private)
+{
+ struct aq_vec_s *self = (struct aq_vec_s *)private;
+ u64 irq_mask = 0U;
+ irqreturn_t err = 0;
+
+ if (!self) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+ err = self->aq_hw_ops->hw_irq_read(self->aq_hw, &irq_mask);
+
+ if (irq_mask) {
+ self->aq_hw_ops->hw_irq_disable(self->aq_hw,
+ 1U << self->aq_ring_param.vec_idx);
+ napi_schedule(&self->napi);
+ } else {
+ self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U);
+ err = IRQ_NONE;
+ }
+
+err_exit:
+ return err >= 0 ? IRQ_HANDLED : IRQ_NONE;
+}
+
+cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self)
+{
+ return &self->aq_ring_param.affinity_mask;
+}
+
+int aq_vec_get_sw_stats(struct aq_vec_s *self, u64 *data, unsigned int *p_count)
+{
+ struct aq_ring_s *ring = NULL;
+ unsigned int count = 0U;
+ unsigned int r = 0U;
+
+ for (r = 0U, ring = self->ring[0];
+ self->tx_rings > r; ++r, ring = self->ring[r]) {
+ data[count] += ring[AQ_VEC_RX_ID].stats.rx_packets;
+ data[++count] += ring[AQ_VEC_TX_ID].stats.tx_packets;
+ data[++count] += ring[AQ_VEC_RX_ID].stats.jumbo_packets;
+ data[++count] += ring[AQ_VEC_RX_ID].stats.lro_packets;
+ data[++count] += ring[AQ_VEC_RX_ID].stats.rx_errors;
+ }
+
+ if (p_count)
+ *p_count = ++count;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.h b/drivers/net/ethernet/aquantia/atlantic/aq_vec.h
new file mode 100644
index 0000000..a37ce8c
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.h
@@ -0,0 +1,40 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_vec.c: Definition of common structures for vector of Rx and Tx rings.
+ * Declaration of functions for Rx and Tx rings.
+ */
+
+#ifndef AQ_VEC_H
+#define AQ_VEC_H
+
+#include "aq_common.h"
+
+#include <linux/irqreturn.h>
+
+struct aq_hw_s;
+struct aq_hw_ops;
+
+int aq_vec_poll(struct napi_struct *napi, int budget);
+irqreturn_t aq_vec_isr(int irq, void *private);
+irqreturn_t aq_vec_isr_legacy(int irq, void *private);
+struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg);
+int aq_vec_init(struct aq_vec_s *self, struct aq_hw_ops *aq_hw_ops,
+ struct aq_hw_s *aq_hw);
+int aq_vec_deinit(struct aq_vec_s *self);
+void aq_vec_free(struct aq_vec_s *self);
+int aq_vec_start(struct aq_vec_s *self);
+int aq_vec_stop(struct aq_vec_s *self);
+cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self);
+int aq_vec_get_sw_stats(struct aq_vec_s *self, u64 *data,
+ unsigned int *p_count);
+
+#endif /* AQ_VEC_H */
--
2.7.4
^ permalink raw reply related
* [PATCH 12/12] Receive side scaling
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <37565094793e5df8b63a1c025d0057382ae70221.1482844668.git.vomlehn@texas.net>
Add definitions that support receive side scaling.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
| 35 +++++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_rss.h
--git a/drivers/net/ethernet/aquantia/atlantic/aq_rss.h b/drivers/net/ethernet/aquantia/atlantic/aq_rss.h
new file mode 100644
index 0000000..181d373
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_rss.h
@@ -0,0 +1,35 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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"
+
+#define HASH_TYPE_IPV4 0x00000100U
+#define HASH_TYPE_TCP_IPV4 0x00000200U
+#define HASH_TYPE_IPV6 0x00000400U
+#define HASH_TYPE_IPV6_EX 0x00000800U
+#define HASH_TYPE_TCP_IPV6 0x00001000U
+#define HASH_TYPE_TCP_IPV6_EX 0x00002000U
+
+struct aq_receive_scale_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 03/12] Add ring spport code
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <67f8be9c3f6a4fede2eefaa4a3c45f9dbaf9b411.1482844668.git.vomlehn@texas.net>
Add code to support the firmware transmit and receive ring buffers.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 383 +++++++++++++++++++++++
drivers/net/ethernet/aquantia/atlantic/aq_ring.h | 150 +++++++++
2 files changed, 533 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ring.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ring.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
new file mode 100644
index 0000000..bec5fcc
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -0,0 +1,383 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_ring.c: Definition of functions for Rx/Tx rings.
+ */
+
+#include "aq_ring.h"
+#include "aq_nic.h"
+#include "aq_hw.h"
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ struct aq_nic_cfg_s *aq_nic_cfg)
+{
+ int err = 0;
+
+ if (!self) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+ self->buff_ring = (struct aq_ring_buff_s *)
+ kzalloc(sizeof(struct aq_ring_buff_s) * self->size, GFP_KERNEL);
+
+ if (!self->buff_ring) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+ self->dx_ring = dma_alloc_coherent(aq_nic_get_dev(aq_nic),
+ self->size * self->dx_size,
+ &self->dx_ring_pa, GFP_KERNEL);
+ if (!self->dx_ring) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+err_exit:
+ if (err < 0) {
+ aq_ring_free(self);
+ self = NULL;
+ }
+ return self;
+}
+
+struct aq_ring_s *aq_ring_tx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg)
+{
+ int err = 0;
+
+ if (!self) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+ self->aq_nic = aq_nic;
+ self->idx = idx;
+ self->size = aq_nic_cfg->txds;
+ self->dx_size = aq_nic_cfg->aq_hw_caps->txd_size;
+
+ self = aq_ring_alloc(self, aq_nic, aq_nic_cfg);
+ if (!self) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+err_exit:
+ if (err < 0) {
+ aq_ring_free(self);
+ self = NULL;
+ }
+ return self;
+}
+
+struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg)
+{
+ int err = 0;
+
+ if (!self) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+ self->aq_nic = aq_nic;
+ self->idx = idx;
+ self->size = aq_nic_cfg->rxds;
+ self->dx_size = aq_nic_cfg->aq_hw_caps->rxd_size;
+
+ self = aq_ring_alloc(self, aq_nic, aq_nic_cfg);
+ if (!self) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+err_exit:
+ if (err < 0) {
+ aq_ring_free(self);
+ self = NULL;
+ }
+ return self;
+}
+
+int aq_ring_init(struct aq_ring_s *self)
+{
+ self->hw_head = 0;
+ self->sw_head = 0;
+ self->sw_tail = 0;
+ return 0;
+}
+
+int aq_ring_deinit(struct aq_ring_s *self)
+{
+ return 0;
+}
+
+void aq_ring_free(struct aq_ring_s *self)
+{
+ if (!self)
+ goto err_exit;
+
+ kfree(self->buff_ring);
+
+ if (self->dx_ring)
+ dma_free_coherent(aq_nic_get_dev(self->aq_nic),
+ self->size * self->dx_size, self->dx_ring,
+ self->dx_ring_pa);
+
+err_exit:;
+}
+
+void aq_ring_tx_append_buffs(struct aq_ring_s *self,
+ struct aq_ring_buff_s *buffer,
+ unsigned int buffers)
+{
+ if (likely(self->sw_tail + buffers < self->size))
+ memcpy(&self->buff_ring[self->sw_tail], buffer,
+ sizeof(buffer[0]) * buffers);
+ else {
+ unsigned int first_part = self->size - self->sw_tail;
+ unsigned int second_part = buffers - first_part;
+
+ memcpy(&self->buff_ring[self->sw_tail], buffer,
+ sizeof(buffer[0]) * first_part);
+
+ memcpy(&self->buff_ring[0], &buffer[first_part],
+ sizeof(buffer[0]) * second_part);
+ }
+}
+
+int aq_ring_tx_clean(struct aq_ring_s *self)
+{
+ struct device *dev = aq_nic_get_dev(self->aq_nic);
+ struct net_device *ndev = aq_nic_get_ndev(self->aq_nic);
+
+ for (; self->sw_head != self->hw_head;
+ self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
+ struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+
+ ++self->stats.tx_packets;
+ ++ndev->stats.tx_packets;
+ ndev->stats.tx_bytes += buff->len;
+
+ if (likely(buff->is_mapped)) {
+ if (unlikely(buff->is_sop))
+ dma_unmap_single(dev, buff->pa, buff->len,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_page(dev, buff->pa, buff->len,
+ DMA_TO_DEVICE);
+ }
+
+ if (unlikely(buff->is_eop))
+ dev_kfree_skb_any(buff->skb);
+ }
+
+ if (aq_ring_avail_dx(self) > AQ_CFG_SKB_FRAGS_MAX)
+ aq_nic_ndev_queue_start(self->aq_nic, self->idx);
+
+ return 0;
+}
+
+static inline unsigned int aq_ring_dx_in_range(unsigned int h, unsigned int i,
+ unsigned int t)
+{
+ return (h < t) ? ((h < i) && (i < t)) : ((h < i) || (i < t));
+}
+
+int aq_ring_rx_clean(struct aq_ring_s *self, int *work_done, int budget)
+{
+ struct net_device *ndev = aq_nic_get_ndev(self->aq_nic);
+ int err = 0;
+ bool is_rsc_completed = true;
+
+ for (; (self->sw_head != self->hw_head) && budget;
+ self->sw_head = aq_ring_next_dx(self, self->sw_head),
+ --budget, ++(*work_done)) {
+ struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+ struct sk_buff *skb = NULL;
+ unsigned int next_ = 0U;
+ unsigned int i = 0U;
+ struct aq_ring_buff_s *buff_ = NULL;
+
+ if (buff->is_error) {
+ __free_pages(buff->page, 0);
+ continue;
+ }
+
+ if (buff->is_cleaned)
+ continue;
+
+ ++self->stats.rx_packets;
+ ++ndev->stats.rx_packets;
+ ndev->stats.rx_bytes += buff->len;
+
+ if (!buff->is_eop) {
+ for (next_ = buff->next,
+ buff_ = &self->buff_ring[next_]; true;
+ next_ = buff_->next,
+ buff_ = &self->buff_ring[next_]) {
+ if (unlikely(!aq_ring_dx_in_range(self->sw_head,
+ next_,
+ self->hw_head))) {
+ is_rsc_completed = false;
+ break;
+ }
+
+ if (buff_->is_eop)
+ break;
+ }
+
+ if (!(is_rsc_completed)) {
+ err = 0;
+ goto err_exit;
+ }
+ }
+
+ skb = netdev_alloc_skb(ndev, ETH_HLEN + AQ_CFG_IP_ALIGN);
+
+ skb_reserve(skb, AQ_CFG_IP_ALIGN);
+ skb_put(skb, ETH_HLEN);
+ memcpy(skb->data, page_address(buff->page), ETH_HLEN);
+
+ skb_add_rx_frag(skb, 0, buff->page, ETH_HLEN,
+ buff->len - ETH_HLEN,
+ SKB_TRUESIZE(buff->len - ETH_HLEN));
+
+ if (!buff->is_eop) {
+ for (i = 1U, next_ = buff->next,
+ buff_ = &self->buff_ring[next_]; true;
+ next_ = buff_->next,
+ buff_ = &self->buff_ring[next_], ++i) {
+ skb_add_rx_frag(skb, i, buff_->page, 0,
+ buff_->len,
+ SKB_TRUESIZE(buff_->len));
+
+ buff_->is_cleaned = 1;
+
+ if (buff_->is_eop)
+ break;
+ }
+ }
+
+ skb->dev = ndev;
+
+ skb->protocol = eth_type_trans(skb, ndev);
+
+ if (unlikely(buff->is_cso_err)) {
+ __skb_mark_checksum_bad(skb);
+ ++self->stats.rx_errors;
+ } else {
+ if (buff->is_ip_cso) {
+ __skb_incr_checksum_unnecessary(skb);
+ if (buff->is_udp_cso || buff->is_tcp_cso)
+ __skb_incr_checksum_unnecessary(skb);
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ }
+
+ skb->hash = buff->rss_hash;
+ skb->l4_hash = buff->is_hash_l4;
+
+ skb_set_hash(skb, buff->rss_hash,
+ buff->is_hash_l4 ? PKT_HASH_TYPE_L4 :
+ PKT_HASH_TYPE_NONE);
+ skb_record_rx_queue(skb, self->idx);
+
+ netif_receive_skb(skb);
+ }
+
+err_exit:
+ return err;
+}
+
+int aq_ring_tx_drop(struct aq_ring_s *self)
+{
+ for (; self->sw_head != self->sw_tail;
+ self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
+ struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+ struct device *ndev = aq_nic_get_dev(self->aq_nic);
+
+ if (likely(buff->is_mapped)) {
+ if (unlikely(buff->is_sop))
+ dma_unmap_single(ndev, buff->pa, buff->len,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_page(ndev, buff->pa, buff->len,
+ DMA_TO_DEVICE);
+ }
+
+ if (unlikely(buff->is_eop))
+ dev_kfree_skb_any(buff->skb);
+ }
+
+ return 0;
+}
+
+int aq_ring_rx_drop(struct aq_ring_s *self)
+{
+ for (; self->sw_head != self->sw_tail;
+ self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
+ struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+
+ dma_unmap_page(aq_nic_get_dev(self->aq_nic), buff->pa,
+ AQ_CFG_RX_FRAME_MAX, DMA_FROM_DEVICE);
+
+ __free_pages(buff->page, 0);
+ }
+
+ return 0;
+}
+
+int aq_ring_rx_fill(struct aq_ring_s *self)
+{
+ struct aq_ring_buff_s *buff = NULL;
+ int err = 0;
+ int i = 0;
+
+ for (i = aq_ring_avail_dx(self); i--;
+ self->sw_tail = aq_ring_next_dx(self, self->sw_tail)) {
+ buff = &self->buff_ring[self->sw_tail];
+
+ buff->flags = 0U;
+ buff->len = AQ_CFG_RX_FRAME_MAX;
+
+ buff->page = alloc_pages(GFP_ATOMIC | __GFP_COLD |
+ __GFP_COMP, 0);
+ if (!buff->page) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+ buff->pa = dma_map_page(aq_nic_get_dev(self->aq_nic),
+ buff->page, 0,
+ AQ_CFG_RX_FRAME_MAX, DMA_FROM_DEVICE);
+
+ err = dma_mapping_error(aq_nic_get_dev(self->aq_nic), buff->pa);
+ if (err < 0)
+ goto err_exit;
+
+ buff = NULL;
+ }
+ if (err < 0)
+ goto err_exit;
+
+err_exit:
+ if (err < 0)
+ if (buff && buff->page)
+ __free_pages(buff->page, 0);
+
+ return err;
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
new file mode 100644
index 0000000..6a97f21
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
@@ -0,0 +1,150 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_ring.h: Declaration of functions for Rx/Tx rings.
+ */
+
+#ifndef AQ_RING_H
+#define AQ_RING_H
+
+#include "aq_common.h"
+
+struct page;
+
+/*
+ * TxC SOP DX EOP
+ * +----------+----------+----------+-----------
+ * 8bytes|len l3,l4 | pa | pa | pa
+ * +----------+----------+----------+-----------
+ * 4/8bytes|len pkt |len pkt | | skb
+ * +----------+----------+----------+-----------
+ * 4/8bytes|is_txc |len,flags |len |len,is_eop
+ * +----------+----------+----------+-----------
+ *
+ * This aq_ring_buff_s doesn't have endianness dependency.
+ * It is __packed for chache line optimisations.
+ */
+struct __packed aq_ring_buff_s {
+ union {
+ /* RX */
+ struct {
+ u32 rss_hash;
+ u16 next;
+ u8 is_hash_l4;
+ u8 rsvd1;
+ struct page *page;
+ };
+ /* EOP */
+ struct {
+ dma_addr_t pa_eop;
+ struct sk_buff *skb;
+ };
+ /* DX */
+ struct {
+ dma_addr_t pa;
+ };
+ /* SOP */
+ struct {
+ dma_addr_t pa_sop;
+ u32 len_pkt_sop;
+ };
+ /* TxC */
+ struct {
+ u32 mss;
+ u8 len_l2;
+ u8 len_l3;
+ u8 len_l4;
+ u8 rsvd2;
+ u32 len_pkt;
+ };
+ };
+ union {
+ struct {
+ u32 len:16;
+ u32 is_ip_cso:1;
+ u32 is_udp_cso:1;
+ u32 is_tcp_cso:1;
+ u32 is_cso_err:1;
+ u32 is_sop:1;
+ u32 is_eop:1;
+ u32 is_txc:1;
+ u32 is_mapped:1;
+ u32 is_cleaned:1;
+ u32 is_error:1;
+ u32 rsvd3:6;
+ };
+ u32 flags;
+ };
+};
+
+struct aq_ring_stats_s {
+ u64 rx_packets;
+ u64 tx_packets;
+ u64 lro_packets;
+ u64 jumbo_packets;
+ u64 rx_errors;
+};
+
+struct aq_ring_s {
+ AQ_OBJ_HEADER;
+ struct aq_ring_buff_s *buff_ring;
+ u8 *dx_ring; /* descriptors ring, dma shared mem */
+ struct aq_nic_s *aq_nic;
+ unsigned int idx; /* for HW layer registers operations */
+ unsigned int hw_head;
+ unsigned int sw_head;
+ unsigned int sw_tail;
+ unsigned int size; /* descriptors number */
+ unsigned int dx_size; /* TX or RX descriptor size, */
+ /* stored here for fater math */
+ struct aq_ring_stats_s stats;
+ dma_addr_t dx_ring_pa;
+};
+
+struct aq_ring_param_s {
+ unsigned int vec_idx;
+ unsigned int cpu;
+ cpumask_t affinity_mask;
+};
+
+static inline unsigned int aq_ring_next_dx(struct aq_ring_s *self,
+ unsigned int dx)
+{
+ return (++dx >= self->size) ? 0U : dx;
+}
+
+static inline unsigned int aq_ring_avail_dx(struct aq_ring_s *self)
+{
+ return (((self->sw_tail >= self->sw_head)) ?
+ (self->size - 1) - self->sw_tail + self->sw_head :
+ self->sw_head - self->sw_tail - 1);
+}
+
+struct aq_ring_s *aq_ring_tx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg);
+struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg);
+int aq_ring_init(struct aq_ring_s *self);
+int aq_ring_deinit(struct aq_ring_s *self);
+void aq_ring_free(struct aq_ring_s *self);
+void aq_ring_tx_append_buffs(struct aq_ring_s *ring,
+ struct aq_ring_buff_s *buffer,
+ unsigned int buffers);
+int aq_ring_tx_clean(struct aq_ring_s *self);
+int aq_ring_rx_clean(struct aq_ring_s *self, int *work_done, int budget);
+int aq_ring_tx_drop(struct aq_ring_s *self);
+int aq_ring_rx_drop(struct aq_ring_s *self);
+int aq_ring_rx_fill(struct aq_ring_s *self);
+
+#endif /* AQ_RING_H */
--
2.7.4
^ permalink raw reply related
* [PATCH 10/12] Hardware interface and utility functions
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <9936fa643d5f6a8f29b069847d052fcf5dc23513.1482844668.git.vomlehn@texas.net>
Add functions to interface with the hardware and some utility functions.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 170 +++++++++++++++++++++
.../net/ethernet/aquantia/atlantic/aq_hw_utils.c | 70 +++++++++
.../net/ethernet/aquantia/atlantic/aq_hw_utils.h | 54 +++++++
3 files changed, 294 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_hw.h
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
new file mode 100644
index 0000000..15e35b1
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -0,0 +1,170 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_receive_scale_parameters *rss_params);
+
+ int (*hw_rss_hash_set)(struct aq_hw_s *self,
+ struct aq_receive_scale_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/atlantic/aq_hw_utils.c b/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c
new file mode 100644
index 0000000..d340f95
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c
@@ -0,0 +1,70 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_utils_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
+ u32 shft, 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 << shft);
+
+ 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_utils_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/atlantic/aq_hw_utils.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.h
new file mode 100644
index 0000000..7a0eaff
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.h
@@ -0,0 +1,54 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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 MBIT
+#define MBIT ((u64)1000000U)
+#define GBIT ((u64)1000000000U)
+#endif
+
+#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_utils_write_reg_bit(struct aq_hw_s *aq_hw, u32 addr, u32 msk,
+ u32 shft, u32 val);
+u32 aq_hw_utils_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);
+inline 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 11/12] Ethtool support
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <7ef8eca5f4c5cc3d28992d820a7a1d9e92590bb2.1482844668.git.vomlehn@texas.net>
Add the driver interfaces required for support by the ethtool utility.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
.../net/ethernet/aquantia/atlantic/aq_ethtool.c | 254 +++++++++++++++++++++
.../net/ethernet/aquantia/atlantic/aq_ethtool.h | 21 ++
2 files changed, 275 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
new file mode 100644
index 0000000..ab50aa1
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -0,0 +1,254 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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);
+ u32 ret = 0U;
+
+ ret = aq_nic_get_link_speed(aq_nic) ? 1U : 0U;
+ return ret;
+}
+
+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/atlantic/aq_ethtool.h b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h
new file mode 100644
index 0000000..e125390
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h
@@ -0,0 +1,21 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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 08/12] PCI operations
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <61665299e584052d30bd1d623ebd4b138dd90694.1482844668.git.vomlehn@texas.net>
Add functions that handle the PCI bus interface.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
.../net/ethernet/aquantia/atlantic/aq_pci_func.c | 356 +++++++++++++++++++++
.../net/ethernet/aquantia/atlantic/aq_pci_func.h | 36 +++
2 files changed, 392 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_pci_func.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
new file mode 100644
index 0000000..bdd15c8
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -0,0 +1,356 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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/pci.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;
+
+ err = aq_nic_cfg_start(self->port[port]);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic_ndev_init(self->port[port]);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic_ndev_register(self->port[port]);
+ if (err < 0)
+ goto err_exit;
+ }
+
+err_exit:
+ if (err < 0)
+ err = 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;
+
+ err = aq_nic_change_pm_state(self->port[port], pm_msg);
+ }
+
+err_exit:
+ return err;
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.h b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.h
new file mode 100644
index 0000000..7b77fac
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.h
@@ -0,0 +1,36 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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
* [PATCH 01/12] Make and configuration files.
From: David VomLehn @ 2016-12-27 13:15 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
Patches to create the make and configuration files.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
drivers/net/ethernet/aquantia/atlantic/Kconfig | 9 ++++++
drivers/net/ethernet/aquantia/atlantic/Makefile | 40 +++++++++++++++++++++++++
drivers/net/ethernet/aquantia/atlantic/ver.h | 18 +++++++++++
3 files changed, 67 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/Kconfig
create mode 100644 drivers/net/ethernet/aquantia/atlantic/Makefile
create mode 100644 drivers/net/ethernet/aquantia/atlantic/ver.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/Kconfig b/drivers/net/ethernet/aquantia/atlantic/Kconfig
new file mode 100644
index 0000000..33f1eb6
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/Kconfig
@@ -0,0 +1,9 @@
+#
+# Aquantia device configuration
+#
+
+config AQTION
+ tristate "Aquantia AQtion Support"
+ depends on PCI
+ ---help---
+ This enables the support for the Aquantia AQtion Ethernet card.
\ No newline at end of file
diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile
new file mode 100644
index 0000000..f0d961f
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/Makefile
@@ -0,0 +1,40 @@
+TARGET:=atlantic
+
+CC = gcc
+
+ifeq "$(CC)" "gcc"
+ ccflags-y := -Wall
+endif
+
+ifneq ($(KERNELRELEASE),)
+ $(TARGET)-objs:=aq_main.o aq_nic.o aq_pci_func.o aq_nic.o aq_vec.o \
+ aq_ring.o aq_hw_utils.o aq_ethtool.o hw_atl/hw_atl_a0.o \
+ hw_atl/hw_atl_utils.o hw_atl/hw_atl_llh.o
+
+ obj-m:=$(TARGET).o
+else
+ ifndef KDIR
+ BUILD_DIR:=/lib/modules/$(shell uname -r)/build
+ else
+ BUILD_DIR:=$(KDIR)
+ endif
+
+ PWD:=$(shell pwd)
+
+all:
+ $(MAKE) -j4 CC=$(CC) -C $(BUILD_DIR) M=$(PWD) modules
+
+dox: .doxygen
+ @doxygen $<
+
+clean:
+ $(MAKE) -j4 -C $(BUILD_DIR) M=$(PWD) clean
+ @-rm -rdf doc/html 2 > /dev/null
+
+load:
+ insmod ./$(TARGET).ko
+
+unload:
+ rmmod ./$(TARGET).ko
+
+endif
diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h b/drivers/net/ethernet/aquantia/atlantic/ver.h
new file mode 100644
index 0000000..225f561
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -0,0 +1,18 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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.
+ */
+
+#ifndef VER_H
+#define VER_H
+
+#define NIC_MAJOR_DRIVER_VERSION 1
+#define NIC_MINOR_DRIVER_VERSION 4
+#define NIC_BUILD_DRIVER_VERSION 1671
+#define NIC_REVISION_DRIVER_VERSION 0
+
+#endif /* VER_H */
--
2.7.4
^ permalink raw reply related
* [PATCH 02/12] Common functions and definitions
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <9cc1565a3a398b4f70248ca98d12991071142682.1482844668.git.vomlehn@texas.net>
Add files containing the functions and definitions used in common in
different functional areas.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | 83 ++++++++++++++++++++++
drivers/net/ethernet/aquantia/atlantic/aq_common.h | 24 +++++++
drivers/net/ethernet/aquantia/atlantic/aq_utils.h | 55 ++++++++++++++
3 files changed, 162 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_common.h
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_utils.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
new file mode 100644
index 0000000..054bc38
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
@@ -0,0 +1,83 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_cfg.h: Definition of configuration parameters and constants.
+ */
+
+#ifndef AQ_CFG_H
+#define AQ_CFG_H
+
+#define AQ_CFG_VECS_DEF 4U
+#define AQ_CFG_TCS_DEF 1U
+
+#define AQ_CFG_TXDS_DEF 4096U
+#define AQ_CFG_RXDS_DEF 248U
+
+#define AQ_CFG_IS_POLLING_DEF 0U
+
+#define AQ_CFG_FORCE_LEGACY_INT 0U
+
+#define AQ_CFG_IS_INTERRUPT_MODERATION_DEF 1U
+#define AQ_CFG_INTERRUPT_MODERATION_RATE_DEF 0xFFFFU
+#define AQ_CFG_IRQ_MASK 0x1FFU
+
+#define AQ_CFG_VECS_MAX 8U
+#define AQ_CFG_TCS_MAX 8U
+
+#define AQ_CFG_TXDS_MAX (16U * 1024U)
+#define AQ_CFG_RXDS_MAX (16U * 1024U)
+
+#define AQ_CFG_TX_FRAME_MAX (16U * 1024U)
+#define AQ_CFG_RX_FRAME_MAX (4U * 1024U)
+
+/* RSS */
+#define AQ_CFG_RSS_INDIRECTION_TABLE_MAX 128U
+#define AQ_CFG_RSS_HASHKEY_SIZE 320U
+
+#define AQ_CFG_IS_RSS_DEF 1U
+#define AQ_CFG_NUM_RSS_QUEUES_DEF AQ_CFG_VECS_DEF
+#define AQ_CFG_RSS_BASE_CPU_NUM_DEF 0U
+
+#define AQ_CFG_PCI_FUNC_MSIX_IRQS 9U
+#define AQ_CFG_PCI_FUNC_PORTS 2U
+
+#define AQ_CFG_SERVICE_TIMER_INTERVAL (2 * HZ)
+#define AQ_CFG_POLLING_TIMER_INTERVAL ((unsigned int)(2 * HZ))
+
+#define AQ_CFG_SKB_FRAGS_MAX 32U
+#define AQ_CFG_IP_ALIGN 0U
+
+#define AQ_CFG_NAPI_WEIGHT 64U
+
+#define AQ_CFG_MULTICAST_ADDRESS_MAX 32U
+
+//#define AQ_CFG_MAC_ADDR_PERMANENT {0x30, 0x0E, 0xE3, 0x12, 0x34, 0x56}
+
+#define AQ_CFG_FC_MODE 3U
+
+#define AQ_CFG_SPEED_MSK 0xFFFFU /* 0xFFFFU==auto_neg */
+
+#define AQ_CFG_IS_AUTONEG_DEF 1U
+#define AQ_CFG_MTU_DEF 1514U
+
+#define AQ_CFG_LOCK_TRYS 100U
+
+#define TXT(_T_) #_T_
+#define TXTTXT(_T_) TXT(_T_)
+
+#define AQ_CFG_DRV_AUTHOR "Aquantia"
+#define AQ_CFG_DRV_DESC "Aquantia Corporation(R) Network Driver"
+#define AQ_CFG_DRV_NAME "aquantia"
+#define AQ_CFG_DRV_VERSION TXTTXT(NIC_MAJOR_DRIVER_VERSION)"."\
+ TXTTXT(NIC_MINOR_DRIVER_VERSION)"."\
+ TXTTXT(NIC_BUILD_DRIVER_VERSION)"."\
+ TXTTXT(NIC_REVISION_DRIVER_VERSION)
+
+#endif /* AQ_CFG_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
new file mode 100644
index 0000000..f92201d
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -0,0 +1,24 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_common.h: Basic includes for all files in project.
+ */
+
+#ifndef AQ_COMMON_H
+#define AQ_COMMON_H
+
+#include <linux/etherdevice.h>
+
+#include "ver.h"
+#include "aq_nic.h"
+#include "aq_cfg.h"
+#include "aq_utils.h"
+
+#endif /* AQ_COMMON_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_utils.h b/drivers/net/ethernet/aquantia/atlantic/aq_utils.h
new file mode 100644
index 0000000..07b4618
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_utils.h
@@ -0,0 +1,55 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_utils.h: Useful macro and structures used in all layers of driver.
+ */
+
+#ifndef AQ_UTILS_H
+#define AQ_UTILS_H
+
+#include "aq_common.h"
+
+#ifndef MBIT
+#define MBIT ((u64)1000000U)
+#define GBIT ((u64)1000000000U)
+#endif
+
+#define AQ_IRQ_INVALID 0U
+#define AQ_IRQ_LEGACY 1U
+#define AQ_IRQ_MSI 2U
+#define AQ_IRQ_MSIX 3U
+
+#define AQ_DIMOF(_ARY_) ARRAY_SIZE(_ARY_)
+
+#define AQ_OBJ_HEADER spinlock_t lock; atomic_t flags; atomic_t busy_count
+
+struct aq_obj_s {
+ AQ_OBJ_HEADER;
+};
+
+#define AQ_OBJ_TST(_OBJ_, _FLAG_) ((_FLAG_) & atomic_read(&(_OBJ_)->flags))
+
+#define AQ_OBJ_SET(_OBJ_, _F_) \
+{ unsigned long flags_old, flags_new; atomic_t *flags = &(_OBJ_)->flags; \
+do { \
+ flags_old = atomic_read(flags); \
+ flags_new = flags_old | (_F_); \
+} while (atomic_cmpxchg(flags, \
+ flags_old, flags_new) != flags_old); }
+
+#define AQ_OBJ_CLR(_OBJ_, _F_) \
+{ unsigned long flags_old, flags_new; atomic_t *flags = &(_OBJ_)->flags; \
+do { \
+ flags_old = atomic_read(flags); \
+ flags_new = flags_old & ~(_F_); \
+} while (atomic_cmpxchg(flags, \
+ flags_old, flags_new) != flags_old); }
+
+#endif /* AQ_UTILS_H */
--
2.7.4
^ permalink raw reply related
* [PATCH 09/12] Atlantic hardware abstraction layer
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <36c7868a58795880d5f6111e523c0136ace2ca91.1482844668.git.vomlehn@texas.net>
Add common functions for Atlantic hardware abstraction layer.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
.../aquantia/atlantic/hw_atl/hw_atl_utils.c | 545 +++++++++++++++++++++
.../aquantia/atlantic/hw_atl/hw_atl_utils.h | 214 ++++++++
2 files changed, 759 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
new file mode 100644
index 0000000..42ca100
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -0,0 +1,545 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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
+
+int hw_atl_utils_fw_download_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;
+}
+
+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;
+}
+
+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)
+
+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;
+}
+
+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_download_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_download_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((struct aq_hw_s *)self,
+ &PHAL_ATLANTIC_A0->chip_features);
+
+ err = hw_atl_utils_mpi_create((struct aq_hw_s *)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_download_dwords(self,
+ aq_hw_read_reg(self, 0x00000374U) +
+ (40U * 4U),
+ mac_addr,
+ AQ_DIMOF(mac_addr));
+ mac_addr[0] = cpu_to_be32(mac_addr[0]);
+ mac_addr[1] = cpu_to_be32(mac_addr[1]);
+
+ ether_addr_copy(mac, (u8 *)mac_addr);
+
+ if ((mac[0] != 0x00) || (mac[1] != 0x17) || (mac[2] != 0xB6)) {
+ /* 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/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
new file mode 100644
index 0000000..aa5550f
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -0,0 +1,214 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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 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);
+
+int hw_atl_fw_download_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt);
+
+void hw_atl_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt);
+
+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 05/12] Support for NIC-specific code
From: David VomLehn @ 2016-12-27 13:17 UTC (permalink / raw)
To: netdev
Cc: Simon Edelhaus, David VomLehn, Dmitrii Tarakanov,
Alexander Loktionov
In-Reply-To: <206766987286d2c30b7f674dec4aafe1ed70a21b.1482844668.git.vomlehn@texas.net>
Add support for code specific to the Atlantic NIC.
Signed-off-by: Dmitrii Tarakanov <Dmitrii.Tarakanov@aquantia.com>
Signed-off-by: Alexander Loktionov <Alexander.Loktionov@aquantia.com>
Signed-off-by: David M. VomLehn <vomlehn@texas.net>
---
drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 993 +++++++++++++++++++++
drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 111 +++
.../ethernet/aquantia/atlantic/aq_nic_internal.h | 48 +
3 files changed, 1152 insertions(+)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_nic.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_nic.h
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_nic_internal.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
new file mode 100644
index 0000000..bc4c672
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -0,0 +1,993 @@
+//err_exit:
+//err_exit:
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_nic.c: Definition of common code for NIC.
+ */
+
+#include "aq_nic.h"
+#include "aq_vec.h"
+#include "aq_ring.h"
+#include "aq_hw.h"
+#include "aq_pci_func.h"
+#include "aq_rss.h"
+#include "aq_nic_internal.h"
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/timer.h>
+#include <linux/cpu.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/ip.h>
+
+/*
+ * Fills aq_nic_cfg with valid defaults
+ */
+static int aq_nic_cfg_init_defaults(struct aq_nic_s *self)
+{
+ struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
+ int err = 0;
+
+ cfg->aq_hw_caps = &self->aq_hw_caps;
+
+ cfg->vecs = AQ_CFG_VECS_DEF;
+ cfg->tcs = AQ_CFG_TCS_DEF;
+
+ cfg->rxds = AQ_CFG_RXDS_DEF;
+ cfg->txds = AQ_CFG_TXDS_DEF;
+
+ cfg->is_polling = AQ_CFG_IS_POLLING_DEF;
+
+ cfg->is_interrupt_moderation = AQ_CFG_IS_INTERRUPT_MODERATION_DEF;
+ cfg->itr = cfg->is_interrupt_moderation ?
+ AQ_CFG_INTERRUPT_MODERATION_RATE_DEF : 0U;
+
+ cfg->is_rss = AQ_CFG_IS_RSS_DEF;
+ cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF;
+ cfg->aq_rss.base_cpu_number = AQ_CFG_RSS_BASE_CPU_NUM_DEF;
+ cfg->flow_control = AQ_CFG_FC_MODE;
+
+ cfg->mtu = AQ_CFG_MTU_DEF;
+ cfg->link_speed_msk = AQ_CFG_SPEED_MSK;
+ cfg->is_autoneg = AQ_CFG_IS_AUTONEG_DEF;
+
+ cfg->vlan_id = 0U;
+
+ err = aq_nic_rss_init(self, cfg->num_rss_queues);
+ if (err < 0)
+ goto err_exit;
+
+err_exit:
+ return err;
+}
+
+/*
+ * Checks hw_caps and 'corrects' aq_nic_cfg in runtime
+ */
+int aq_nic_cfg_start(struct aq_nic_s *self)
+{
+ struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
+
+ /*descriptors */
+ cfg->rxds = min(cfg->rxds, cfg->aq_hw_caps->rxds);
+ cfg->txds = min(cfg->txds, cfg->aq_hw_caps->txds);
+
+ /*rss rings */
+ cfg->vecs = min(cfg->vecs, cfg->aq_hw_caps->vecs);
+ cfg->vecs = min(cfg->vecs, num_online_cpus());
+
+ cfg->irq_type = aq_pci_func_get_irq_type(self->aq_pci_func);
+
+ if ((cfg->irq_type == AQ_IRQ_LEGACY) ||
+ (self->aq_hw_caps.vecs == 1U) ||
+ (cfg->vecs == 1U)) {
+ cfg->is_rss = 0U;
+ cfg->vecs = 1U;
+ }
+
+ cfg->link_speed_msk &= self->aq_hw_caps.link_speed_msk;
+
+ return 0;
+}
+
+static int aq_nic_cfg_read(struct aq_nic_s *self)
+{
+ return 0;
+}
+
+static int aq_nic_cfg_check(struct aq_nic_s *self)
+{
+ return 0;
+}
+
+int aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues)
+{
+ struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
+ struct aq_receive_scale_parameters *rss_params = &cfg->aq_rss;
+ int i = 0;
+
+ static u8 rss_key[40] = {
+ 0x1e, 0xad, 0x71, 0x87, 0x65, 0xfc, 0x26, 0x7d,
+ 0x0d, 0x45, 0x67, 0x74, 0xcd, 0x06, 0x1a, 0x18,
+ 0xb6, 0xc1, 0xf0, 0xc7, 0xbb, 0x18, 0xbe, 0xf8,
+ 0x19, 0x13, 0x4b, 0xa9, 0xd0, 0x3e, 0xfe, 0x70,
+ 0x25, 0x03, 0xab, 0x50, 0x6a, 0x8b, 0x82, 0x0c
+ };
+
+ rss_params->hash_secret_key_size = sizeof(rss_key);
+ memcpy(rss_params->hash_secret_key, rss_key, sizeof(rss_key));
+ rss_params->indirection_table_size = AQ_CFG_RSS_INDIRECTION_TABLE_MAX;
+
+ for (i = rss_params->indirection_table_size; i--;)
+ rss_params->indirection_table[i] = i & (num_rss_queues - 1);
+ return 0;
+}
+
+static void aq_nic_service_timer_cb(unsigned long param)
+{
+ struct aq_nic_s *self = (struct aq_nic_s *)param;
+ int err = 0;
+ bool is_busy = false;
+ struct aq_hw_link_status_s link_status;
+
+ atomic_inc(&self->busy_count);
+ is_busy = true;
+ if (AQ_OBJ_TST(self, AQ_NIC_FLAGS_IS_NOT_READY)) {
+ err = -EFAULT;
+ goto err_exit;
+ }
+ err = self->aq_hw_ops.hw_get_link_status(self->aq_hw, &link_status);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw,
+ self->aq_nic_cfg.is_interrupt_moderation);
+
+ if (memcmp(&link_status, &self->link_status, sizeof(link_status))) {
+ if (link_status.bps) {
+ AQ_OBJ_SET(self, AQ_NIC_FLAG_STARTED);
+ AQ_OBJ_CLR(self, AQ_NIC_LINK_DOWN);
+ netif_carrier_on(self->ndev);
+ } else {
+ netif_carrier_off(self->ndev);
+ AQ_OBJ_SET(self, AQ_NIC_LINK_DOWN);
+ }
+
+ self->link_status = link_status;
+ }
+
+err_exit:
+ if (is_busy)
+ atomic_dec(&self->busy_count);
+ mod_timer(&self->service_timer,
+ jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL);
+}
+
+static void aq_nic_polling_timer_cb(unsigned long param)
+{
+ struct aq_nic_s *self = (struct aq_nic_s *)param;
+ struct aq_vec_s *aq_vec = NULL;
+ unsigned int i = 0U;
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
+ aq_vec_isr(i, (void *)aq_vec);
+
+ mod_timer(&self->polling_timer, jiffies +
+ AQ_CFG_POLLING_TIMER_INTERVAL);
+}
+
+struct aq_nic_s *aq_nic_alloc_cold(const struct net_device_ops *ndev_ops,
+ const struct ethtool_ops *et_ops,
+ struct device *dev,
+ struct aq_pci_func_s *aq_pci_func,
+ unsigned int port,
+ const struct aq_hw_ops *aq_hw_ops)
+{
+ struct net_device *ndev = NULL;
+ struct aq_nic_s *self = NULL;
+ int err = 0;
+
+ ndev = aq_nic_ndev_alloc();
+ self = (struct aq_nic_s *)netdev_priv(ndev);
+ if (!self) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+
+ ndev->netdev_ops = ndev_ops;
+ ndev->ethtool_ops = et_ops;
+
+ SET_NETDEV_DEV(ndev, dev);
+
+ ndev->if_port = port;
+ self->ndev = ndev;
+
+ self->aq_pci_func = aq_pci_func;
+
+ self->aq_hw_ops = *aq_hw_ops;
+ self->port = (u8)port;
+
+ self->aq_hw = self->aq_hw_ops.create(aq_pci_func, self->port,
+ &self->aq_hw_ops);
+ err = self->aq_hw_ops.get_hw_caps(self->aq_hw, &self->aq_hw_caps);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic_cfg_init_defaults(self);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic_cfg_check(self);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic_cfg_read(self);
+
+ if (err >= 0) {
+ err = aq_nic_cfg_check(self);
+ if (err < 0)
+ goto err_exit;
+ }
+
+ if (err < 0) {
+ err = aq_nic_cfg_init_defaults(self);
+ if (err < 0)
+ goto err_exit;
+ }
+
+err_exit:
+ if (err < 0) {
+ aq_nic_free_hot_resources(self);
+ self = NULL;
+ }
+ return self;
+}
+
+int aq_nic_ndev_register(struct aq_nic_s *self)
+{
+ int err = 0;
+ unsigned int i = 0U;
+
+ if (!self->ndev) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+ err = self->aq_hw_ops.hw_get_mac_permanent(self->aq_hw,
+ self->ndev->dev_addr);
+ if (err < 0)
+ goto err_exit;
+
+#if defined(AQ_CFG_MAC_ADDR_PERMANENT)
+ {
+ static u8 mac_addr_permanent[] = AQ_CFG_MAC_ADDR_PERMANENT;
+
+ ether_addr_copy(self->ndev->dev_addr, mac_addr_permanent);
+ }
+#endif
+ err = register_netdev(self->ndev);
+ if (err < 0)
+ goto err_exit;
+
+ self->is_ndev_registered = true;
+ netif_carrier_off(self->ndev);
+
+ for (i = AQ_CFG_VECS_MAX; i--;)
+ aq_nic_ndev_queue_stop(self, i);
+
+err_exit:
+ return err;
+}
+
+struct net_device *aq_nic_ndev_alloc(void)
+{
+ struct net_device *ndev = NULL;
+ int err = 0;
+
+ ndev = alloc_etherdev_mq(sizeof(struct aq_nic_s), AQ_CFG_VECS_MAX);
+ if (!ndev) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+
+err_exit:
+ (void)err;
+ return ndev;
+}
+
+int aq_nic_ndev_init(struct aq_nic_s *self)
+{
+ struct aq_hw_caps_s *aq_hw_caps = self->aq_nic_cfg.aq_hw_caps;
+ struct aq_nic_cfg_s *aq_nic_cfg = &self->aq_nic_cfg;
+
+ self->ndev->features = aq_hw_caps->hw_features;
+ self->ndev->hw_features |= aq_hw_caps->hw_features;
+ self->ndev->priv_flags = aq_hw_caps->hw_priv_flags;
+ self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN;
+
+ return 0;
+}
+
+void aq_nic_ndev_free(struct aq_nic_s *self)
+{
+ int err = 0;
+
+ if (!self->ndev) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+ if (self->is_ndev_registered)
+ unregister_netdev(self->ndev);
+
+ if (self->aq_hw)
+ self->aq_hw_ops.destroy(self->aq_hw);
+
+ free_netdev(self->ndev);
+
+err_exit:;
+ (void)err;
+}
+
+struct aq_nic_s *aq_nic_alloc_hot(struct net_device *ndev)
+{
+ struct aq_nic_s *self = NULL;
+ int err = 0;
+
+ if (!ndev) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+ self = (struct aq_nic_s *)netdev_priv(ndev);
+
+ if (!self) {
+ err = -EINVAL;
+ goto err_exit;
+ }
+ if (netif_running(ndev)) {
+ unsigned int i;
+
+ for (i = AQ_CFG_VECS_MAX; i--;)
+ netif_stop_subqueue(ndev, i);
+ }
+
+ for (self->aq_vecs = 0; self->aq_vecs < self->aq_nic_cfg.vecs;
+ self->aq_vecs++) {
+ self->aq_vec[self->aq_vecs] =
+ aq_vec_alloc(self, self->aq_vecs, &self->aq_nic_cfg);
+ if (!self->aq_vec[self->aq_vecs]) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+ }
+
+err_exit:
+ if (err < 0) {
+ aq_nic_free_hot_resources(self);
+ self = NULL;
+ }
+ return self;
+}
+
+void aq_nic_set_tx_ring(struct aq_nic_s *self, unsigned int idx,
+ struct aq_ring_s *ring)
+{
+ self->aq_ring_tx[idx] = ring;
+}
+
+struct device *aq_nic_get_dev(struct aq_nic_s *self)
+{
+ return self->ndev->dev.parent;
+}
+
+struct net_device *aq_nic_get_ndev(struct aq_nic_s *self)
+{
+ return self->ndev;
+}
+
+int aq_nic_init(struct aq_nic_s *self)
+{
+ struct aq_vec_s *aq_vec = NULL;
+ int err = 0;
+ unsigned int i = 0U;
+
+ self->power_state = AQ_HW_POWER_STATE_D0;
+
+ err = self->aq_hw_ops.hw_reset(self->aq_hw);
+
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops.hw_init(self->aq_hw, &self->aq_nic_cfg,
+ aq_nic_get_ndev(self)->dev_addr);
+ if (err < 0)
+ goto err_exit;
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
+ aq_vec_init(aq_vec, &self->aq_hw_ops, self->aq_hw);
+
+err_exit:
+ return err;
+}
+
+void aq_nic_ndev_queue_start(struct aq_nic_s *self, unsigned int idx)
+{
+ netif_start_subqueue(self->ndev, idx);
+}
+
+void aq_nic_ndev_queue_stop(struct aq_nic_s *self, unsigned int idx)
+{
+ netif_stop_subqueue(self->ndev, idx);
+}
+
+int aq_nic_start(struct aq_nic_s *self)
+{
+ struct aq_vec_s *aq_vec = NULL;
+ int err = 0;
+ unsigned int i = 0U;
+
+ err = self->aq_hw_ops.hw_multicast_list_set(self->aq_hw,
+ self->mc_list.ar,
+ self->mc_list.count);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops.hw_packet_filter_set(self->aq_hw,
+ self->packet_filter);
+ if (err < 0)
+ goto err_exit;
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) {
+ err = aq_vec_start(aq_vec);
+ if (err < 0)
+ goto err_exit;
+ }
+
+ err = self->aq_hw_ops.hw_start(self->aq_hw);
+
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw,
+ self->aq_nic_cfg.is_interrupt_moderation);
+ if (err < 0)
+ goto err_exit;
+ setup_timer(&self->service_timer, &aq_nic_service_timer_cb,
+ (unsigned long)self);
+ mod_timer(&self->service_timer, jiffies +
+ AQ_CFG_SERVICE_TIMER_INTERVAL);
+
+ if (self->aq_nic_cfg.is_polling) {
+ setup_timer(&self->polling_timer, &aq_nic_polling_timer_cb,
+ (unsigned long)self);
+ mod_timer(&self->polling_timer, jiffies +
+ AQ_CFG_POLLING_TIMER_INTERVAL);
+ } else {
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) {
+ err = aq_pci_func_alloc_irq(self->aq_pci_func, i,
+ self->ndev->name, aq_vec,
+ aq_vec_get_affinity_mask(aq_vec));
+ if (err < 0)
+ goto err_exit;
+ }
+
+ err = self->aq_hw_ops.hw_irq_enable(self->aq_hw,
+ AQ_CFG_IRQ_MASK);
+ if (err < 0)
+ goto err_exit;
+ }
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
+ aq_nic_ndev_queue_start(self, i);
+
+ err = netif_set_real_num_tx_queues(self->ndev, self->aq_vecs);
+ if (err < 0)
+ goto err_exit;
+
+ err = netif_set_real_num_rx_queues(self->ndev, self->aq_vecs);
+ if (err < 0)
+ goto err_exit;
+
+err_exit:
+ return err;
+}
+
+static unsigned int aq_nic_map_skb_frag(struct aq_nic_s *self,
+ struct sk_buff *skb,
+ struct aq_ring_buff_s *dx)
+{
+ unsigned int ret = 0U;
+ unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+ unsigned int frag_count = 0U;
+
+ dx->flags = 0U;
+ dx->len = skb_headlen(skb);
+ dx->pa = dma_map_single(aq_nic_get_dev(self), skb->data, dx->len,
+ DMA_TO_DEVICE);
+ dx->len_pkt = skb->len;
+ dx->is_sop = 1U;
+ dx->is_mapped = 1U;
+
+ ++ret;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ dx->is_ip_cso = (htons(ETH_P_IP) == skb->protocol) ? 1U : 0U;
+ dx->is_tcp_cso =
+ (ip_hdr(skb)->protocol == IPPROTO_TCP) ? 1U : 0U;
+ dx->is_udp_cso =
+ (ip_hdr(skb)->protocol == IPPROTO_UDP) ? 1U : 0U;
+ }
+
+ for (; nr_frags--; ++frag_count) {
+ unsigned int frag_len;
+ dma_addr_t frag_pa;
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_count];
+
+ frag_len = skb_frag_size(frag);
+ frag_pa = skb_frag_dma_map(aq_nic_get_dev(self),
+ frag, 0, frag_len, DMA_TO_DEVICE);
+
+ while (frag_len > AQ_CFG_TX_FRAME_MAX) {
+ ++dx;
+ ++ret;
+ dx->flags = 0U;
+ dx->len = AQ_CFG_TX_FRAME_MAX;
+ dx->pa = frag_pa;
+ dx->is_mapped = 1U;
+
+ frag_len -= AQ_CFG_TX_FRAME_MAX;
+ frag_pa += AQ_CFG_TX_FRAME_MAX;
+ }
+
+ ++dx;
+ ++ret;
+
+ dx->flags = 0U;
+ dx->len = frag_len;
+ dx->pa = frag_pa;
+ dx->is_mapped = 1U;
+ }
+
+ dx->is_eop = 1U;
+ dx->skb = skb;
+
+ return ret;
+}
+
+static unsigned int aq_nic_map_skb_lso(struct aq_nic_s *self,
+ struct sk_buff *skb,
+ struct aq_ring_buff_s *dx)
+{
+ unsigned int ret = 0U;
+
+ dx->flags = 0U;
+ dx->len_pkt = skb->len;
+ dx->len_l2 = ETH_HLEN;
+ dx->len_l3 = ip_hdrlen(skb);
+ dx->len_l4 = tcp_hdrlen(skb);
+ dx->mss = skb_shinfo(skb)->gso_size;
+ dx->is_txc = 1U;
+ ret = 1U;
+
+ return ret;
+}
+
+static unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb,
+ struct aq_ring_buff_s *dx)
+{
+ unsigned int ret = 0U;
+
+ if (unlikely(skb_is_gso(skb))) {
+ ret = aq_nic_map_skb_lso(self, skb, dx);
+ ++dx;
+ }
+
+ ret += aq_nic_map_skb_frag(self, skb, dx);
+
+ return ret;
+}
+
+int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb)
+{
+ struct aq_ring_s *ring = NULL;
+ unsigned int frags = 0U;
+ unsigned int vec = skb->queue_mapping % self->aq_nic_cfg.vecs;
+ unsigned int tc = 0U;
+ int err = 0;
+ bool is_nic_in_bad_state;
+ bool is_locked = false;
+ bool is_busy = false;
+ struct aq_ring_buff_s buffers[AQ_CFG_SKB_FRAGS_MAX];
+
+ frags = skb_shinfo(skb)->nr_frags + 1;
+
+ ring = self->aq_ring_tx[AQ_NIC_TCVEC2RING(self, tc, vec)];
+
+ atomic_inc(&self->busy_count);
+ is_busy = true;
+
+ if (frags > AQ_CFG_SKB_FRAGS_MAX) {
+ dev_kfree_skb_any(skb);
+ goto err_exit;
+ }
+
+ is_nic_in_bad_state = AQ_OBJ_TST(self, AQ_NIC_FLAGS_IS_NOT_TX_READY) ||
+ (aq_ring_avail_dx(ring) < AQ_CFG_SKB_FRAGS_MAX);
+
+ if (is_nic_in_bad_state) {
+ aq_nic_ndev_queue_stop(self, ring->idx);
+ err = NETDEV_TX_BUSY;
+ goto err_exit;
+ }
+
+ {
+ unsigned int trys = AQ_CFG_LOCK_TRYS;
+
+ frags = aq_nic_map_skb(self, skb, &buffers[0]);
+
+ do {
+ is_locked = spin_trylock(&ring->lock);
+ } while (--trys && !is_locked);
+ if (!(is_locked)) {
+ err = NETDEV_TX_BUSY;
+ goto err_exit;
+ }
+
+ aq_ring_tx_append_buffs(ring, &buffers[0], frags);
+
+ err = self->aq_hw_ops.hw_ring_tx_xmit(self->aq_hw, ring, frags);
+ if (err < 0)
+ goto err_exit;
+ }
+
+ if (aq_ring_avail_dx(ring) < AQ_CFG_SKB_FRAGS_MAX + 1)
+ aq_nic_ndev_queue_stop(self, ring->idx);
+
+ spin_unlock(&ring->lock);
+
+ atomic_dec(&self->busy_count);
+
+err_exit:
+ if (err < 0) {
+ if (is_busy)
+ atomic_dec(&self->busy_count);
+
+ if (is_locked)
+ spin_unlock(&ring->lock);
+ }
+ return err;
+}
+
+int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags)
+{
+ int err = 0;
+
+ err = self->aq_hw_ops.hw_packet_filter_set(self->aq_hw, flags);
+ if (err < 0)
+ goto err_exit;
+
+ self->packet_filter = flags;
+
+err_exit:
+ return err;
+}
+
+int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
+{
+ struct netdev_hw_addr *ha = NULL;
+ unsigned int i = 0U;
+ int err = 0;
+
+ self->mc_list.count = 0U;
+
+ netdev_for_each_mc_addr(ha, ndev) {
+ ether_addr_copy(self->mc_list.ar[i++], ha->addr);
+ ++self->mc_list.count;
+ }
+
+ err = self->aq_hw_ops.hw_multicast_list_set(self->aq_hw,
+ self->mc_list.ar,
+ self->mc_list.count);
+ if (err < 0)
+ goto err_exit;
+
+err_exit:
+ return err;
+}
+
+int aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu)
+{
+ int err = 0;
+
+ if (new_mtu > self->aq_hw_caps.mtu) {
+ err = 0;
+ goto err_exit;
+ }
+ self->aq_nic_cfg.mtu = new_mtu;
+
+err_exit:
+ return err;
+}
+
+int aq_nic_set_mac(struct aq_nic_s *self, struct net_device *ndev)
+{
+ return self->aq_hw_ops.hw_set_mac_address(self->aq_hw, ndev->dev_addr);
+}
+
+unsigned int aq_nic_get_link_speed(struct aq_nic_s *self)
+{
+ return self->link_status.bps / 1000000;
+}
+
+int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p)
+{
+ u32 *regs_buff = p;
+ int err = 0;
+ struct aq_hw_caps_s caps;
+
+ regs->version = 1;
+
+ err = self->aq_hw_ops.get_hw_caps(self->aq_hw, &caps);
+ if (err < 0)
+ goto err_exit;
+
+ err = self->aq_hw_ops.hw_get_regs(self->aq_hw, &caps, regs_buff);
+ if (err < 0)
+ goto err_exit;
+
+err_exit:
+ return err;
+}
+
+int aq_nic_get_regs_count(struct aq_nic_s *self)
+{
+ return self->aq_hw_caps.mac_regs_count;
+}
+
+void aq_nic_get_stats(struct aq_nic_s *self, u64 *data)
+{
+ struct aq_vec_s *aq_vec = NULL;
+ unsigned int i = 0U;
+ unsigned int count = 0U;
+ int err = 0;
+
+ err = self->aq_hw_ops.hw_get_hw_stats(self->aq_hw, data, &count);
+ if (err < 0)
+ goto err_exit;
+
+ data += count;
+ count = 0U;
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) {
+ data += count;
+ aq_vec_get_sw_stats(aq_vec, data, &count);
+ }
+
+err_exit:;
+ (void)err;
+}
+
+void aq_nic_get_link_settings(struct aq_nic_s *self, struct ethtool_cmd *cmd)
+{
+ int err = 0;
+ struct aq_hw_caps_s caps;
+
+ cmd->autoneg = self->aq_nic_cfg.is_autoneg;
+
+ err = self->aq_hw_ops.get_hw_caps(self->aq_hw, &caps);
+ if (err < 0)
+ goto err_exit;
+
+ cmd->supported |= (caps.link_speed_msk & AQ_NIC_RATE_10G) ?
+ ADVERTISED_10000baseT_Full : 0U;
+ cmd->supported |= (caps.link_speed_msk & AQ_NIC_RATE_1G) ?
+ ADVERTISED_1000baseT_Full : 0U;
+ cmd->supported |= (caps.link_speed_msk & AQ_NIC_RATE_100M) ?
+ ADVERTISED_100baseT_Full : 0U;
+ cmd->supported |= caps.flow_control ? SUPPORTED_Pause : 0;
+ cmd->supported |= SUPPORTED_Autoneg;
+
+ cmd->advertising = (self->aq_nic_cfg.is_autoneg) ?
+ ADVERTISED_Autoneg : 0U;
+ cmd->advertising |=
+ (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10G) ?
+ ADVERTISED_10000baseT_Full : 0U;
+ cmd->advertising |=
+ (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G) ?
+ ADVERTISED_1000baseT_Full : 0U;
+
+ cmd->advertising |=
+ (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M) ?
+ ADVERTISED_100baseT_Full : 0U;
+ cmd->advertising |= (self->aq_nic_cfg.flow_control) ?
+ ADVERTISED_Pause : 0U;
+
+err_exit:;
+ (void)err;
+}
+
+int aq_nic_set_link_settings(struct aq_nic_s *self, struct ethtool_cmd *cmd)
+{
+ u32 speed = 0U;
+ u32 rate = 0U;
+ int err = 0;
+ struct aq_hw_caps_s caps;
+
+ err = self->aq_hw_ops.get_hw_caps(self->aq_hw, &caps);
+ if (err < 0)
+ goto err_exit;
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ rate = caps.link_speed_msk;
+ self->aq_nic_cfg.is_autoneg = true;
+ } else {
+ speed = ethtool_cmd_speed(cmd);
+
+ switch (speed) {
+ case SPEED_100:
+ rate = AQ_NIC_RATE_100M;
+ break;
+
+ case SPEED_1000:
+ rate = AQ_NIC_RATE_1G;
+ break;
+
+ case SPEED_2500:
+ rate = AQ_NIC_RATE_2GS;
+ break;
+
+ case SPEED_5000:
+ rate = AQ_NIC_RATE_5G;
+ break;
+
+ case SPEED_10000:
+ rate = AQ_NIC_RATE_10G;
+ break;
+
+ default:
+ err = -1;
+ goto err_exit;
+ break;
+ }
+ if (!(caps.link_speed_msk & rate)) {
+ err = -1;
+ goto err_exit;
+ }
+
+ self->aq_nic_cfg.is_autoneg = false;
+ }
+
+ err = self->aq_hw_ops.hw_set_link_speed(self->aq_hw, rate);
+ if (err < 0)
+ goto err_exit;
+
+ self->aq_nic_cfg.link_speed_msk = rate;
+
+err_exit:
+ return err;
+}
+
+struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self)
+{
+ return &self->aq_nic_cfg;
+}
+
+u32 aq_nic_get_fw_version(struct aq_nic_s *self)
+{
+ u32 fw_version = 0U;
+
+ self->aq_hw_ops.hw_get_fw_version(self->aq_hw, &fw_version);
+
+ return fw_version;
+}
+
+int aq_nic_stop(struct aq_nic_s *self)
+{
+ struct aq_vec_s *aq_vec = NULL;
+ int err = 0;
+ unsigned int i = 0U;
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
+ aq_nic_ndev_queue_stop(self, i);
+
+ del_timer_sync(&self->service_timer);
+
+ err = self->aq_hw_ops.hw_irq_disable(self->aq_hw, AQ_CFG_IRQ_MASK);
+
+ if (self->aq_nic_cfg.is_polling)
+ del_timer_sync(&self->polling_timer);
+ else
+ aq_pci_func_free_irqs(self->aq_pci_func);
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
+ aq_vec_stop(aq_vec);
+
+ err = self->aq_hw_ops.hw_stop(self->aq_hw);
+
+ return err;
+}
+
+int aq_nic_deinit(struct aq_nic_s *self)
+{
+ struct aq_vec_s *aq_vec = NULL;
+ int err = 0;
+ unsigned int i = 0U;
+
+ for (i = 0U, aq_vec = self->aq_vec[0];
+ self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
+ aq_vec_deinit(aq_vec);
+
+ if (self->power_state == AQ_HW_POWER_STATE_D0)
+ err = self->aq_hw_ops.hw_deinit(self->aq_hw);
+ else
+ err = self->aq_hw_ops.hw_set_power(self->aq_hw,
+ self->power_state);
+
+ return err;
+}
+
+void aq_nic_free_hot_resources(struct aq_nic_s *self)
+{
+ unsigned int i = 0U;
+
+ if (!self)
+ goto err_exit;
+
+ for (i = AQ_DIMOF(self->aq_vec); i--;)
+ if (self->aq_vec[i])
+ aq_vec_free(self->aq_vec[i]);
+
+err_exit:;
+}
+
+int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg)
+{
+ int err = 0;
+
+ if (!(netif_running(self->ndev))) {
+ err = 0;
+ goto err_exit;
+ }
+ if (pm_msg->event & PM_EVENT_SLEEP || pm_msg->event & PM_EVENT_FREEZE) {
+ self->power_state = AQ_HW_POWER_STATE_D3;
+ netif_device_detach(self->ndev);
+ netif_tx_stop_all_queues(self->ndev);
+
+ err = aq_nic_stop(self);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic_deinit(self);
+ if (err < 0)
+ goto err_exit;
+ } else {
+ err = aq_nic_init(self);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic_start(self);
+ if (err < 0)
+ goto err_exit;
+
+ netif_device_attach(self->ndev);
+ netif_tx_start_all_queues(self->ndev);
+ }
+
+err_exit:
+ return err;
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
new file mode 100644
index 0000000..89958e7
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -0,0 +1,111 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_nic.c: Declaration of common code for NIC.
+ */
+
+#ifndef AQ_NIC_H
+#define AQ_NIC_H
+
+#include "aq_common.h"
+#include "aq_rss.h"
+
+struct aq_ring_s;
+struct aq_pci_func_s;
+struct aq_hw_ops;
+
+#define AQ_NIC_FC_OFF 0U
+#define AQ_NIC_FC_TX 1U
+#define AQ_NIC_FC_RX 2U
+#define AQ_NIC_FC_FULL 3U
+#define AQ_NIC_FC_AUTO 4U
+
+#define AQ_NIC_RATE_10G BIT(0)
+#define AQ_NIC_RATE_5G BIT(1)
+#define AQ_NIC_RATE_5GSR BIT(2)
+#define AQ_NIC_RATE_2GS BIT(3)
+#define AQ_NIC_RATE_1G BIT(4)
+#define AQ_NIC_RATE_100M BIT(5)
+
+struct aq_nic_cfg_s {
+ struct aq_hw_caps_s *aq_hw_caps;
+ u64 hw_features;
+ u32 rxds; /* rx ring size, descriptors # */
+ u32 txds; /* tx ring size, descriptors # */
+ u32 vecs; /* vecs==allocated irqs */
+ u32 irq_type;
+ u32 itr;
+ u32 num_rss_queues;
+ u32 mtu;
+ u32 ucp_0x364;
+ u32 flow_control;
+ u32 link_speed_msk;
+ u32 vlan_id;
+ u16 is_mc_list_enabled;
+ u16 mc_list_count;
+ bool is_autoneg;
+ bool is_interrupt_moderation;
+ bool is_polling;
+ bool is_rss;
+ u8 tcs;
+ struct aq_receive_scale_parameters aq_rss;
+};
+
+#define AQ_NIC_FLAG_STARTED 0x00000004U
+#define AQ_NIC_FLAG_STOPPING 0x00000008U
+#define AQ_NIC_FLAG_RESETTING 0x00000010U
+#define AQ_NIC_FLAG_CLOSING 0x00000020U
+#define AQ_NIC_LINK_DOWN 0x04000000U
+#define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U
+#define AQ_NIC_FLAG_ERR_HW 0x80000000U
+
+#define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
+ ((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
+
+struct aq_nic_s *aq_nic_alloc_cold(const struct net_device_ops *ndev_ops,
+ const struct ethtool_ops *et_ops,
+ struct device *dev,
+ struct aq_pci_func_s *aq_pci_func,
+ unsigned int port,
+ const struct aq_hw_ops *aq_hw_ops);
+int aq_nic_ndev_init(struct aq_nic_s *self);
+struct aq_nic_s *aq_nic_alloc_hot(struct net_device *ndev);
+void aq_nic_set_tx_ring(struct aq_nic_s *self, unsigned int idx,
+ struct aq_ring_s *ring);
+struct device *aq_nic_get_dev(struct aq_nic_s *self);
+struct net_device *aq_nic_get_ndev(struct aq_nic_s *self);
+int aq_nic_init(struct aq_nic_s *self);
+int aq_nic_cfg_start(struct aq_nic_s *self);
+struct net_device *aq_nic_ndev_alloc(void);
+int aq_nic_ndev_register(struct aq_nic_s *self);
+void aq_nic_ndev_queue_start(struct aq_nic_s *self, unsigned int idx);
+void aq_nic_ndev_queue_stop(struct aq_nic_s *self, unsigned int idx);
+void aq_nic_ndev_free(struct aq_nic_s *self);
+int aq_nic_start(struct aq_nic_s *self);
+int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb);
+int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p);
+int aq_nic_get_regs_count(struct aq_nic_s *self);
+void aq_nic_get_stats(struct aq_nic_s *self, u64 *data);
+int aq_nic_stop(struct aq_nic_s *self);
+int aq_nic_deinit(struct aq_nic_s *self);
+void aq_nic_free_hot_resources(struct aq_nic_s *self);
+int aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues);
+int aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu);
+int aq_nic_set_mac(struct aq_nic_s *self, struct net_device *ndev);
+int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags);
+int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev);
+unsigned int aq_nic_get_link_speed(struct aq_nic_s *self);
+void aq_nic_get_link_settings(struct aq_nic_s *self, struct ethtool_cmd *cmd);
+int aq_nic_set_link_settings(struct aq_nic_s *self, struct ethtool_cmd *cmd);
+struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
+u32 aq_nic_get_fw_version(struct aq_nic_s *self);
+int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
+
+#endif /* AQ_NIC_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic_internal.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic_internal.h
new file mode 100644
index 0000000..6f27816
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic_internal.h
@@ -0,0 +1,48 @@
+/*
+ * Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2016 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_nic_internal.h: Definition of private object structure.
+ */
+
+#ifndef AQ_NIC_INTERNAL_H
+#define AQ_NIC_INTERNAL_H
+
+struct aq_nic_s {
+ AQ_OBJ_HEADER;
+ struct aq_vec_s *aq_vec[AQ_CFG_VECS_MAX];
+ struct aq_ring_s *aq_ring_tx[AQ_CFG_VECS_MAX * AQ_CFG_TCS_MAX];
+ struct aq_hw_s *aq_hw;
+ struct net_device *ndev;
+ struct aq_pci_func_s *aq_pci_func;
+ unsigned int aq_vecs;
+ unsigned int packet_filter;
+ unsigned int power_state;
+ bool is_ndev_registered;
+ u8 port;
+ struct aq_hw_ops aq_hw_ops;
+ struct aq_hw_caps_s aq_hw_caps;
+ struct aq_nic_cfg_s aq_nic_cfg;
+ struct timer_list service_timer;
+ struct timer_list polling_timer;
+ struct aq_hw_link_status_s link_status;
+ struct {
+ u32 count;
+ u8 ar[AQ_CFG_MULTICAST_ADDRESS_MAX][ETH_ALEN];
+ } mc_list;
+};
+
+#define AQ_NIC_FLAGS_IS_NOT_READY (AQ_NIC_FLAG_STOPPING | \
+ AQ_NIC_FLAG_RESETTING | AQ_NIC_FLAG_CLOSING | \
+ AQ_NIC_FLAG_ERR_UNPLUG | AQ_NIC_FLAG_ERR_HW)
+
+#define AQ_NIC_FLAGS_IS_NOT_TX_READY (AQ_NIC_FLAGS_IS_NOT_READY | \
+ AQ_NIC_LINK_DOWN)
+
+#endif /* AQ_NIC_INTERNAL_H */
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox