* Re: [PATCH v2 0/4] Deterministic SPI latency with NXP DSPI driver
From: Mark Brown @ 2019-09-09 10:06 UTC (permalink / raw)
To: Vladimir Oltean
Cc: h.feurstein, mlichvar, richardcochran, andrew, f.fainelli,
linux-spi, netdev
In-Reply-To: <20190905010114.26718-1-olteanv@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 773 bytes --]
On Thu, Sep 05, 2019 at 04:01:10AM +0300, Vladimir Oltean wrote:
> This patchset proposes an interface from the SPI subsystem for
> software timestamping SPI transfers. There is a default implementation
> provided in the core, as well as a mechanism for SPI slave drivers to
> check which byte was in fact timestamped post-facto. The patchset also
> adds the first user of this interface (the NXP DSPI driver in TCFQ mode).
I think this is about as good as we're going to get but we're
very near the merge window now so I'll leave this until after the
merge window is done in case there's more review comments before
applying. I need to reread the implementation code a bit as
well, it looked fine on a first scan through but it's possible I
might spot something later.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* RE: [RFC PATCH 3/3] Enable ptp_kvm for arm64
From: Jianyong Wu (Arm Technology China) @ 2019-09-09 10:17 UTC (permalink / raw)
To: Marc Zyngier
Cc: netdev@vger.kernel.org, pbonzini@redhat.com,
sean.j.christopherson@intel.com, richardcochran@gmail.com,
Mark Rutland, Will Deacon, Suzuki Poulose,
linux-kernel@vger.kernel.org, Steve Capper,
Kaly Xin (Arm Technology China), Justin He (Arm Technology China)
In-Reply-To: <86h85osbzz.wl-maz@kernel.org>
Hi Marc,
> -----Original Message-----
> From: Marc Zyngier <maz@kernel.org>
> Sent: Saturday, September 7, 2019 5:16 PM
> To: Jianyong Wu (Arm Technology China) <Jianyong.Wu@arm.com>
> Cc: netdev@vger.kernel.org; pbonzini@redhat.com;
> sean.j.christopherson@intel.com; richardcochran@gmail.com; Mark Rutland
> <Mark.Rutland@arm.com>; Will Deacon <Will.Deacon@arm.com>; Suzuki
> Poulose <Suzuki.Poulose@arm.com>; linux-kernel@vger.kernel.org; Steve
> Capper <Steve.Capper@arm.com>; Kaly Xin (Arm Technology China)
> <Kaly.Xin@arm.com>; Justin He (Arm Technology China)
> <Justin.He@arm.com>
> Subject: Re: [RFC PATCH 3/3] Enable ptp_kvm for arm64
>
> On Fri, 06 Sep 2019 12:58:15 +0100,
> "Jianyong Wu (Arm Technology China)" <Jianyong.Wu@arm.com> wrote:
> >
> > Hi Marc,
> >
> > Very sorry to have missed this comments.
> >
> > > -----Original Message-----
> > > From: Marc Zyngier <maz@kernel.org>
> > > Sent: Thursday, August 29, 2019 6:33 PM
> > > To: Jianyong Wu (Arm Technology China) <Jianyong.Wu@arm.com>;
> > > netdev@vger.kernel.org; pbonzini@redhat.com;
> > > sean.j.christopherson@intel.com; richardcochran@gmail.com; Mark
> > > Rutland <Mark.Rutland@arm.com>; Will Deacon
> <Will.Deacon@arm.com>;
> > > Suzuki Poulose <Suzuki.Poulose@arm.com>
> > > Cc: linux-kernel@vger.kernel.org; Steve Capper
> > > <Steve.Capper@arm.com>; Kaly Xin (Arm Technology China)
> > > <Kaly.Xin@arm.com>; Justin He (Arm Technology China)
> > > <Justin.He@arm.com>
> > > Subject: Re: [RFC PATCH 3/3] Enable ptp_kvm for arm64
> > >
> > > On 29/08/2019 07:39, Jianyong Wu wrote:
> > > > Currently in arm64 virtualization environment, there is no
> > > > mechanism to keep time sync between guest and host. Time in guest
> > > > will drift compared with host after boot up as they may both use
> > > > third party time sources to correct their time respectively. The
> > > > time deviation will be in order of milliseconds but some scenarios
> > > > ask for higher time precision, like in cloud envirenment, we want
> > > > all the VMs running in the host aquire the same level accuracy from
> host clock.
> > > >
> > > > Use of kvm ptp clock, which choose the host clock source clock as
> > > > a reference clock to sync time clock between guest and host has
> > > > been adopted by x86 which makes the time sync order from
> > > > milliseconds to
> > > nanoseconds.
> > > >
> > > > This patch enable kvm ptp on arm64 and we get the similar clock
> > > > drift as found with x86 with kvm ptp.
> > > >
> > > > Test result comparison between with kvm ptp and without it in
> > > > arm64 are as follows. This test derived from the result of command
> > > > 'chronyc sources'. we should take more cure of the last sample
> > > > column which shows the offset between the local clock and the
> > > > source at the last
> > > measurement.
> > > >
> > > > no kvm ptp in guest:
> > > > MS Name/IP address Stratum Poll Reach LastRx Last sample
> > > >
> > >
> ==========================================================
> > > ==============
> > > > ^* dns1.synet.edu.cn 2 6 377 13 +1040us[+1581us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 21 +1040us[+1581us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 29 +1040us[+1581us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 37 +1040us[+1581us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 45 +1040us[+1581us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 53 +1040us[+1581us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 61 +1040us[+1581us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 4 -130us[ +796us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 12 -130us[ +796us] +/- 21ms
> > > > ^* dns1.synet.edu.cn 2 6 377 20 -130us[ +796us] +/- 21ms
> > > >
> > > > in host:
> > > > MS Name/IP address Stratum Poll Reach LastRx Last sample
> > > >
> > >
> ==========================================================
> > > ==============
> > > > ^* 120.25.115.20 2 7 377 72 -470us[ -603us] +/- 18ms
> > > > ^* 120.25.115.20 2 7 377 92 -470us[ -603us] +/- 18ms
> > > > ^* 120.25.115.20 2 7 377 112 -470us[ -603us] +/- 18ms
> > > > ^* 120.25.115.20 2 7 377 2 +872ns[-6808ns] +/- 17ms
> > > > ^* 120.25.115.20 2 7 377 22 +872ns[-6808ns] +/- 17ms
> > > > ^* 120.25.115.20 2 7 377 43 +872ns[-6808ns] +/- 17ms
> > > > ^* 120.25.115.20 2 7 377 63 +872ns[-6808ns] +/- 17ms
> > > > ^* 120.25.115.20 2 7 377 83 +872ns[-6808ns] +/- 17ms
> > > > ^* 120.25.115.20 2 7 377 103 +872ns[-6808ns] +/- 17ms
> > > > ^* 120.25.115.20 2 7 377 123 +872ns[-6808ns] +/- 17ms
> > > >
> > > > The dns1.synet.edu.cn is the network reference clock for guest and
> > > > 120.25.115.20 is the network reference clock for host. we can't
> > > > get the clock error between guest and host directly, but a roughly
> > > > estimated value will be in order of hundreds of us to ms.
> > > >
> > > > with kvm ptp in guest:
> > > > chrony has been disabled in host to remove the disturb by network
> clock.
> > >
> > > Is that a realistic use case? Why should the host not use NTP?
> > >
> >
> > Not really, NTP will change the the host clock which will contaminate
> > the data of sync between Host and guest. But in reality, we will keep NTP
> online.
> >
> > > >
> > > > MS Name/IP address Stratum Poll Reach LastRx Last sample
> > > >
> > >
> ==========================================================
> > > ==============
> > > > * PHC0 0 3 377 8 -7ns[ +1ns] +/- 3ns
> > > > * PHC0 0 3 377 8 +1ns[ +16ns] +/- 3ns
> > > > * PHC0 0 3 377 6 -4ns[ -0ns] +/- 6ns
> > > > * PHC0 0 3 377 6 -8ns[ -12ns] +/- 5ns
> > > > * PHC0 0 3 377 5 +2ns[ +4ns] +/- 4ns
> > > > * PHC0 0 3 377 13 +2ns[ +4ns] +/- 4ns
> > > > * PHC0 0 3 377 12 -4ns[ -6ns] +/- 4ns
> > > > * PHC0 0 3 377 11 -8ns[ -11ns] +/- 6ns
> > > > * PHC0 0 3 377 10 -14ns[ -20ns] +/- 4ns
> > > > * PHC0 0 3 377 8 +4ns[ +5ns] +/- 4ns
> > > >
> > > > The PHC0 is the ptp clock which choose the host clock as its
> > > > source clock. So we can be sure to say that the clock error
> > > > between host and guest is in order of ns.
> > > >
> > > > Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
> > > > ---
> > > > arch/arm64/include/asm/arch_timer.h | 3 ++
> > > > arch/arm64/kvm/arch_ptp_kvm.c | 76
> > > ++++++++++++++++++++++++++++
> > > > drivers/clocksource/arm_arch_timer.c | 6 ++-
> > > > drivers/ptp/Kconfig | 2 +-
> > > > include/linux/arm-smccc.h | 14 +++++
> > > > virt/kvm/arm/psci.c | 17 +++++++
> > > > 6 files changed, 115 insertions(+), 3 deletions(-) create mode
> > > > 100644 arch/arm64/kvm/arch_ptp_kvm.c
> > >
> > > Please split this patch into two parts: the hypervisor code in a
> > > patch and the guest code in another patch. Having both of them together
> is confusing.
> > >
> > Ok, really better.
> >
> > > >
> > > > diff --git a/arch/arm64/include/asm/arch_timer.h
> > > > b/arch/arm64/include/asm/arch_timer.h
> > > > index 6756178c27db..880576a814b6 100644
> > > > --- a/arch/arm64/include/asm/arch_timer.h
> > > > +++ b/arch/arm64/include/asm/arch_timer.h
> > > > @@ -229,4 +229,7 @@ static inline int arch_timer_arch_init(void)
> > > > return 0;
> > > > }
> > > >
> > > > +extern struct clocksource clocksource_counter; extern u64
> > > > +arch_counter_read(struct clocksource *cs);
> > >
> > > I'm definitely not keen on exposing the internals of the arch_timer
> > > driver to random subsystems. Furthermore, you seem to expect that
> > > the guest kernel will only use the arch timer as a clocksource, and
> > > nothing really guarantees that (in which case
> get_device_system_crosststamp will fail).
> > >
> > The code here is really ugly, I need a better solution to offer a
> > clock source For the guest.
> >
> > > It looks to me that we'd be better off exposing a core timekeeping
> > > API that populates a struct system_counterval_t based on the
> > > *current* timekeeper monotonic clocksource. This would simplify the
> > > split between generic and arch-specific code.
> > >
> > I think it really necessary.
> >
> > > Whether or not tglx will be happy with the idea is another problem,
> > > but I'm certainly not taking any change to the arch timer code based on
> this.
> > >
> > I can have a try, but the detail is not clear for me now.
>
> Something along those lines:
>
> From 5f1c061e55c691d64012bc7c1490a1a8c4432c67 Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <maz@kernel.org>
> Date: Sat, 7 Sep 2019 10:11:49 +0100
> Subject: [PATCH] timekeeping: Expose API allowing retrival of current
> clocksource and counter value
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
> include/linux/timekeeping.h | 5 +++++
> kernel/time/timekeeping.c | 12 ++++++++++++
> 2 files changed, 17 insertions(+)
>
> diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index
> b27e2ffa96c1..6df26a913711 100644
> --- a/include/linux/timekeeping.h
> +++ b/include/linux/timekeeping.h
> @@ -275,6 +275,11 @@ extern int get_device_system_crosststamp(
> struct system_time_snapshot *history,
> struct system_device_crosststamp *xtstamp);
>
> +/*
> + * Obtain current monotonic clock and its counter value */ extern void
> +get_current_counterval(struct system_counterval_t *sc);
> +
> /*
> * Simultaneously snapshot realtime and monotonic raw clocks
> */
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index
> d911c8470149..de689bbd3808 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -1098,6 +1098,18 @@ static bool cycle_between(u64 before, u64 test,
> u64 after)
> return false;
> }
>
> +/**
> + * get_current_counterval - Snapshot the current clocksource and counter
> value
> + * @sc: Pointer to a struct containing the current clocksource and its
> value
> + */
> +void get_current_counterval(struct system_counterval_t *sc) {
> + struct timekeeper *tk = &tk_core.timekeeper;
> +
> + sc->cs = READ_ONCE(tk->tkr_mono.clock);
> + sc->cycles = sc->cs->read(sc->cs);
> +}
> +
> /**
> * get_device_system_crosststamp - Synchronously capture system/device
> timestamp
> * @get_time_fn: Callback to get simultaneous device time and
>
> which should do the right thing.
>
It is a good news for me. These code is indeed what I need!
So what's your plan about this patch? Is there any problem with you if I include these code
into my patch ?
> >
> > > > +
> > > > #endif
> > > > diff --git a/arch/arm64/kvm/arch_ptp_kvm.c
> > > > b/arch/arm64/kvm/arch_ptp_kvm.c
> > >
> > > We don't put non-hypervisor in arch/arm64/kvm. Please move it back
> > > to drivers/ptp (as well as its x86 counterpart), and just link the two parts
> there.
> > > This should also allow this to be enabled for 32bit guests.
> > >
> > Err, sorry, what's mean of "link the two parts there"? should I add
> > another two file update driver/ptp/ Both for arm64 and x86 to contains
> > these arch-specific code or pack them all into ptp_kvm.c?
>
> What I'm suggesting is that you have 3 files:
>
> drivers/ptp/ptp_kvm.c
> drivers/ptp/ptp_kvm_x86.c
> drivers/ptp/ptp_kvm_arm.c
>
> and let the Makefile combine them.
>
> [...]
>
it is what I want to do at the beginning of drafting these patches.
> > > Other questions: how does this works with VM migration? Specially
> > > when moving from a hypervisor that supports the feature to one that
> doesn't?
> > >
> > I think it won't solve the problem generated by VM migration and only
> > for VMs in a single machine. Ptp_kvm only works for VMs in the same
> > machine. But using ptp (not ptp_kvm) clock, all the machines in a low
> > latency network environment can keep time sync in high precision, Then
> > VMs move from one machine to another will obtain a high precision time
> > sync.
>
> That's a problem. Migration must be possible from one host to another, even
> if that means temporarily loosing some (or a lot of) precision. The service
> must be discoverable from userspace on the host so that the MVV can decie
> whether a migration is possible or not.
>
Don't worry, things will be not that bad.
ptp_kvm will not trouble the VM migration. This ptp_kvm is one clocksource of the clock pool for
chrony. Chrony will choose the highest precision clock from the pool. If host does not support
ptp_kvm, the ptp_kvm will not be chosen as the clocksouce of chrony.
We have roughly the same logic of implementation of ptp_kvm with x86, and ptp_kvm works well in x86.
so I think that will be the case for arm64.
Maybe I miss your point, I have no idea of MVV and can't get related info from google.
Also I'm not clear of your last words of how to decide VM migration is possible?
Thanks
Jianyong Wu
> Thanks,
>
> M.
>
> --
> Jazz is not dead, it just smells funny.
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
^ permalink raw reply
* Re: [PATCH] ncsi-netlink: support sending NC-SI commands over Netlink interface
From: Brad Bishop @ 2019-09-09 10:46 UTC (permalink / raw)
To: Ben Wei
Cc: Terry Duncan, sam@mendozajonas.com, davem@davemloft.net,
netdev@vger.kernel.org, openbmc@lists.ozlabs.org,
Justin.Lee1@Dell.com
In-Reply-To: <CH2PR15MB3686CCC22840AD848796D6CAA3BD0@CH2PR15MB3686.namprd15.prod.outlook.com>
>> Do you have plans to upstream your yocto recipe for this repo?
>
> Yes I sure can upstream the recipe file. I had to make local changes to
> build ncsi-netlink for my BMC platform.
> Is there a group I may submit my recipe to?
Hi Ben
Can you try meta-openembedded? If they will not take it, I’m happy to host
a recipe for this in meta-phosphor.
In case you have not submitted a patch to meta-openembedded before... the
correct mailing list is openembedded-devel:
https://www.openembedded.org/wiki/How_to_submit_a_patch_to_OpenEmbedded
thx - brad
^ permalink raw reply
* [PATCH 2/2] NET: m_can: add PCI glue driver
From: Felipe Balbi @ 2019-09-09 10:59 UTC (permalink / raw)
To: Wolfgang Grandegger, Marc Kleine-Budde; +Cc: netdev, davem, Felipe Balbi
In-Reply-To: <20190909105953.36504-1-felipe.balbi@linux.intel.com>
Some intel platforms support an MCAN controller attached to the PCI
bus. This minimal driver adds support for those.
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
---
drivers/net/can/m_can/Kconfig | 7 +
drivers/net/can/m_can/Makefile | 1 +
drivers/net/can/m_can/m_can_pci.c | 222 ++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 drivers/net/can/m_can/m_can_pci.c
diff --git a/drivers/net/can/m_can/Kconfig b/drivers/net/can/m_can/Kconfig
index fba73338bc38..c7fbea72491c 100644
--- a/drivers/net/can/m_can/Kconfig
+++ b/drivers/net/can/m_can/Kconfig
@@ -13,4 +13,11 @@ config CAN_M_CAN_PLATFORM
Say Y here if you want to support Bosch M_CAN controller connected
to the platform bus.
+config CAN_M_CAN_PCI
+ tristate "Generic PCI Bus based M_CAN driver"
+ depends on PCI
+ ---help---
+ Say Y here if you want to support Bosch M_CAN controller connected
+ to the pci bus.
+
endif
diff --git a/drivers/net/can/m_can/Makefile b/drivers/net/can/m_can/Makefile
index ac568be3de98..104de5cb6d79 100644
--- a/drivers/net/can/m_can/Makefile
+++ b/drivers/net/can/m_can/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_CAN_M_CAN) += m_can.o
obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o
+obj-$(CONFIG_CAN_M_CAN_PCI) += m_can_pci.o
diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c
new file mode 100644
index 000000000000..fc6dfc334d34
--- /dev/null
+++ b/drivers/net/can/m_can/m_can_pci.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * m_can_pci.c - PCI Specific M_CAN Glue
+ *
+ * Copyright (C) 2018 Intel Corporation - https://www.intel.com
+ * Author: Felipe Balbi <felipe.balbi@linux.intel.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/can/dev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+
+#include "m_can.h"
+
+#define PCI_DEVICE_ID_INTEL_EHL_1 0x4bc1
+#define PCI_DEVICE_ID_INTEL_EHL_2 0x4bc2
+
+#define M_CAN_PCI_MMIO_BAR 0
+#define M_CAN_MRAM_OFFSET 0x800
+
+#define M_CAN_CLOCK_FREQ_EHL 100000000
+
+static void m_can_init_mram_conf(struct m_can_priv *priv)
+{
+ priv->mcfg[MRAM_SIDF].off = 0;
+ priv->mcfg[MRAM_SIDF].num = 128;
+ priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off +
+ priv->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
+ priv->mcfg[MRAM_XIDF].num = 64;
+ priv->mcfg[MRAM_RXF0].off = priv->mcfg[MRAM_XIDF].off +
+ priv->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
+ priv->mcfg[MRAM_RXF0].num = 64 &
+ (RXFC_FS_MASK >> RXFC_FS_SHIFT);
+ priv->mcfg[MRAM_RXF1].off = priv->mcfg[MRAM_RXF0].off +
+ priv->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
+ priv->mcfg[MRAM_RXF1].num = 0 &
+ (RXFC_FS_MASK >> RXFC_FS_SHIFT);
+ priv->mcfg[MRAM_RXB].off = priv->mcfg[MRAM_RXF1].off +
+ priv->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
+ priv->mcfg[MRAM_RXB].num = 64;
+ priv->mcfg[MRAM_TXE].off = priv->mcfg[MRAM_RXB].off +
+ priv->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
+ priv->mcfg[MRAM_TXE].num = 0;
+ priv->mcfg[MRAM_TXB].off = priv->mcfg[MRAM_TXE].off +
+ priv->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
+ priv->mcfg[MRAM_TXB].num = 16 &
+ (TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT);
+
+ dev_dbg(priv->device,
+ "mram_base %p sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
+ priv->mram_base,
+ priv->mcfg[MRAM_SIDF].off, priv->mcfg[MRAM_SIDF].num,
+ priv->mcfg[MRAM_XIDF].off, priv->mcfg[MRAM_XIDF].num,
+ priv->mcfg[MRAM_RXF0].off, priv->mcfg[MRAM_RXF0].num,
+ priv->mcfg[MRAM_RXF1].off, priv->mcfg[MRAM_RXF1].num,
+ priv->mcfg[MRAM_RXB].off, priv->mcfg[MRAM_RXB].num,
+ priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
+ priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
+
+ m_can_init_ram(priv);
+}
+
+static int m_can_pci_probe(struct pci_dev *pci,
+ const struct pci_device_id *id)
+{
+ struct m_can_priv *priv;
+ struct net_device *net;
+ struct device *dev;
+ void __iomem *base;
+ int ret;
+
+ ret = pcim_enable_device(pci);
+ if (ret)
+ return ret;
+
+ pci_set_master(pci);
+
+ ret = pcim_iomap_regions(pci, BIT(M_CAN_PCI_MMIO_BAR), pci_name(pci));
+ if (ret)
+ return ret;
+
+ dev = &pci->dev;
+
+ base = pcim_iomap_table(pci)[M_CAN_PCI_MMIO_BAR];
+
+ if (!base) {
+ dev_err(dev, "failed to map BARs\n");
+ return -ENOMEM;
+ }
+
+ net = alloc_m_can_dev(1);
+ if (!net)
+ return -ENOMEM;
+
+ ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ return ret;
+
+ priv = netdev_priv(net);
+ net->irq = pci_irq_vector(pci, 0);
+ priv->device = dev;
+ priv->can.clock.freq = id->driver_data;
+ priv->mram_base = base + M_CAN_MRAM_OFFSET;
+
+ pci_set_drvdata(pci, net);
+ SET_NETDEV_DEV(net, dev);
+
+ ret = m_can_dev_setup(dev, net, base);
+ if (ret)
+ goto err;
+
+ ret = register_m_can_dev(net);
+ if (ret)
+ goto err;
+
+ m_can_init_mram_conf(priv);
+ devm_can_led_init(net);
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_put_noidle(dev);
+ pm_runtime_allow(dev);
+
+ return 0;
+
+err:
+ pm_runtime_disable(&pci->dev);
+ pci_free_irq_vectors(pci);
+ return ret;
+}
+
+static void m_can_pci_remove(struct pci_dev *pci)
+{
+ struct net_device *dev = pci_get_drvdata(pci);
+
+ pm_runtime_forbid(&pci->dev);
+ pm_runtime_get_noresume(&pci->dev);
+
+ pci_free_irq_vectors(pci);
+ unregister_m_can_dev(dev);
+ free_m_can_dev(dev);
+}
+
+static __maybe_unused int m_can_pci_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct m_can_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ m_can_stop(ndev);
+ m_can_clk_stop(priv);
+ }
+
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ return 0;
+}
+
+static __maybe_unused int m_can_pci_resume(struct device *dev)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct m_can_priv *priv = netdev_priv(ndev);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(ndev)) {
+ int ret;
+
+ ret = m_can_clk_start(priv);
+ if (ret)
+ return ret;
+
+ m_can_init_ram(priv);
+ m_can_start(ndev);
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops m_can_pci_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(m_can_pci_suspend, m_can_pci_resume)
+};
+
+static const struct pci_device_id m_can_pci_id_table[] = {
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL_1),
+ M_CAN_CLOCK_FREQ_EHL, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL_2),
+ M_CAN_CLOCK_FREQ_EHL, },
+
+ { } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, m_can_pci_id_table);
+
+static struct pci_driver m_can_pci_driver = {
+ .name = "m_can_pci",
+ .probe = m_can_pci_probe,
+ .remove = m_can_pci_remove,
+ .id_table = m_can_pci_id_table,
+ .driver = {
+ .pm = &m_can_pci_pm_ops,
+ }
+};
+
+MODULE_AUTHOR("Felipe Balbi <felipe.balbi@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller on PCI bus");
+
+module_pci_driver(m_can_pci_driver);
--
2.23.0
^ permalink raw reply related
* [PATCH 1/2] NET: m_can: split into core library and platform adaptation
From: Felipe Balbi @ 2019-09-09 10:59 UTC (permalink / raw)
To: Wolfgang Grandegger, Marc Kleine-Budde; +Cc: netdev, davem, Felipe Balbi
A future patch will add PCI-based m_can driver. This patch makes that
a lot simpler.
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
---
drivers/net/can/m_can/Kconfig | 10 +
drivers/net/can/m_can/Makefile | 1 +
drivers/net/can/m_can/m_can.c | 707 ++-----------------------
drivers/net/can/m_can/m_can.h | 420 +++++++++++++++
drivers/net/can/m_can/m_can_platform.c | 306 +++++++++++
5 files changed, 778 insertions(+), 666 deletions(-)
create mode 100644 drivers/net/can/m_can/m_can.h
create mode 100644 drivers/net/can/m_can/m_can_platform.c
diff --git a/drivers/net/can/m_can/Kconfig b/drivers/net/can/m_can/Kconfig
index ec4b2e117f66..fba73338bc38 100644
--- a/drivers/net/can/m_can/Kconfig
+++ b/drivers/net/can/m_can/Kconfig
@@ -4,3 +4,13 @@ config CAN_M_CAN
tristate "Bosch M_CAN devices"
---help---
Say Y here if you want to support for Bosch M_CAN controller.
+
+if CAN_M_CAN
+
+config CAN_M_CAN_PLATFORM
+ tristate "Generic Platform Bus based M_CAN driver"
+ ---help---
+ Say Y here if you want to support Bosch M_CAN controller connected
+ to the platform bus.
+
+endif
diff --git a/drivers/net/can/m_can/Makefile b/drivers/net/can/m_can/Makefile
index 599ae69cb4a1..ac568be3de98 100644
--- a/drivers/net/can/m_can/Makefile
+++ b/drivers/net/can/m_can/Makefile
@@ -4,3 +4,4 @@
#
obj-$(CONFIG_CAN_M_CAN) += m_can.o
+obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index deb274a19ba0..eabd3777908b 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -13,402 +13,19 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
+#include <linux/device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/iopoll.h>
#include <linux/can/dev.h>
-#include <linux/pinctrl/consumer.h>
-
-/* napi related */
-#define M_CAN_NAPI_WEIGHT 64
-
-/* message ram configuration data length */
-#define MRAM_CFG_LEN 8
-
-/* registers definition */
-enum m_can_reg {
- M_CAN_CREL = 0x0,
- M_CAN_ENDN = 0x4,
- M_CAN_CUST = 0x8,
- M_CAN_DBTP = 0xc,
- M_CAN_TEST = 0x10,
- M_CAN_RWD = 0x14,
- M_CAN_CCCR = 0x18,
- M_CAN_NBTP = 0x1c,
- M_CAN_TSCC = 0x20,
- M_CAN_TSCV = 0x24,
- M_CAN_TOCC = 0x28,
- M_CAN_TOCV = 0x2c,
- M_CAN_ECR = 0x40,
- M_CAN_PSR = 0x44,
-/* TDCR Register only available for version >=3.1.x */
- M_CAN_TDCR = 0x48,
- M_CAN_IR = 0x50,
- M_CAN_IE = 0x54,
- M_CAN_ILS = 0x58,
- M_CAN_ILE = 0x5c,
- M_CAN_GFC = 0x80,
- M_CAN_SIDFC = 0x84,
- M_CAN_XIDFC = 0x88,
- M_CAN_XIDAM = 0x90,
- M_CAN_HPMS = 0x94,
- M_CAN_NDAT1 = 0x98,
- M_CAN_NDAT2 = 0x9c,
- M_CAN_RXF0C = 0xa0,
- M_CAN_RXF0S = 0xa4,
- M_CAN_RXF0A = 0xa8,
- M_CAN_RXBC = 0xac,
- M_CAN_RXF1C = 0xb0,
- M_CAN_RXF1S = 0xb4,
- M_CAN_RXF1A = 0xb8,
- M_CAN_RXESC = 0xbc,
- M_CAN_TXBC = 0xc0,
- M_CAN_TXFQS = 0xc4,
- M_CAN_TXESC = 0xc8,
- M_CAN_TXBRP = 0xcc,
- M_CAN_TXBAR = 0xd0,
- M_CAN_TXBCR = 0xd4,
- M_CAN_TXBTO = 0xd8,
- M_CAN_TXBCF = 0xdc,
- M_CAN_TXBTIE = 0xe0,
- M_CAN_TXBCIE = 0xe4,
- M_CAN_TXEFC = 0xf0,
- M_CAN_TXEFS = 0xf4,
- M_CAN_TXEFA = 0xf8,
-};
-
-/* m_can lec values */
-enum m_can_lec_type {
- LEC_NO_ERROR = 0,
- LEC_STUFF_ERROR,
- LEC_FORM_ERROR,
- LEC_ACK_ERROR,
- LEC_BIT1_ERROR,
- LEC_BIT0_ERROR,
- LEC_CRC_ERROR,
- LEC_UNUSED,
-};
-
-enum m_can_mram_cfg {
- MRAM_SIDF = 0,
- MRAM_XIDF,
- MRAM_RXF0,
- MRAM_RXF1,
- MRAM_RXB,
- MRAM_TXE,
- MRAM_TXB,
- MRAM_CFG_NUM,
-};
-
-/* Core Release Register (CREL) */
-#define CREL_REL_SHIFT 28
-#define CREL_REL_MASK (0xF << CREL_REL_SHIFT)
-#define CREL_STEP_SHIFT 24
-#define CREL_STEP_MASK (0xF << CREL_STEP_SHIFT)
-#define CREL_SUBSTEP_SHIFT 20
-#define CREL_SUBSTEP_MASK (0xF << CREL_SUBSTEP_SHIFT)
-
-/* Data Bit Timing & Prescaler Register (DBTP) */
-#define DBTP_TDC BIT(23)
-#define DBTP_DBRP_SHIFT 16
-#define DBTP_DBRP_MASK (0x1f << DBTP_DBRP_SHIFT)
-#define DBTP_DTSEG1_SHIFT 8
-#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT)
-#define DBTP_DTSEG2_SHIFT 4
-#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT)
-#define DBTP_DSJW_SHIFT 0
-#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT)
-
-/* Transmitter Delay Compensation Register (TDCR) */
-#define TDCR_TDCO_SHIFT 8
-#define TDCR_TDCO_MASK (0x7F << TDCR_TDCO_SHIFT)
-#define TDCR_TDCF_SHIFT 0
-#define TDCR_TDCF_MASK (0x7F << TDCR_TDCF_SHIFT)
-
-/* Test Register (TEST) */
-#define TEST_LBCK BIT(4)
-
-/* CC Control Register(CCCR) */
-#define CCCR_CMR_MASK 0x3
-#define CCCR_CMR_SHIFT 10
-#define CCCR_CMR_CANFD 0x1
-#define CCCR_CMR_CANFD_BRS 0x2
-#define CCCR_CMR_CAN 0x3
-#define CCCR_CME_MASK 0x3
-#define CCCR_CME_SHIFT 8
-#define CCCR_CME_CAN 0
-#define CCCR_CME_CANFD 0x1
-#define CCCR_CME_CANFD_BRS 0x2
-#define CCCR_TXP BIT(14)
-#define CCCR_TEST BIT(7)
-#define CCCR_MON BIT(5)
-#define CCCR_CSR BIT(4)
-#define CCCR_CSA BIT(3)
-#define CCCR_ASM BIT(2)
-#define CCCR_CCE BIT(1)
-#define CCCR_INIT BIT(0)
-#define CCCR_CANFD 0x10
-/* for version >=3.1.x */
-#define CCCR_EFBI BIT(13)
-#define CCCR_PXHD BIT(12)
-#define CCCR_BRSE BIT(9)
-#define CCCR_FDOE BIT(8)
-/* only for version >=3.2.x */
-#define CCCR_NISO BIT(15)
-
-/* Nominal Bit Timing & Prescaler Register (NBTP) */
-#define NBTP_NSJW_SHIFT 25
-#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT)
-#define NBTP_NBRP_SHIFT 16
-#define NBTP_NBRP_MASK (0x1ff << NBTP_NBRP_SHIFT)
-#define NBTP_NTSEG1_SHIFT 8
-#define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT)
-#define NBTP_NTSEG2_SHIFT 0
-#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT)
-
-/* Error Counter Register(ECR) */
-#define ECR_RP BIT(15)
-#define ECR_REC_SHIFT 8
-#define ECR_REC_MASK (0x7f << ECR_REC_SHIFT)
-#define ECR_TEC_SHIFT 0
-#define ECR_TEC_MASK 0xff
-
-/* Protocol Status Register(PSR) */
-#define PSR_BO BIT(7)
-#define PSR_EW BIT(6)
-#define PSR_EP BIT(5)
-#define PSR_LEC_MASK 0x7
-
-/* Interrupt Register(IR) */
-#define IR_ALL_INT 0xffffffff
-
-/* Renamed bits for versions > 3.1.x */
-#define IR_ARA BIT(29)
-#define IR_PED BIT(28)
-#define IR_PEA BIT(27)
-
-/* Bits for version 3.0.x */
-#define IR_STE BIT(31)
-#define IR_FOE BIT(30)
-#define IR_ACKE BIT(29)
-#define IR_BE BIT(28)
-#define IR_CRCE BIT(27)
-#define IR_WDI BIT(26)
-#define IR_BO BIT(25)
-#define IR_EW BIT(24)
-#define IR_EP BIT(23)
-#define IR_ELO BIT(22)
-#define IR_BEU BIT(21)
-#define IR_BEC BIT(20)
-#define IR_DRX BIT(19)
-#define IR_TOO BIT(18)
-#define IR_MRAF BIT(17)
-#define IR_TSW BIT(16)
-#define IR_TEFL BIT(15)
-#define IR_TEFF BIT(14)
-#define IR_TEFW BIT(13)
-#define IR_TEFN BIT(12)
-#define IR_TFE BIT(11)
-#define IR_TCF BIT(10)
-#define IR_TC BIT(9)
-#define IR_HPM BIT(8)
-#define IR_RF1L BIT(7)
-#define IR_RF1F BIT(6)
-#define IR_RF1W BIT(5)
-#define IR_RF1N BIT(4)
-#define IR_RF0L BIT(3)
-#define IR_RF0F BIT(2)
-#define IR_RF0W BIT(1)
-#define IR_RF0N BIT(0)
-#define IR_ERR_STATE (IR_BO | IR_EW | IR_EP)
-
-/* Interrupts for version 3.0.x */
-#define IR_ERR_LEC_30X (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
-#define IR_ERR_BUS_30X (IR_ERR_LEC_30X | IR_WDI | IR_ELO | IR_BEU | \
- IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
- IR_RF1L | IR_RF0L)
-#define IR_ERR_ALL_30X (IR_ERR_STATE | IR_ERR_BUS_30X)
-/* Interrupts for version >= 3.1.x */
-#define IR_ERR_LEC_31X (IR_PED | IR_PEA)
-#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_ELO | IR_BEU | \
- IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
- IR_RF1L | IR_RF0L)
-#define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X)
-
-/* Interrupt Line Select (ILS) */
-#define ILS_ALL_INT0 0x0
-#define ILS_ALL_INT1 0xFFFFFFFF
-
-/* Interrupt Line Enable (ILE) */
-#define ILE_EINT1 BIT(1)
-#define ILE_EINT0 BIT(0)
-
-/* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
-#define RXFC_FWM_SHIFT 24
-#define RXFC_FWM_MASK (0x7f << RXFC_FWM_SHIFT)
-#define RXFC_FS_SHIFT 16
-#define RXFC_FS_MASK (0x7f << RXFC_FS_SHIFT)
-
-/* Rx FIFO 0/1 Status (RXF0S/RXF1S) */
-#define RXFS_RFL BIT(25)
-#define RXFS_FF BIT(24)
-#define RXFS_FPI_SHIFT 16
-#define RXFS_FPI_MASK 0x3f0000
-#define RXFS_FGI_SHIFT 8
-#define RXFS_FGI_MASK 0x3f00
-#define RXFS_FFL_MASK 0x7f
-
-/* Rx Buffer / FIFO Element Size Configuration (RXESC) */
-#define M_CAN_RXESC_8BYTES 0x0
-#define M_CAN_RXESC_64BYTES 0x777
-
-/* Tx Buffer Configuration(TXBC) */
-#define TXBC_NDTB_SHIFT 16
-#define TXBC_NDTB_MASK (0x3f << TXBC_NDTB_SHIFT)
-#define TXBC_TFQS_SHIFT 24
-#define TXBC_TFQS_MASK (0x3f << TXBC_TFQS_SHIFT)
-
-/* Tx FIFO/Queue Status (TXFQS) */
-#define TXFQS_TFQF BIT(21)
-#define TXFQS_TFQPI_SHIFT 16
-#define TXFQS_TFQPI_MASK (0x1f << TXFQS_TFQPI_SHIFT)
-#define TXFQS_TFGI_SHIFT 8
-#define TXFQS_TFGI_MASK (0x1f << TXFQS_TFGI_SHIFT)
-#define TXFQS_TFFL_SHIFT 0
-#define TXFQS_TFFL_MASK (0x3f << TXFQS_TFFL_SHIFT)
-
-/* Tx Buffer Element Size Configuration(TXESC) */
-#define TXESC_TBDS_8BYTES 0x0
-#define TXESC_TBDS_64BYTES 0x7
-
-/* Tx Event FIFO Configuration (TXEFC) */
-#define TXEFC_EFS_SHIFT 16
-#define TXEFC_EFS_MASK (0x3f << TXEFC_EFS_SHIFT)
-
-/* Tx Event FIFO Status (TXEFS) */
-#define TXEFS_TEFL BIT(25)
-#define TXEFS_EFF BIT(24)
-#define TXEFS_EFGI_SHIFT 8
-#define TXEFS_EFGI_MASK (0x1f << TXEFS_EFGI_SHIFT)
-#define TXEFS_EFFL_SHIFT 0
-#define TXEFS_EFFL_MASK (0x3f << TXEFS_EFFL_SHIFT)
-
-/* Tx Event FIFO Acknowledge (TXEFA) */
-#define TXEFA_EFAI_SHIFT 0
-#define TXEFA_EFAI_MASK (0x1f << TXEFA_EFAI_SHIFT)
-
-/* Message RAM Configuration (in bytes) */
-#define SIDF_ELEMENT_SIZE 4
-#define XIDF_ELEMENT_SIZE 8
-#define RXF0_ELEMENT_SIZE 72
-#define RXF1_ELEMENT_SIZE 72
-#define RXB_ELEMENT_SIZE 72
-#define TXE_ELEMENT_SIZE 8
-#define TXB_ELEMENT_SIZE 72
-
-/* Message RAM Elements */
-#define M_CAN_FIFO_ID 0x0
-#define M_CAN_FIFO_DLC 0x4
-#define M_CAN_FIFO_DATA(n) (0x8 + ((n) << 2))
-
-/* Rx Buffer Element */
-/* R0 */
-#define RX_BUF_ESI BIT(31)
-#define RX_BUF_XTD BIT(30)
-#define RX_BUF_RTR BIT(29)
-/* R1 */
-#define RX_BUF_ANMF BIT(31)
-#define RX_BUF_FDF BIT(21)
-#define RX_BUF_BRS BIT(20)
-
-/* Tx Buffer Element */
-/* T0 */
-#define TX_BUF_ESI BIT(31)
-#define TX_BUF_XTD BIT(30)
-#define TX_BUF_RTR BIT(29)
-/* T1 */
-#define TX_BUF_EFC BIT(23)
-#define TX_BUF_FDF BIT(21)
-#define TX_BUF_BRS BIT(20)
-#define TX_BUF_MM_SHIFT 24
-#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT)
-
-/* Tx event FIFO Element */
-/* E1 */
-#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT
-#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT)
-
-/* address offset and element number for each FIFO/Buffer in the Message RAM */
-struct mram_cfg {
- u16 off;
- u8 num;
-};
-
-/* m_can private data structure */
-struct m_can_priv {
- struct can_priv can; /* must be the first member */
- struct napi_struct napi;
- struct net_device *dev;
- struct device *device;
- struct clk *hclk;
- struct clk *cclk;
- void __iomem *base;
- u32 irqstatus;
- int version;
-
- /* message ram configuration */
- void __iomem *mram_base;
- struct mram_cfg mcfg[MRAM_CFG_NUM];
-};
-
-static inline u32 m_can_read(const struct m_can_priv *priv, enum m_can_reg reg)
-{
- return readl(priv->base + reg);
-}
-
-static inline void m_can_write(const struct m_can_priv *priv,
- enum m_can_reg reg, u32 val)
-{
- writel(val, priv->base + reg);
-}
-static inline u32 m_can_fifo_read(const struct m_can_priv *priv,
- u32 fgi, unsigned int offset)
-{
- return readl(priv->mram_base + priv->mcfg[MRAM_RXF0].off +
- fgi * RXF0_ELEMENT_SIZE + offset);
-}
+#include "m_can.h"
-static inline void m_can_fifo_write(const struct m_can_priv *priv,
- u32 fpi, unsigned int offset, u32 val)
-{
- writel(val, priv->mram_base + priv->mcfg[MRAM_TXB].off +
- fpi * TXB_ELEMENT_SIZE + offset);
-}
-
-static inline u32 m_can_txe_fifo_read(const struct m_can_priv *priv,
- u32 fgi,
- u32 offset) {
- return readl(priv->mram_base + priv->mcfg[MRAM_TXE].off +
- fgi * TXE_ELEMENT_SIZE + offset);
-}
-
-static inline bool m_can_tx_fifo_full(const struct m_can_priv *priv)
-{
- return !!(m_can_read(priv, M_CAN_TXFQS) & TXFQS_TFQF);
-}
-
-static inline void m_can_config_endisable(const struct m_can_priv *priv,
- bool enable)
+void m_can_config_endisable(const struct m_can_priv *priv, bool enable)
{
u32 cccr = m_can_read(priv, M_CAN_CCCR);
u32 timeout = 10;
@@ -437,17 +54,20 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv,
udelay(1);
}
}
+EXPORT_SYMBOL_GPL(m_can_config_endisable);
-static inline void m_can_enable_all_interrupts(const struct m_can_priv *priv)
+void m_can_enable_all_interrupts(const struct m_can_priv *priv)
{
/* Only interrupt line 0 is used in this driver */
m_can_write(priv, M_CAN_ILE, ILE_EINT0);
}
+EXPORT_SYMBOL_GPL(m_can_enable_all_interrupts);
-static inline void m_can_disable_all_interrupts(const struct m_can_priv *priv)
+void m_can_disable_all_interrupts(const struct m_can_priv *priv)
{
m_can_write(priv, M_CAN_ILE, 0x0);
}
+EXPORT_SYMBOL_GPL(m_can_disable_all_interrupts);
static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
{
@@ -629,7 +249,7 @@ static int __m_can_get_berr_counter(const struct net_device *dev,
return 0;
}
-static int m_can_clk_start(struct m_can_priv *priv)
+int m_can_clk_start(struct m_can_priv *priv)
{
int err;
@@ -641,11 +261,13 @@ static int m_can_clk_start(struct m_can_priv *priv)
return 0;
}
+EXPORT_SYMBOL_GPL(m_can_clk_start);
-static void m_can_clk_stop(struct m_can_priv *priv)
+void m_can_clk_stop(struct m_can_priv *priv)
{
pm_runtime_put_sync(priv->device);
}
+EXPORT_SYMBOL_GPL(m_can_clk_stop);
static int m_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
@@ -1178,7 +800,7 @@ static void m_can_chip_config(struct net_device *dev)
m_can_config_endisable(priv, false);
}
-static void m_can_start(struct net_device *dev)
+void m_can_start(struct net_device *dev)
{
struct m_can_priv *priv = netdev_priv(dev);
@@ -1189,6 +811,7 @@ static void m_can_start(struct net_device *dev)
m_can_enable_all_interrupts(priv);
}
+EXPORT_SYMBOL_GPL(m_can_start);
static int m_can_set_mode(struct net_device *dev, enum can_mode mode)
{
@@ -1263,7 +886,7 @@ static bool m_can_niso_supported(const struct m_can_priv *priv)
return !niso_timeout;
}
-static int m_can_dev_setup(struct platform_device *pdev, struct net_device *dev,
+int m_can_dev_setup(struct device *dev, struct net_device *net,
void __iomem *addr)
{
struct m_can_priv *priv;
@@ -1272,17 +895,17 @@ static int m_can_dev_setup(struct platform_device *pdev, struct net_device *dev,
m_can_version = m_can_check_core_release(addr);
/* return if unsupported version */
if (!m_can_version) {
- dev_err(&pdev->dev, "Unsupported version number: %2d",
+ dev_err(dev, "Unsupported version number: %2d",
m_can_version);
return -EINVAL;
}
- priv = netdev_priv(dev);
- netif_napi_add(dev, &priv->napi, m_can_poll, M_CAN_NAPI_WEIGHT);
+ priv = netdev_priv(net);
+ netif_napi_add(net, &priv->napi, m_can_poll, M_CAN_NAPI_WEIGHT);
/* Shared properties of all M_CAN versions */
priv->version = m_can_version;
- priv->dev = dev;
+ priv->dev = net;
priv->base = addr;
priv->can.do_set_mode = m_can_set_mode;
priv->can.do_get_berr_counter = m_can_get_berr_counter;
@@ -1297,14 +920,14 @@ static int m_can_dev_setup(struct platform_device *pdev, struct net_device *dev,
switch (priv->version) {
case 30:
/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */
- can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
+ can_set_static_ctrlmode(net, CAN_CTRLMODE_FD_NON_ISO);
priv->can.bittiming_const = &m_can_bittiming_const_30X;
priv->can.data_bittiming_const =
&m_can_data_bittiming_const_30X;
break;
case 31:
/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */
- can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
+ can_set_static_ctrlmode(net, CAN_CTRLMODE_FD_NON_ISO);
priv->can.bittiming_const = &m_can_bittiming_const_31X;
priv->can.data_bittiming_const =
&m_can_data_bittiming_const_31X;
@@ -1318,13 +941,14 @@ static int m_can_dev_setup(struct platform_device *pdev, struct net_device *dev,
: 0);
break;
default:
- dev_err(&pdev->dev, "Unsupported version number: %2d",
+ dev_err(dev, "Unsupported version number: %2d",
priv->version);
return -EINVAL;
}
return 0;
}
+EXPORT_SYMBOL_GPL(m_can_dev_setup);
static int m_can_open(struct net_device *dev)
{
@@ -1366,7 +990,7 @@ static int m_can_open(struct net_device *dev)
return err;
}
-static void m_can_stop(struct net_device *dev)
+void m_can_stop(struct net_device *dev)
{
struct m_can_priv *priv = netdev_priv(dev);
@@ -1376,6 +1000,7 @@ static void m_can_stop(struct net_device *dev)
/* set the state as STOPPED */
priv->can.state = CAN_STATE_STOPPED;
}
+EXPORT_SYMBOL_GPL(m_can_stop);
static int m_can_close(struct net_device *dev)
{
@@ -1528,15 +1153,16 @@ static const struct net_device_ops m_can_netdev_ops = {
.ndo_change_mtu = can_change_mtu,
};
-static int register_m_can_dev(struct net_device *dev)
+int register_m_can_dev(struct net_device *dev)
{
dev->flags |= IFF_ECHO; /* we support local echo */
dev->netdev_ops = &m_can_netdev_ops;
return register_candev(dev);
}
+EXPORT_SYMBOL_GPL(register_m_can_dev);
-static void m_can_init_ram(struct m_can_priv *priv)
+void m_can_init_ram(struct m_can_priv *priv)
{
int end, i, start;
@@ -1549,283 +1175,32 @@ static void m_can_init_ram(struct m_can_priv *priv)
for (i = start; i < end; i += 4)
writel(0x0, priv->mram_base + i);
}
+EXPORT_SYMBOL_GPL(m_can_init_ram);
-static void m_can_of_parse_mram(struct m_can_priv *priv,
- const u32 *mram_config_vals)
+void unregister_m_can_dev(struct net_device *dev)
{
- priv->mcfg[MRAM_SIDF].off = mram_config_vals[0];
- priv->mcfg[MRAM_SIDF].num = mram_config_vals[1];
- priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off +
- priv->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
- priv->mcfg[MRAM_XIDF].num = mram_config_vals[2];
- priv->mcfg[MRAM_RXF0].off = priv->mcfg[MRAM_XIDF].off +
- priv->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
- priv->mcfg[MRAM_RXF0].num = mram_config_vals[3] &
- (RXFC_FS_MASK >> RXFC_FS_SHIFT);
- priv->mcfg[MRAM_RXF1].off = priv->mcfg[MRAM_RXF0].off +
- priv->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
- priv->mcfg[MRAM_RXF1].num = mram_config_vals[4] &
- (RXFC_FS_MASK >> RXFC_FS_SHIFT);
- priv->mcfg[MRAM_RXB].off = priv->mcfg[MRAM_RXF1].off +
- priv->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
- priv->mcfg[MRAM_RXB].num = mram_config_vals[5];
- priv->mcfg[MRAM_TXE].off = priv->mcfg[MRAM_RXB].off +
- priv->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
- priv->mcfg[MRAM_TXE].num = mram_config_vals[6];
- priv->mcfg[MRAM_TXB].off = priv->mcfg[MRAM_TXE].off +
- priv->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
- priv->mcfg[MRAM_TXB].num = mram_config_vals[7] &
- (TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT);
-
- dev_dbg(priv->device,
- "mram_base %p sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
- priv->mram_base,
- priv->mcfg[MRAM_SIDF].off, priv->mcfg[MRAM_SIDF].num,
- priv->mcfg[MRAM_XIDF].off, priv->mcfg[MRAM_XIDF].num,
- priv->mcfg[MRAM_RXF0].off, priv->mcfg[MRAM_RXF0].num,
- priv->mcfg[MRAM_RXF1].off, priv->mcfg[MRAM_RXF1].num,
- priv->mcfg[MRAM_RXB].off, priv->mcfg[MRAM_RXB].num,
- priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
- priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
-
- m_can_init_ram(priv);
+ unregister_candev(dev);
}
+EXPORT_SYMBOL_GPL(unregister_m_can_dev);
-static int m_can_plat_probe(struct platform_device *pdev)
+struct net_device *alloc_m_can_dev(u32 tx_fifo_size)
{
- struct net_device *dev;
+ struct net_device *net;
struct m_can_priv *priv;
- struct resource *res;
- void __iomem *addr;
- void __iomem *mram_addr;
- struct clk *hclk, *cclk;
- int irq, ret;
- struct device_node *np;
- u32 mram_config_vals[MRAM_CFG_LEN];
- u32 tx_fifo_size;
-
- np = pdev->dev.of_node;
-
- hclk = devm_clk_get(&pdev->dev, "hclk");
- cclk = devm_clk_get(&pdev->dev, "cclk");
-
- if (IS_ERR(hclk) || IS_ERR(cclk)) {
- dev_err(&pdev->dev, "no clock found\n");
- ret = -ENODEV;
- goto failed_ret;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
- addr = devm_ioremap_resource(&pdev->dev, res);
- irq = platform_get_irq_byname(pdev, "int0");
-
- if (IS_ERR(addr) || irq < 0) {
- ret = -EINVAL;
- goto failed_ret;
- }
-
- /* message ram could be shared */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
- if (!res) {
- ret = -ENODEV;
- goto failed_ret;
- }
-
- mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!mram_addr) {
- ret = -ENOMEM;
- goto failed_ret;
- }
-
- /* get message ram configuration */
- ret = of_property_read_u32_array(np, "bosch,mram-cfg",
- mram_config_vals,
- sizeof(mram_config_vals) / 4);
- if (ret) {
- dev_err(&pdev->dev, "Could not get Message RAM configuration.");
- goto failed_ret;
- }
-
- /* Get TX FIFO size
- * Defines the total amount of echo buffers for loopback
- */
- tx_fifo_size = mram_config_vals[7];
-
- /* allocate the m_can device */
- dev = alloc_candev(sizeof(*priv), tx_fifo_size);
- if (!dev) {
- ret = -ENOMEM;
- goto failed_ret;
- }
-
- priv = netdev_priv(dev);
- dev->irq = irq;
- priv->device = &pdev->dev;
- priv->hclk = hclk;
- priv->cclk = cclk;
- priv->can.clock.freq = clk_get_rate(cclk);
- priv->mram_base = mram_addr;
-
- platform_set_drvdata(pdev, dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- /* Enable clocks. Necessary to read Core Release in order to determine
- * M_CAN version
- */
- pm_runtime_enable(&pdev->dev);
- ret = m_can_clk_start(priv);
- if (ret)
- goto pm_runtime_fail;
-
- ret = m_can_dev_setup(pdev, dev, addr);
- if (ret)
- goto clk_disable;
-
- ret = register_m_can_dev(dev);
- if (ret) {
- dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
- KBUILD_MODNAME, ret);
- goto clk_disable;
- }
-
- m_can_of_parse_mram(priv, mram_config_vals);
-
- devm_can_led_init(dev);
-
- of_can_transceiver(dev);
-
- dev_info(&pdev->dev, "%s device registered (irq=%d, version=%d)\n",
- KBUILD_MODNAME, dev->irq, priv->version);
-
- /* Probe finished
- * Stop clocks. They will be reactivated once the M_CAN device is opened
- */
-clk_disable:
- m_can_clk_stop(priv);
-pm_runtime_fail:
- if (ret) {
- pm_runtime_disable(&pdev->dev);
- free_candev(dev);
- }
-failed_ret:
- return ret;
-}
-
-static __maybe_unused int m_can_suspend(struct device *dev)
-{
- struct net_device *ndev = dev_get_drvdata(dev);
- struct m_can_priv *priv = netdev_priv(ndev);
-
- if (netif_running(ndev)) {
- netif_stop_queue(ndev);
- netif_device_detach(ndev);
- m_can_stop(ndev);
- m_can_clk_stop(priv);
- }
-
- pinctrl_pm_select_sleep_state(dev);
-
- priv->can.state = CAN_STATE_SLEEPING;
-
- return 0;
-}
-
-static __maybe_unused int m_can_resume(struct device *dev)
-{
- struct net_device *ndev = dev_get_drvdata(dev);
- struct m_can_priv *priv = netdev_priv(ndev);
-
- pinctrl_pm_select_default_state(dev);
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
-
- if (netif_running(ndev)) {
- int ret;
+ net = alloc_candev(sizeof(*priv), tx_fifo_size);
+ if (!net)
+ return NULL;
- ret = m_can_clk_start(priv);
- if (ret)
- return ret;
-
- m_can_init_ram(priv);
- m_can_start(ndev);
- netif_device_attach(ndev);
- netif_start_queue(ndev);
- }
-
- return 0;
+ return net;
}
+EXPORT_SYMBOL_GPL(alloc_m_can_dev);
-static void unregister_m_can_dev(struct net_device *dev)
+void free_m_can_dev(struct net_device *dev)
{
- unregister_candev(dev);
-}
-
-static int m_can_plat_remove(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
-
- unregister_m_can_dev(dev);
-
- pm_runtime_disable(&pdev->dev);
-
- platform_set_drvdata(pdev, NULL);
-
free_candev(dev);
-
- return 0;
-}
-
-static int __maybe_unused m_can_runtime_suspend(struct device *dev)
-{
- struct net_device *ndev = dev_get_drvdata(dev);
- struct m_can_priv *priv = netdev_priv(ndev);
-
- clk_disable_unprepare(priv->cclk);
- clk_disable_unprepare(priv->hclk);
-
- return 0;
-}
-
-static int __maybe_unused m_can_runtime_resume(struct device *dev)
-{
- struct net_device *ndev = dev_get_drvdata(dev);
- struct m_can_priv *priv = netdev_priv(ndev);
- int err;
-
- err = clk_prepare_enable(priv->hclk);
- if (err)
- return err;
-
- err = clk_prepare_enable(priv->cclk);
- if (err)
- clk_disable_unprepare(priv->hclk);
-
- return err;
}
-
-static const struct dev_pm_ops m_can_pmops = {
- SET_RUNTIME_PM_OPS(m_can_runtime_suspend,
- m_can_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume)
-};
-
-static const struct of_device_id m_can_of_table[] = {
- { .compatible = "bosch,m_can", .data = NULL },
- { /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, m_can_of_table);
-
-static struct platform_driver m_can_plat_driver = {
- .driver = {
- .name = KBUILD_MODNAME,
- .of_match_table = m_can_of_table,
- .pm = &m_can_pmops,
- },
- .probe = m_can_plat_probe,
- .remove = m_can_plat_remove,
-};
-
-module_platform_driver(m_can_plat_driver);
+EXPORT_SYMBOL_GPL(free_m_can_dev);
MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
new file mode 100644
index 000000000000..e40ff64ac819
--- /dev/null
+++ b/drivers/net/can/m_can/m_can.h
@@ -0,0 +1,420 @@
+/*
+ * CAN bus driver for Bosch M_CAN controller
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Dong Aisheng <b29396@freescale.com>
+ *
+ * Bosch M_CAN user manual can be obtained from:
+ * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/
+ * mcan_users_manual_v302.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __M_CAN_H
+#define __M_CAN_H
+
+#include <linux/can/dev.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+/* napi related */
+#define M_CAN_NAPI_WEIGHT 64
+
+/* message ram configuration data length */
+#define MRAM_CFG_LEN 8
+
+/* registers definition */
+enum m_can_reg {
+ M_CAN_CREL = 0x0,
+ M_CAN_ENDN = 0x4,
+ M_CAN_CUST = 0x8,
+ M_CAN_DBTP = 0xc,
+ M_CAN_TEST = 0x10,
+ M_CAN_RWD = 0x14,
+ M_CAN_CCCR = 0x18,
+ M_CAN_NBTP = 0x1c,
+ M_CAN_TSCC = 0x20,
+ M_CAN_TSCV = 0x24,
+ M_CAN_TOCC = 0x28,
+ M_CAN_TOCV = 0x2c,
+ M_CAN_ECR = 0x40,
+ M_CAN_PSR = 0x44,
+/* TDCR Register only available for version >=3.1.x */
+ M_CAN_TDCR = 0x48,
+ M_CAN_IR = 0x50,
+ M_CAN_IE = 0x54,
+ M_CAN_ILS = 0x58,
+ M_CAN_ILE = 0x5c,
+ M_CAN_GFC = 0x80,
+ M_CAN_SIDFC = 0x84,
+ M_CAN_XIDFC = 0x88,
+ M_CAN_XIDAM = 0x90,
+ M_CAN_HPMS = 0x94,
+ M_CAN_NDAT1 = 0x98,
+ M_CAN_NDAT2 = 0x9c,
+ M_CAN_RXF0C = 0xa0,
+ M_CAN_RXF0S = 0xa4,
+ M_CAN_RXF0A = 0xa8,
+ M_CAN_RXBC = 0xac,
+ M_CAN_RXF1C = 0xb0,
+ M_CAN_RXF1S = 0xb4,
+ M_CAN_RXF1A = 0xb8,
+ M_CAN_RXESC = 0xbc,
+ M_CAN_TXBC = 0xc0,
+ M_CAN_TXFQS = 0xc4,
+ M_CAN_TXESC = 0xc8,
+ M_CAN_TXBRP = 0xcc,
+ M_CAN_TXBAR = 0xd0,
+ M_CAN_TXBCR = 0xd4,
+ M_CAN_TXBTO = 0xd8,
+ M_CAN_TXBCF = 0xdc,
+ M_CAN_TXBTIE = 0xe0,
+ M_CAN_TXBCIE = 0xe4,
+ M_CAN_TXEFC = 0xf0,
+ M_CAN_TXEFS = 0xf4,
+ M_CAN_TXEFA = 0xf8,
+};
+
+/* m_can lec values */
+enum m_can_lec_type {
+ LEC_NO_ERROR = 0,
+ LEC_STUFF_ERROR,
+ LEC_FORM_ERROR,
+ LEC_ACK_ERROR,
+ LEC_BIT1_ERROR,
+ LEC_BIT0_ERROR,
+ LEC_CRC_ERROR,
+ LEC_UNUSED,
+};
+
+enum m_can_mram_cfg {
+ MRAM_SIDF = 0,
+ MRAM_XIDF,
+ MRAM_RXF0,
+ MRAM_RXF1,
+ MRAM_RXB,
+ MRAM_TXE,
+ MRAM_TXB,
+ MRAM_CFG_NUM,
+};
+
+/* Core Release Register (CREL) */
+#define CREL_REL_SHIFT 28
+#define CREL_REL_MASK (0xF << CREL_REL_SHIFT)
+#define CREL_STEP_SHIFT 24
+#define CREL_STEP_MASK (0xF << CREL_STEP_SHIFT)
+#define CREL_SUBSTEP_SHIFT 20
+#define CREL_SUBSTEP_MASK (0xF << CREL_SUBSTEP_SHIFT)
+
+/* Data Bit Timing & Prescaler Register (DBTP) */
+#define DBTP_TDC BIT(23)
+#define DBTP_DBRP_SHIFT 16
+#define DBTP_DBRP_MASK (0x1f << DBTP_DBRP_SHIFT)
+#define DBTP_DTSEG1_SHIFT 8
+#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT)
+#define DBTP_DTSEG2_SHIFT 4
+#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT)
+#define DBTP_DSJW_SHIFT 0
+#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT)
+
+/* Transmitter Delay Compensation Register (TDCR) */
+#define TDCR_TDCO_SHIFT 8
+#define TDCR_TDCO_MASK (0x7F << TDCR_TDCO_SHIFT)
+#define TDCR_TDCF_SHIFT 0
+#define TDCR_TDCF_MASK (0x7F << TDCR_TDCF_SHIFT)
+
+/* Test Register (TEST) */
+#define TEST_LBCK BIT(4)
+
+/* CC Control Register(CCCR) */
+#define CCCR_CMR_MASK 0x3
+#define CCCR_CMR_SHIFT 10
+#define CCCR_CMR_CANFD 0x1
+#define CCCR_CMR_CANFD_BRS 0x2
+#define CCCR_CMR_CAN 0x3
+#define CCCR_CME_MASK 0x3
+#define CCCR_CME_SHIFT 8
+#define CCCR_CME_CAN 0
+#define CCCR_CME_CANFD 0x1
+#define CCCR_CME_CANFD_BRS 0x2
+#define CCCR_TXP BIT(14)
+#define CCCR_TEST BIT(7)
+#define CCCR_MON BIT(5)
+#define CCCR_CSR BIT(4)
+#define CCCR_CSA BIT(3)
+#define CCCR_ASM BIT(2)
+#define CCCR_CCE BIT(1)
+#define CCCR_INIT BIT(0)
+#define CCCR_CANFD 0x10
+/* for version >=3.1.x */
+#define CCCR_EFBI BIT(13)
+#define CCCR_PXHD BIT(12)
+#define CCCR_BRSE BIT(9)
+#define CCCR_FDOE BIT(8)
+/* only for version >=3.2.x */
+#define CCCR_NISO BIT(15)
+
+/* Nominal Bit Timing & Prescaler Register (NBTP) */
+#define NBTP_NSJW_SHIFT 25
+#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT)
+#define NBTP_NBRP_SHIFT 16
+#define NBTP_NBRP_MASK (0x1ff << NBTP_NBRP_SHIFT)
+#define NBTP_NTSEG1_SHIFT 8
+#define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT)
+#define NBTP_NTSEG2_SHIFT 0
+#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT)
+
+/* Error Counter Register(ECR) */
+#define ECR_RP BIT(15)
+#define ECR_REC_SHIFT 8
+#define ECR_REC_MASK (0x7f << ECR_REC_SHIFT)
+#define ECR_TEC_SHIFT 0
+#define ECR_TEC_MASK 0xff
+
+/* Protocol Status Register(PSR) */
+#define PSR_BO BIT(7)
+#define PSR_EW BIT(6)
+#define PSR_EP BIT(5)
+#define PSR_LEC_MASK 0x7
+
+/* Interrupt Register(IR) */
+#define IR_ALL_INT 0xffffffff
+
+/* Renamed bits for versions > 3.1.x */
+#define IR_ARA BIT(29)
+#define IR_PED BIT(28)
+#define IR_PEA BIT(27)
+
+/* Bits for version 3.0.x */
+#define IR_STE BIT(31)
+#define IR_FOE BIT(30)
+#define IR_ACKE BIT(29)
+#define IR_BE BIT(28)
+#define IR_CRCE BIT(27)
+#define IR_WDI BIT(26)
+#define IR_BO BIT(25)
+#define IR_EW BIT(24)
+#define IR_EP BIT(23)
+#define IR_ELO BIT(22)
+#define IR_BEU BIT(21)
+#define IR_BEC BIT(20)
+#define IR_DRX BIT(19)
+#define IR_TOO BIT(18)
+#define IR_MRAF BIT(17)
+#define IR_TSW BIT(16)
+#define IR_TEFL BIT(15)
+#define IR_TEFF BIT(14)
+#define IR_TEFW BIT(13)
+#define IR_TEFN BIT(12)
+#define IR_TFE BIT(11)
+#define IR_TCF BIT(10)
+#define IR_TC BIT(9)
+#define IR_HPM BIT(8)
+#define IR_RF1L BIT(7)
+#define IR_RF1F BIT(6)
+#define IR_RF1W BIT(5)
+#define IR_RF1N BIT(4)
+#define IR_RF0L BIT(3)
+#define IR_RF0F BIT(2)
+#define IR_RF0W BIT(1)
+#define IR_RF0N BIT(0)
+#define IR_ERR_STATE (IR_BO | IR_EW | IR_EP)
+
+/* Interrupts for version 3.0.x */
+#define IR_ERR_LEC_30X (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
+#define IR_ERR_BUS_30X (IR_ERR_LEC_30X | IR_WDI | IR_ELO | IR_BEU | \
+ IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
+ IR_RF1L | IR_RF0L)
+#define IR_ERR_ALL_30X (IR_ERR_STATE | IR_ERR_BUS_30X)
+/* Interrupts for version >= 3.1.x */
+#define IR_ERR_LEC_31X (IR_PED | IR_PEA)
+#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_ELO | IR_BEU | \
+ IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
+ IR_RF1L | IR_RF0L)
+#define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X)
+
+/* Interrupt Line Select (ILS) */
+#define ILS_ALL_INT0 0x0
+#define ILS_ALL_INT1 0xFFFFFFFF
+
+/* Interrupt Line Enable (ILE) */
+#define ILE_EINT1 BIT(1)
+#define ILE_EINT0 BIT(0)
+
+/* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
+#define RXFC_FWM_SHIFT 24
+#define RXFC_FWM_MASK (0x7f << RXFC_FWM_SHIFT)
+#define RXFC_FS_SHIFT 16
+#define RXFC_FS_MASK (0x7f << RXFC_FS_SHIFT)
+
+/* Rx FIFO 0/1 Status (RXF0S/RXF1S) */
+#define RXFS_RFL BIT(25)
+#define RXFS_FF BIT(24)
+#define RXFS_FPI_SHIFT 16
+#define RXFS_FPI_MASK 0x3f0000
+#define RXFS_FGI_SHIFT 8
+#define RXFS_FGI_MASK 0x3f00
+#define RXFS_FFL_MASK 0x7f
+
+/* Rx Buffer / FIFO Element Size Configuration (RXESC) */
+#define M_CAN_RXESC_8BYTES 0x0
+#define M_CAN_RXESC_64BYTES 0x777
+
+/* Tx Buffer Configuration(TXBC) */
+#define TXBC_NDTB_SHIFT 16
+#define TXBC_NDTB_MASK (0x3f << TXBC_NDTB_SHIFT)
+#define TXBC_TFQS_SHIFT 24
+#define TXBC_TFQS_MASK (0x3f << TXBC_TFQS_SHIFT)
+
+/* Tx FIFO/Queue Status (TXFQS) */
+#define TXFQS_TFQF BIT(21)
+#define TXFQS_TFQPI_SHIFT 16
+#define TXFQS_TFQPI_MASK (0x1f << TXFQS_TFQPI_SHIFT)
+#define TXFQS_TFGI_SHIFT 8
+#define TXFQS_TFGI_MASK (0x1f << TXFQS_TFGI_SHIFT)
+#define TXFQS_TFFL_SHIFT 0
+#define TXFQS_TFFL_MASK (0x3f << TXFQS_TFFL_SHIFT)
+
+/* Tx Buffer Element Size Configuration(TXESC) */
+#define TXESC_TBDS_8BYTES 0x0
+#define TXESC_TBDS_64BYTES 0x7
+
+/* Tx Event FIFO Configuration (TXEFC) */
+#define TXEFC_EFS_SHIFT 16
+#define TXEFC_EFS_MASK (0x3f << TXEFC_EFS_SHIFT)
+
+/* Tx Event FIFO Status (TXEFS) */
+#define TXEFS_TEFL BIT(25)
+#define TXEFS_EFF BIT(24)
+#define TXEFS_EFGI_SHIFT 8
+#define TXEFS_EFGI_MASK (0x1f << TXEFS_EFGI_SHIFT)
+#define TXEFS_EFFL_SHIFT 0
+#define TXEFS_EFFL_MASK (0x3f << TXEFS_EFFL_SHIFT)
+
+/* Tx Event FIFO Acknowledge (TXEFA) */
+#define TXEFA_EFAI_SHIFT 0
+#define TXEFA_EFAI_MASK (0x1f << TXEFA_EFAI_SHIFT)
+
+/* Message RAM Configuration (in bytes) */
+#define SIDF_ELEMENT_SIZE 4
+#define XIDF_ELEMENT_SIZE 8
+#define RXF0_ELEMENT_SIZE 72
+#define RXF1_ELEMENT_SIZE 72
+#define RXB_ELEMENT_SIZE 72
+#define TXE_ELEMENT_SIZE 8
+#define TXB_ELEMENT_SIZE 72
+
+/* Message RAM Elements */
+#define M_CAN_FIFO_ID 0x0
+#define M_CAN_FIFO_DLC 0x4
+#define M_CAN_FIFO_DATA(n) (0x8 + ((n) << 2))
+
+/* Rx Buffer Element */
+/* R0 */
+#define RX_BUF_ESI BIT(31)
+#define RX_BUF_XTD BIT(30)
+#define RX_BUF_RTR BIT(29)
+/* R1 */
+#define RX_BUF_ANMF BIT(31)
+#define RX_BUF_FDF BIT(21)
+#define RX_BUF_BRS BIT(20)
+
+/* Tx Buffer Element */
+/* T0 */
+#define TX_BUF_ESI BIT(31)
+#define TX_BUF_XTD BIT(30)
+#define TX_BUF_RTR BIT(29)
+/* T1 */
+#define TX_BUF_EFC BIT(23)
+#define TX_BUF_FDF BIT(21)
+#define TX_BUF_BRS BIT(20)
+#define TX_BUF_MM_SHIFT 24
+#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT)
+
+/* Tx event FIFO Element */
+/* E1 */
+#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT
+#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT)
+
+/* address offset and element number for each FIFO/Buffer in the Message RAM */
+struct mram_cfg {
+ u16 off;
+ u8 num;
+};
+
+/* m_can private data structure */
+struct m_can_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *dev;
+ struct device *device;
+ struct clk *hclk;
+ struct clk *cclk;
+ void __iomem *base;
+ u32 irqstatus;
+ int version;
+
+ /* message ram configuration */
+ void __iomem *mram_base;
+ struct mram_cfg mcfg[MRAM_CFG_NUM];
+};
+
+static inline u32 m_can_read(const struct m_can_priv *priv, enum m_can_reg reg)
+{
+ return readl(priv->base + reg);
+}
+
+static inline void m_can_write(const struct m_can_priv *priv,
+ enum m_can_reg reg, u32 val)
+{
+ writel(val, priv->base + reg);
+}
+
+static inline u32 m_can_fifo_read(const struct m_can_priv *priv,
+ u32 fgi, unsigned int offset)
+{
+ return readl(priv->mram_base + priv->mcfg[MRAM_RXF0].off +
+ fgi * RXF0_ELEMENT_SIZE + offset);
+}
+
+static inline void m_can_fifo_write(const struct m_can_priv *priv,
+ u32 fpi, unsigned int offset, u32 val)
+{
+ writel(val, priv->mram_base + priv->mcfg[MRAM_TXB].off +
+ fpi * TXB_ELEMENT_SIZE + offset);
+}
+
+static inline u32 m_can_txe_fifo_read(const struct m_can_priv *priv,
+ u32 fgi,
+ u32 offset) {
+ return readl(priv->mram_base + priv->mcfg[MRAM_TXE].off +
+ fgi * TXE_ELEMENT_SIZE + offset);
+}
+
+static inline bool m_can_tx_fifo_full(const struct m_can_priv *priv)
+{
+ return !!(m_can_read(priv, M_CAN_TXFQS) & TXFQS_TFQF);
+}
+
+extern int register_m_can_dev(struct net_device *dev);
+extern void unregister_m_can_dev(struct net_device *dev);
+extern void m_can_config_endisable(const struct m_can_priv *priv, bool enable);
+extern void m_can_enable_all_interrupts(const struct m_can_priv *priv);
+extern void m_can_disable_all_interrupts(const struct m_can_priv *priv);
+extern struct net_device *alloc_m_can_dev(u32 tx_fifo_size);
+extern void free_m_can_dev(struct net_device *dev);
+extern int m_can_clk_start(struct m_can_priv *priv);
+extern void m_can_clk_stop(struct m_can_priv *priv);
+extern int m_can_dev_setup(struct device *dev, struct net_device *net,
+ void __iomem *addr);
+extern void m_can_start(struct net_device *dev);
+extern void m_can_stop(struct net_device *dev);
+extern void m_can_init_ram(struct m_can_priv *priv);
+
+#endif
diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c
new file mode 100644
index 000000000000..f69f502c9265
--- /dev/null
+++ b/drivers/net/can/m_can/m_can_platform.c
@@ -0,0 +1,306 @@
+/*
+ * CAN bus driver for Bosch M_CAN controller
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Dong Aisheng <b29396@freescale.com>
+ *
+ * Bosch M_CAN user manual can be obtained from:
+ * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/
+ * mcan_users_manual_v302.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
+#include <linux/can/dev.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "m_can.h"
+
+static void m_can_of_parse_mram(struct m_can_priv *priv, const u32 *mram_config_vals)
+{
+ priv->mcfg[MRAM_SIDF].off = mram_config_vals[0];
+ priv->mcfg[MRAM_SIDF].num = mram_config_vals[1];
+ priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off +
+ priv->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
+ priv->mcfg[MRAM_XIDF].num = mram_config_vals[2];
+ priv->mcfg[MRAM_RXF0].off = priv->mcfg[MRAM_XIDF].off +
+ priv->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
+ priv->mcfg[MRAM_RXF0].num = mram_config_vals[3] &
+ (RXFC_FS_MASK >> RXFC_FS_SHIFT);
+ priv->mcfg[MRAM_RXF1].off = priv->mcfg[MRAM_RXF0].off +
+ priv->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
+ priv->mcfg[MRAM_RXF1].num = mram_config_vals[4] &
+ (RXFC_FS_MASK >> RXFC_FS_SHIFT);
+ priv->mcfg[MRAM_RXB].off = priv->mcfg[MRAM_RXF1].off +
+ priv->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
+ priv->mcfg[MRAM_RXB].num = mram_config_vals[5];
+ priv->mcfg[MRAM_TXE].off = priv->mcfg[MRAM_RXB].off +
+ priv->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
+ priv->mcfg[MRAM_TXE].num = mram_config_vals[6];
+ priv->mcfg[MRAM_TXB].off = priv->mcfg[MRAM_TXE].off +
+ priv->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
+ priv->mcfg[MRAM_TXB].num = mram_config_vals[7] &
+ (TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT);
+
+ dev_dbg(priv->device,
+ "mram_base %p sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
+ priv->mram_base,
+ priv->mcfg[MRAM_SIDF].off, priv->mcfg[MRAM_SIDF].num,
+ priv->mcfg[MRAM_XIDF].off, priv->mcfg[MRAM_XIDF].num,
+ priv->mcfg[MRAM_RXF0].off, priv->mcfg[MRAM_RXF0].num,
+ priv->mcfg[MRAM_RXF1].off, priv->mcfg[MRAM_RXF1].num,
+ priv->mcfg[MRAM_RXB].off, priv->mcfg[MRAM_RXB].num,
+ priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
+ priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
+
+ m_can_init_ram(priv);
+}
+
+static int m_can_plat_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct m_can_priv *priv;
+ struct resource *res;
+ void __iomem *addr;
+ void __iomem *mram_addr;
+ struct clk *hclk, *cclk;
+ int irq, ret;
+ struct device_node *np;
+ u32 mram_config_vals[MRAM_CFG_LEN];
+ u32 tx_fifo_size;
+
+ np = pdev->dev.of_node;
+
+ hclk = devm_clk_get(&pdev->dev, "hclk");
+ cclk = devm_clk_get(&pdev->dev, "cclk");
+
+ if (IS_ERR(hclk) || IS_ERR(cclk)) {
+ dev_err(&pdev->dev, "no clock found\n");
+ ret = -ENODEV;
+ goto failed_ret;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ irq = platform_get_irq_byname(pdev, "int0");
+
+ if (IS_ERR(addr) || irq < 0) {
+ ret = -EINVAL;
+ goto failed_ret;
+ }
+
+ /* message ram could be shared */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
+ if (!res) {
+ ret = -ENODEV;
+ goto failed_ret;
+ }
+
+ mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!mram_addr) {
+ ret = -ENOMEM;
+ goto failed_ret;
+ }
+
+ /* get message ram configuration */
+ ret = of_property_read_u32_array(np, "bosch,mram-cfg",
+ mram_config_vals,
+ sizeof(mram_config_vals) / 4);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not get Message RAM configuration.");
+ goto failed_ret;
+ }
+
+ /* Get TX FIFO size
+ * Defines the total amount of echo buffers for loopback
+ */
+ tx_fifo_size = mram_config_vals[7];
+
+ /* allocate the m_can device */
+ dev = alloc_m_can_dev(tx_fifo_size);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto failed_ret;
+ }
+
+ priv = netdev_priv(dev);
+ dev->irq = irq;
+ priv->device = &pdev->dev;
+ priv->hclk = hclk;
+ priv->cclk = cclk;
+ priv->can.clock.freq = clk_get_rate(cclk);
+ priv->mram_base = mram_addr;
+
+ platform_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ /* Enable clocks. Necessary to read Core Release in order to determine
+ * M_CAN version
+ */
+ pm_runtime_enable(&pdev->dev);
+ ret = m_can_clk_start(priv);
+ if (ret)
+ goto pm_runtime_fail;
+
+ ret = m_can_dev_setup(&pdev->dev, dev, addr);
+ if (ret)
+ goto clk_disable;
+
+ ret = register_m_can_dev(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+ KBUILD_MODNAME, ret);
+ goto clk_disable;
+ }
+
+ m_can_of_parse_mram(priv, mram_config_vals);
+
+ devm_can_led_init(dev);
+
+ of_can_transceiver(dev);
+
+ dev_info(&pdev->dev, "%s device registered (irq=%d, version=%d)\n",
+ KBUILD_MODNAME, dev->irq, priv->version);
+
+ /* Probe finished
+ * Stop clocks. They will be reactivated once the M_CAN device is opened
+ */
+clk_disable:
+ m_can_clk_stop(priv);
+pm_runtime_fail:
+ if (ret) {
+ pm_runtime_disable(&pdev->dev);
+ free_m_can_dev(dev);
+ }
+failed_ret:
+ return ret;
+}
+
+static __maybe_unused int m_can_suspend(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct m_can_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ m_can_stop(ndev);
+ m_can_clk_stop(priv);
+ }
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ return 0;
+}
+
+static __maybe_unused int m_can_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct m_can_priv *priv = netdev_priv(ndev);
+
+ pinctrl_pm_select_default_state(dev);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(ndev)) {
+ int ret;
+
+ ret = m_can_clk_start(priv);
+ if (ret)
+ return ret;
+
+ m_can_init_ram(priv);
+ m_can_start(ndev);
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+
+ return 0;
+}
+
+static int m_can_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ unregister_m_can_dev(dev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_m_can_dev(dev);
+
+ return 0;
+}
+
+static int __maybe_unused m_can_runtime_suspend(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct m_can_priv *priv = netdev_priv(ndev);
+
+ clk_disable_unprepare(priv->cclk);
+ clk_disable_unprepare(priv->hclk);
+
+ return 0;
+}
+
+static int __maybe_unused m_can_runtime_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct m_can_priv *priv = netdev_priv(ndev);
+ int err;
+
+ err = clk_prepare_enable(priv->hclk);
+ if (err)
+ return err;
+
+ err = clk_prepare_enable(priv->cclk);
+ if (err)
+ clk_disable_unprepare(priv->hclk);
+
+ return err;
+}
+
+static const struct dev_pm_ops m_can_pmops = {
+ SET_RUNTIME_PM_OPS(m_can_runtime_suspend,
+ m_can_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume)
+};
+
+static const struct of_device_id m_can_of_table[] = {
+ { .compatible = "bosch,m_can", .data = NULL },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, m_can_of_table);
+
+static struct platform_driver m_can_plat_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = m_can_of_table,
+ .pm = &m_can_pmops,
+ },
+ .probe = m_can_plat_probe,
+ .remove = m_can_plat_remove,
+};
+
+module_platform_driver(m_can_plat_driver);
+
+MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");
--
2.23.0
^ permalink raw reply related
* [PATCH v2 2/2] net: phy: dp83867: Add SGMII mode type switching
From: Vitaly Gaiduk @ 2019-09-09 11:02 UTC (permalink / raw)
To: davem, robh+dt, f.fainelli
Cc: Vitaly Gaiduk, Mark Rutland, Andrew Lunn, Heiner Kallweit,
Trent Piepho, netdev, devicetree, linux-kernel
In-Reply-To: <1567700761-14195-2-git-send-email-vitaly.gaiduk@cloudbear.ru>
This patch adds ability to switch beetween two PHY SGMII modes.
Some hardware, for example, FPGA IP designs may use 6-wire mode
which enables differential SGMII clock to MAC.
Signed-off-by: Vitaly Gaiduk <vitaly.gaiduk@cloudbear.ru>
---
Changes in v2:
- changed variable sgmii_type name to sgmii_ref_clk_en
drivers/net/phy/dp83867.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index 1f1ecee..cd6260e 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -37,6 +37,7 @@
#define DP83867_STRAP_STS2 0x006f
#define DP83867_RGMIIDCTL 0x0086
#define DP83867_IO_MUX_CFG 0x0170
+#define DP83867_SGMIICTL 0x00D3
#define DP83867_10M_SGMII_CFG 0x016F
#define DP83867_10M_SGMII_RATE_ADAPT_MASK BIT(7)
@@ -61,6 +62,9 @@
#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
+/* SGMIICTL bits */
+#define DP83867_SGMII_TYPE BIT(14)
+
/* STRAP_STS1 bits */
#define DP83867_STRAP_STS1_RESERVED BIT(11)
@@ -109,6 +113,7 @@ struct dp83867_private {
bool rxctrl_strap_quirk;
bool set_clk_output;
u32 clk_output_sel;
+ bool sgmii_ref_clk_en;
};
static int dp83867_ack_interrupt(struct phy_device *phydev)
@@ -197,6 +202,9 @@ static int dp83867_of_init(struct phy_device *phydev)
dp83867->rxctrl_strap_quirk = of_property_read_bool(of_node,
"ti,dp83867-rxctrl-strap-quirk");
+ dp83867->sgmii_ref_clk_en = of_property_read_bool(of_node,
+ "ti,sgmii-ref-clock-output-enable");
+
/* Existing behavior was to use default pin strapping delay in rgmii
* mode, but rgmii should have meant no delay. Warn existing users.
*/
@@ -389,6 +397,14 @@ static int dp83867_config_init(struct phy_device *phydev)
if (ret)
return ret;
+
+ /* SGMII type is set to 4-wire mode by default */
+ if (dp83867->sgmii_ref_clk_en) {
+ /* Switch on 6-wire mode */
+ val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL);
+ val |= DP83867_SGMII_TYPE;
+ phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL, val);
+ }
}
/* Enable Interrupt output INT_OE in CFG3 register */
--
2.7.4
^ permalink raw reply related
* [PATCH v2 1/2] net: phy: dp83867: Add documentation for SGMII mode type
From: Vitaly Gaiduk @ 2019-09-09 11:02 UTC (permalink / raw)
To: davem, robh+dt, f.fainelli
Cc: Vitaly Gaiduk, Mark Rutland, Andrew Lunn, Trent Piepho, netdev,
devicetree, linux-kernel
In-Reply-To: <1568026945-3857-1-git-send-email-vitaly.gaiduk@cloudbear.ru>
Add documentation of ti,sgmii-ref-clock-output-enable
which can be used to select SGMII mode type (4 or 6-wire).
Signed-off-by: Vitaly Gaiduk <vitaly.gaiduk@cloudbear.ru>
---
Changes in v2:
- renamed ti,sgmii-type to ti,sgmii-ref-clock-output-enable
and extended description
Documentation/devicetree/bindings/net/ti,dp83867.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/ti,dp83867.txt b/Documentation/devicetree/bindings/net/ti,dp83867.txt
index db6aa3f..c98c682 100644
--- a/Documentation/devicetree/bindings/net/ti,dp83867.txt
+++ b/Documentation/devicetree/bindings/net/ti,dp83867.txt
@@ -37,6 +37,10 @@ Optional property:
for applicable values. The CLK_OUT pin can also
be disabled by this property. When omitted, the
PHY's default will be left as is.
+ - ti,sgmii-ref-clock-output-enable - This denotes the fact which
+ SGMII configuration is used (4 or 6-wire modes).
+ Some MACs work with differential SGMII clock.
+ See data manual for details.
Note: ti,min-output-impedance and ti,max-output-impedance are mutually
exclusive. When both properties are present ti,max-output-impedance
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 1/2] net: phy: dp83867: Add documentation for SGMII mode type
From: Vitaly Gaiduk @ 2019-09-09 11:07 UTC (permalink / raw)
To: Andrew Lunn
Cc: davem@davemloft.net, robh+dt@kernel.org, f.fainelli@gmail.com,
Mark Rutland, netdev@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Trent Piepho
In-Reply-To: <20190908085417.GA28580@lunn.ch>
I've done required changes. Sorry for HTML in previous mail I sent it
from mobile app which has not disabling HTML.
Vitaly.
^ permalink raw reply
* Re: [PATCH] rtl8xxxu: add bluetooth co-existence support for single antenna
From: Jes Sorensen @ 2019-09-09 11:13 UTC (permalink / raw)
To: Chris Chiu, kvalo, davem; +Cc: linux-wireless, netdev, linux-kernel, linux
In-Reply-To: <20190903053735.85957-1-chiu@endlessm.com>
On 9/3/19 1:37 AM, Chris Chiu wrote:
> The RTL8723BU suffers the wifi disconnection problem while bluetooth
> device connected. While wifi is doing tx/rx, the bluetooth will scan
> without results. This is due to the wifi and bluetooth share the same
> single antenna for RF communication and they need to have a mechanism
> to collaborate.
>
> BT information is provided via the packet sent from co-processor to
> host (C2H). It contains the status of BT but the rtl8723bu_handle_c2h
> dose not really handle it. And there's no bluetooth coexistence
> mechanism to deal with it.
>
> This commit adds a workqueue to set the tdma configurations and
> coefficient table per the parsed bluetooth link status and given
> wifi connection state. The tdma/coef table comes from the vendor
> driver code of the RTL8192EU and RTL8723BU. However, this commit is
> only for single antenna scenario which RTL8192EU is default dual
> antenna. The rtl8xxxu_parse_rxdesc24 which invokes the handle_c2h
> is only for 8723b and 8192e so the mechanism is expected to work
> on both chips with single antenna. Note RTL8192EU dual antenna is
> not supported.
I am pretty excited to see this! It always bugged me the bluetooth
driver was allowed to be applied breaking the existing wifi driver.
Except for some cosmetic stuff, I am all happy with this.
> Signed-off-by: Chris Chiu <chiu@endlessm.com>
> ---
> .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 37 +++
> .../realtek/rtl8xxxu/rtl8xxxu_8723b.c | 2 -
> .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 243 +++++++++++++++++-
> 3 files changed, 275 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
> index 582c2a346cec..22e95b11bfbb 100644
> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
> +
> +struct rtl8xxxu_btcoex {
> + u8 bt_status;
> + bool bt_busy;
> + bool has_sco;
> + bool has_a2dp;
> + bool has_hid;
> + bool has_pan;
> + bool hid_only;
> + bool a2dp_only;
> + bool c2h_bt_inquiry;
> +};
bool is large, maybe just use flags or u8's for this? Not a big deal though.
> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
> index a6f358b9e447..4f72c2d14d44 100644
> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
> + if (!btcoex->has_a2dp &&
> + !btcoex->has_sco &&
> + !btcoex->has_pan &&
> + btcoex->has_hid)
This should all fit in one line - 80 characters
> + btcoex->hid_only = true;
> + else
> + btcoex->hid_only = false;
> +
> + if (!btcoex->has_sco &&
> + !btcoex->has_pan &&
> + !btcoex->has_hid &&
> + btcoex->has_a2dp)
Ditto
> +static void rtl8xxxu_c2hcmd_callback(struct work_struct *work)
> +{
> + struct rtl8xxxu_priv *priv;
> + struct rtl8723bu_c2h *c2h;
> + struct ieee80211_vif *vif;
> + struct device *dev;
> + struct sk_buff *skb = NULL;
> + unsigned long flags;
> + int len;
> + u8 bt_info = 0;
> + struct rtl8xxxu_btcoex *btcoex;
> +
> + priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work);
> + vif = priv->vif;
> + btcoex = &priv->bt_coex;
> + dev = &priv->udev->dev;
> +
> + if (priv->rf_paths > 1)
> + goto out;
> +
> + while (!skb_queue_empty(&priv->c2hcmd_queue)) {
> + spin_lock_irqsave(&priv->c2hcmd_lock, flags);
> + skb = __skb_dequeue(&priv->c2hcmd_queue);
> + spin_unlock_irqrestore(&priv->c2hcmd_lock, flags);
> +
> + c2h = (struct rtl8723bu_c2h *)skb->data;
> + len = skb->len - 2;
> +
> + switch (c2h->id) {
> + case C2H_8723B_BT_INFO:
> + bt_info = c2h->bt_info.bt_info;
> +
> + rtl8723bu_update_bt_link_info(priv, bt_info);
> +
> + if (btcoex->c2h_bt_inquiry) {
> + if (vif && !vif->bss_conf.assoc) {
> + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0);
> + rtl8723bu_set_coex_with_type(priv, 0);
> + } else if (btcoex->has_sco ||
> + btcoex->has_hid ||
> + btcoex->has_a2dp) {
> + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, 0x3, 0x11, 0x11);
> + rtl8723bu_set_coex_with_type(priv, 4);
> + } else if (btcoex->has_pan) {
> + rtl8723bu_set_ps_tdma(priv, 0x61, 0x3f, 0x3, 0x11, 0x11);
> + rtl8723bu_set_coex_with_type(priv, 4);
> + } else {
> + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0);
> + rtl8723bu_set_coex_with_type(priv, 7);
> + }
> +
> + return;
> + }
Kernel code is 80 characters wide - maybe create a btcoex helper
function for this?
> +
> + if (vif && vif->bss_conf.assoc) {
> + u32 val32 = 0;
> + u32 high_prio_tx = 0, high_prio_rx = 0;
> +
> + val32 = rtl8xxxu_read32(priv, 0x770);
> + high_prio_tx = val32 & 0x0000ffff;
> + high_prio_rx = (val32 & 0xffff0000) >> 16;
> +
> + if (btcoex->bt_busy) {
> + if (btcoex->hid_only) {
> + rtl8723bu_set_ps_tdma(priv, 0x61, 0x20, 0x3, 0x11, 0x11);
> + rtl8723bu_set_coex_with_type(priv, 5);
> + } else if (btcoex->a2dp_only) {
> + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, 0x3, 0x11, 0x11);
> + rtl8723bu_set_coex_with_type(priv, 4);
> + } else if ((btcoex->has_a2dp &&
> + btcoex->has_pan) ||
> + (btcoex->has_hid &&
> + btcoex->has_a2dp &&
> + btcoex->has_pan)) {
> + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, 0x3, 0x10, 0x10);
> + rtl8723bu_set_coex_with_type(priv, 4);
> + } else if (btcoex->has_hid &&
> + btcoex->has_a2dp) {
> + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, 0x3, 0x10, 0x10);
> + rtl8723bu_set_coex_with_type(priv, 3);
> + } else {
> + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, 0x3, 0x11, 0x11);
> + rtl8723bu_set_coex_with_type(priv, 4);
> + }
Same here
Otherwise, thanks for digging into this, it's really great to see!
Cheers,
Jes
^ permalink raw reply
* Re: [RFC PATCH 3/3] Enable ptp_kvm for arm64
From: Marc Zyngier @ 2019-09-09 11:24 UTC (permalink / raw)
To: Jianyong Wu (Arm Technology China)
Cc: netdev@vger.kernel.org, pbonzini@redhat.com,
sean.j.christopherson@intel.com, richardcochran@gmail.com,
Mark Rutland, Will Deacon, Suzuki Poulose,
linux-kernel@vger.kernel.org, Steve Capper,
Kaly Xin (Arm Technology China), Justin He (Arm Technology China)
In-Reply-To: <HE1PR0801MB16768BE47D3D1F0662DDC3C7F4B70@HE1PR0801MB1676.eurprd08.prod.outlook.com>
On Mon, 09 Sep 2019 11:17:24 +0100,
"Jianyong Wu (Arm Technology China)" <Jianyong.Wu@arm.com> wrote:
Hi Jianyoung,
[...]
> > > > I'm definitely not keen on exposing the internals of the arch_timer
> > > > driver to random subsystems. Furthermore, you seem to expect that
> > > > the guest kernel will only use the arch timer as a clocksource, and
> > > > nothing really guarantees that (in which case
> > get_device_system_crosststamp will fail).
> > > >
> > > The code here is really ugly, I need a better solution to offer a
> > > clock source For the guest.
> > >
> > > > It looks to me that we'd be better off exposing a core timekeeping
> > > > API that populates a struct system_counterval_t based on the
> > > > *current* timekeeper monotonic clocksource. This would simplify the
> > > > split between generic and arch-specific code.
> > > >
> > > I think it really necessary.
> > >
> > > > Whether or not tglx will be happy with the idea is another problem,
> > > > but I'm certainly not taking any change to the arch timer code based on
> > this.
> > > >
> > > I can have a try, but the detail is not clear for me now.
> >
> > Something along those lines:
> >
> > From 5f1c061e55c691d64012bc7c1490a1a8c4432c67 Mon Sep 17 00:00:00 2001
> > From: Marc Zyngier <maz@kernel.org>
> > Date: Sat, 7 Sep 2019 10:11:49 +0100
> > Subject: [PATCH] timekeeping: Expose API allowing retrival of current
> > clocksource and counter value
> >
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> > include/linux/timekeeping.h | 5 +++++
> > kernel/time/timekeeping.c | 12 ++++++++++++
> > 2 files changed, 17 insertions(+)
> >
> > diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index
> > b27e2ffa96c1..6df26a913711 100644
> > --- a/include/linux/timekeeping.h
> > +++ b/include/linux/timekeeping.h
> > @@ -275,6 +275,11 @@ extern int get_device_system_crosststamp(
> > struct system_time_snapshot *history,
> > struct system_device_crosststamp *xtstamp);
> >
> > +/*
> > + * Obtain current monotonic clock and its counter value */ extern void
> > +get_current_counterval(struct system_counterval_t *sc);
> > +
> > /*
> > * Simultaneously snapshot realtime and monotonic raw clocks
> > */
> > diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index
> > d911c8470149..de689bbd3808 100644
> > --- a/kernel/time/timekeeping.c
> > +++ b/kernel/time/timekeeping.c
> > @@ -1098,6 +1098,18 @@ static bool cycle_between(u64 before, u64 test,
> > u64 after)
> > return false;
> > }
> >
> > +/**
> > + * get_current_counterval - Snapshot the current clocksource and counter
> > value
> > + * @sc: Pointer to a struct containing the current clocksource and its
> > value
> > + */
> > +void get_current_counterval(struct system_counterval_t *sc) {
> > + struct timekeeper *tk = &tk_core.timekeeper;
> > +
> > + sc->cs = READ_ONCE(tk->tkr_mono.clock);
> > + sc->cycles = sc->cs->read(sc->cs);
> > +}
> > +
> > /**
> > * get_device_system_crosststamp - Synchronously capture system/device
> > timestamp
> > * @get_time_fn: Callback to get simultaneous device time and
> >
> > which should do the right thing.
> >
> It is a good news for me. These code is indeed what I need! So
> what's your plan about this patch? Is there any problem with you if
> I include these code into my patch ?
Just add this patch as part of your series (I'll try to write an
actual commit log for that).
[...]
> > > > Other questions: how does this works with VM migration? Specially
> > > > when moving from a hypervisor that supports the feature to one that
> > doesn't?
> > > >
> > > I think it won't solve the problem generated by VM migration and only
> > > for VMs in a single machine. Ptp_kvm only works for VMs in the same
> > > machine. But using ptp (not ptp_kvm) clock, all the machines in a low
> > > latency network environment can keep time sync in high precision, Then
> > > VMs move from one machine to another will obtain a high precision time
> > > sync.
> >
> > That's a problem. Migration must be possible from one host to another, even
> > if that means temporarily loosing some (or a lot of) precision. The service
> > must be discoverable from userspace on the host so that the MVV can decie
> > whether a migration is possible or not.
> >
> Don't worry, things will be not that bad. ptp_kvm will not trouble
> the VM migration. This ptp_kvm is one clocksource of the clock pool
> for chrony. Chrony will choose the highest precision clock from the
> pool. If host does not support ptp_kvm, the ptp_kvm will not be
> chosen as the clocksouce of chrony. We have roughly the same logic
> of implementation of ptp_kvm with x86, and ptp_kvm works well in
> x86. so I think that will be the case for arm64.
>
> Maybe I miss your point, I have no idea of MVV and can't get related
> info from google. Also I'm not clear of your last words of how to
> decide VM migration is possible?
Sorry. s/MVV/VMM/. Basically userspace, such as QEMU.
Here's an example: The guest runs on a PTP aware host, starts using
the PTP service and uses HVC calls to get its clock. We now migrate
the guest to a non PTP-aware host. The hypercalls are now going to
fail unexpectedly. Is that something that is acceptable? I don't think
it is. Once you've allowed a guest to use a service, this service
should be preserved. I'd be more confident if we gave to userspace the
indication that the hypervisor supports PTP. Userspace can then decide
whether to perform migration or not.
Thanks,
M.
--
Jazz is not dead, it just smells funny.
^ permalink raw reply
* Re: VRF Issue Since kernel 5
From: Alexis Bauvin @ 2019-09-09 12:01 UTC (permalink / raw)
To: Gowen; +Cc: netdev@vger.kernel.org
In-Reply-To: <CWLP265MB1554B902B7F3B43E6E75FD0DFDB70@CWLP265MB1554.GBRP265.PROD.OUTLOOK.COM>
Hi,
I guess all routing from the management VRF itself is working correctly (i.e. cURLing
an IP from this VRF or digging any DNS), and it is your route leakage that’s at fault.
Could you try swapping the local and l3mdev rules?
`ip rule del pref 0; ip rule add from all lookup local pref 1001`
I faced security issues and behavioral weirdnesses from the default kernel rule ordering
regarding the default vrf.
Alexis
> Le 9 sept. 2019 à 12:53, Gowen <gowen@potatocomputing.co.uk> a écrit :
>
> Hi Alexis,
>
> Admin@NETM06:~$ sysctl net.ipv4.tcp_l3mdev_accept
> net.ipv4.tcp_l3mdev_accept = 1
>
> Admin@NETM06:~$ sudo ip vrf exec mgmt-vrf curl kernel.org
> curl: (6) Could not resolve host: kernel.org
>
> the failure to resolve is the same with all DNS lookups from any process I've run
>
> The route is there from the guide I originally used, I can't remember the purpose but I know I don't need it - I've removed it now and no change
>
> Admin@NETM06:~$ ip rule show
> 0: from all lookup local
> 1000: from all lookup [l3mdev-table]
> 32766: from all lookup main
> 32767: from all lookup default
>
> I could switch the VRFs over, but this is a test-box and i have prod boxes on this as well so not so keen on that if I can avoid it.
>
> From what I can speculate, because the TCP return traffic is met with an RST, it looks like it may be something to do with iptables - but even if I set the policy to ACCEPT and flush all the rules, the behaviour remains the same.
>
> Is it possible that the TCP stack isn't aware of the session (as is mapped to wrong VRF internally or something to that effect) and is therefore sending the RST?
>
> Gareth
> From: Alexis Bauvin <abauvin@online.net>
> Sent: 09 September 2019 10:28
> To: Gowen <gowen@potatocomputing.co.uk>
> Cc: netdev@vger.kernel.org <netdev@vger.kernel.org>
> Subject: Re: VRF Issue Since kernel 5
>
> Hi,
>
> There has been some changes regarding VRF isolation in Linux 5 IIRC, namely proper
> isolation of the default VRF.
>
> Some things you may try:
>
> - looking at the l3mdev_accept sysctls (e.g. `net.ipv4.tcp_l3mdev_accept`)
> - querying stuff from the management vrf through `ip vrf exec vrf-mgmt <stuff>`
> e.g. `ip vrf exec vrf-mgmt curl kernel.org`
> `ip vrf exec vrf-mgmt dig @1.1.1.1 kernel.org`
> - reversing your logic: default VRF is your management one, the other one is for your
> other boxes
>
> Also, your `unreachable default metric 4278198272` route looks odd to me.
>
> What are your routing rules? (`ip rule`)
>
> Alexis
>
> > Le 9 sept. 2019 à 09:46, Gowen <gowen@potatocomputing.co.uk> a écrit :
> >
> > Hi there,
> >
> > Dave A said this was the mailer to send this to:
> >
> >
> > I’ve been using my management interface in a VRF for several months now and it’s worked perfectly – I’ve been able to update/upgrade the packages just fine and iptables works excellently with it – exactly as I needed.
> >
> >
> > Since Kernel 5 though I am no longer able to update – but the issue is quite a curious one as some traffic appears to be fine (DNS lookups use VRF correctly) but others don’t (updating/upgrading the packages)
> >
> >
> > I have on this device 2 interfaces:
> > Eth0 for management – inbound SSH, DNS, updates/upgrades
> > Eth1 for managing other boxes (ansible using SSH)
> >
> >
> > Link and addr info shown below:
> >
> >
> > Admin@NETM06:~$ ip link show
> > 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
> > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
> > 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master mgmt-vrf state UP mode DEFAULT group default qlen 1000
> > link/ether 00:22:48:07:cc:ad brd ff:ff:ff:ff:ff:ff
> > 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
> > link/ether 00:22:48:07:c9:6c brd ff:ff:ff:ff:ff:ff
> > 4: mgmt-vrf: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000
> > link/ether 8a:f6:26:65:02:5a brd ff:ff:ff:ff:ff:ff
> >
> >
> > Admin@NETM06:~$ ip addr
> > 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
> > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
> > inet 127.0.0.1/8 scope host lo
> > valid_lft forever preferred_lft forever
> > inet6 ::1/128 scope host
> > valid_lft forever preferred_lft forever
> > 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master mgmt-vrf state UP group default qlen 1000
> > link/ether 00:22:48:07:cc:ad brd ff:ff:ff:ff:ff:ff
> > inet 10.24.12.10/24 brd 10.24.12.255 scope global eth0
> > valid_lft forever preferred_lft forever
> > inet6 fe80::222:48ff:fe07:ccad/64 scope link
> > valid_lft forever preferred_lft forever
> > 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
> > link/ether 00:22:48:07:c9:6c brd ff:ff:ff:ff:ff:ff
> > inet 10.24.12.9/24 brd 10.24.12.255 scope global eth1
> > valid_lft forever preferred_lft forever
> > inet6 fe80::222:48ff:fe07:c96c/64 scope link
> > valid_lft forever preferred_lft forever
> > 4: mgmt-vrf: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP group default qlen 1000
> > link/ether 8a:f6:26:65:02:5a brd ff:ff:ff:ff:ff:ff
> >
> >
> >
> > the production traffic is all in the 10.0.0.0/8 network (eth1 global VRF) except for a few subnets (DNS) which are routed out eth0 (mgmt-vrf)
> >
> >
> > Admin@NETM06:~$ ip route show
> > default via 10.24.12.1 dev eth0
> > 10.0.0.0/8 via 10.24.12.1 dev eth1
> > 10.24.12.0/24 dev eth1 proto kernel scope link src 10.24.12.9
> > 10.24.65.0/24 via 10.24.12.1 dev eth0
> > 10.25.65.0/24 via 10.24.12.1 dev eth0
> > 10.26.0.0/21 via 10.24.12.1 dev eth0
> > 10.26.64.0/21 via 10.24.12.1 dev eth0
> >
> >
> > Admin@NETM06:~$ ip route show vrf mgmt-vrf
> > default via 10.24.12.1 dev eth0
> > unreachable default metric 4278198272
> > 10.24.12.0/24 dev eth0 proto kernel scope link src 10.24.12.10
> > 10.24.65.0/24 via 10.24.12.1 dev eth0
> > 10.25.65.0/24 via 10.24.12.1 dev eth0
> > 10.26.0.0/21 via 10.24.12.1 dev eth0
> > 10.26.64.0/21 via 10.24.12.1 dev eth0
> >
> >
> >
> > The strange activity occurs when I enter the command “sudo apt update” as I can resolve the DNS request (10.24.65.203 or 10.24.64.203, verified with tcpdump) out eth0 but for the actual update traffic there is no activity:
> >
> >
> > sudo tcpdump -i eth0 '(host 10.24.65.203 or host 10.25.65.203) and port 53' -n
> > <OUTPUT OMITTED FOR BREVITY>
> > 10:06:05.268735 IP 10.24.12.10.39963 > 10.24.65.203.53: 48798+ [1au] A? security.ubuntu.com. (48)
> > <OUTPUT OMITTED FOR BREVITY>
> > 10:06:05.284403 IP 10.24.65.203.53 > 10.24.12.10.39963: 48798 13/0/1 A 91.189.91.23, A 91.189.88.24, A 91.189.91.26, A 91.189.88.162, A 91.189.88.149, A 91.189.91.24, A 91.189.88.173, A 91.189.88.177, A 91.189.88.31, A 91.189.91.14, A 91.189.88.176, A 91.189.88.175, A 91.189.88.174 (256)
> >
> >
> >
> > You can see that the update traffic is returned but is not accepted by the stack and a RST is sent
> >
> >
> > Admin@NETM06:~$ sudo tcpdump -i eth0 '(not host 168.63.129.16 and port 80)' -n
> > tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
> > listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
> > 10:17:12.690658 IP 10.24.12.10.40216 > 91.189.88.175.80: Flags [S], seq 2279624826, win 64240, options [mss 1460,sackOK,TS val 2029365856 ecr 0,nop,wscale 7], length 0
> > 10:17:12.691929 IP 10.24.12.10.52362 > 91.189.95.83.80: Flags [S], seq 1465797256, win 64240, options [mss 1460,sackOK,TS val 3833463674 ecr 0,nop,wscale 7], length 0
> > 10:17:12.696270 IP 91.189.88.175.80 > 10.24.12.10.40216: Flags [S.], seq 968450722, ack 2279624827, win 28960, options [mss 1418,sackOK,TS val 81957103 ecr 2029365856,nop,wscale 7], length 0
> > 10:17:12.696301 IP 10.24.12.10.40216 > 91.189.88.175.80: Flags [R], seq 2279624827, win 0, length 0
> > 10:17:12.697884 IP 91.189.95.83.80 > 10.24.12.10.52362: Flags [S.], seq 4148330738, ack 1465797257, win 28960, options [mss 1418,sackOK,TS val 2257624414 ecr 3833463674,nop,wscale 8], length 0
> > 10:17:12.697909 IP 10.24.12.10.52362 > 91.189.95.83.80: Flags [R], seq 1465797257, win 0, length 0
> >
> >
> >
> >
> > I can emulate the DNS lookup using netcat in the vrf:
> >
> >
> > sudo ip vrf exec mgmt-vrf nc -u 10.24.65.203 53
> >
> >
> > then interactively enter the binary for a www.google.co.uk request:
> >
> >
> > 0035624be394010000010000000000010377777706676f6f676c6502636f02756b00000100010000290200000000000000
> >
> >
> > This returns as expected:
> >
> >
> > 00624be394010000010000000000010377777706676f6f676c6502636f02756b00000100010000290200000000000000
> >
> >
> > I can run:
> >
> >
> > Admin@NETM06:~$ host www.google.co.uk
> > www.google.co.uk has address 172.217.169.3
> > www.google.co.uk has IPv6 address 2a00:1450:4009:80d::2003
> >
> >
> > but I get a timeout for:
> >
> >
> > sudo ip vrf exec mgmt-vrf host www.google.co.uk
> > ;; connection timed out; no servers could be reached
> >
> >
> >
> > However I can take a repo address and vrf exec to it on port 80:
> >
> >
> > Admin@NETM06:~$ sudo ip vrf exec mgmt-vrf nc 91.189.91.23 80
> > hello
> > HTTP/1.1 400 Bad Request
> > <OUTPUT OMITTED>
> >
> > My iptables rule:
> >
> >
> > sudo iptables -Z
> > Admin@NETM06:~$ sudo iptables -L -v
> > Chain INPUT (policy DROP 16 packets, 3592 bytes)
> > pkts bytes target prot opt in out source destination
> > 44 2360 ACCEPT tcp -- any any anywhere anywhere tcp spt:http ctstate RELATED,ESTABLISHED
> > 83 10243 ACCEPT udp -- any any anywhere anywhere udp spt:domain ctstate RELATED,ESTABLISHED
> >
> >
> >
> > I cannot find out why the update isn’t working. Any help greatly appreciated
> >
> >
> > Kind Regards,
> >
> >
> > Gareth
^ permalink raw reply
* Re: [PATCH 0/2] Revert and rework on the metadata accelreation
From: Michael S. Tsirkin @ 2019-09-09 12:15 UTC (permalink / raw)
To: Jason Wang
Cc: David Miller, jgg, kvm, virtualization, netdev, linux-kernel,
aarcange, jglisse, linux-mm
In-Reply-To: <bb9ae371-58b7-b7fc-b728-b5c5f55d3a91@redhat.com>
On Mon, Sep 09, 2019 at 03:18:01PM +0800, Jason Wang wrote:
>
> On 2019/9/6 下午9:15, David Miller wrote:
> > From: Jason Wang <jasowang@redhat.com>
> > Date: Fri, 6 Sep 2019 18:02:35 +0800
> >
> > > On 2019/9/5 下午9:59, Jason Gunthorpe wrote:
> > > > I think you should apply the revert this cycle and rebase the other
> > > > patch for next..
> > > >
> > > > Jason
> > > Yes, the plan is to revert in this release cycle.
> > Then you should reset patch #1 all by itself targetting 'net'.
>
>
> Thanks for the reminding. I want the patch to go through Michael's vhost
> tree, that's why I don't put 'net' prefix. For next time, maybe I can use
> "vhost" as a prefix for classification?
That's fine by me.
--
MST
^ permalink raw reply
* [PATCH net-next 1/2] net: stmmac: Only enable enhanced addressing mode when needed
From: Thierry Reding @ 2019-09-09 12:36 UTC (permalink / raw)
To: David S . Miller
Cc: Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu, Jon Hunter,
Bitan Biswas, netdev, linux-tegra
From: Thierry Reding <treding@nvidia.com>
Enhanced addressing mode is only required when more than 32 bits need to
be addressed. Add a DMA configuration parameter to enable this mode only
when needed.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 5 ++++-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++++++
include/linux/stmmac.h | 1 +
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 64956465c030..3e00fd8befcf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -27,7 +27,10 @@ static void dwxgmac2_dma_init(void __iomem *ioaddr,
if (dma_cfg->aal)
value |= XGMAC_AAL;
- writel(value | XGMAC_EAME, ioaddr + XGMAC_DMA_SYSBUS_MODE);
+ if (dma_cfg->eame)
+ value |= XGMAC_EAME;
+
+ writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE);
}
static void dwxgmac2_dma_init_chan(void __iomem *ioaddr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 06ccd216ae90..ecd461207dbc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4497,6 +4497,12 @@ int stmmac_dvr_probe(struct device *device,
if (!ret) {
dev_info(priv->device, "Using %d bits DMA width\n",
priv->dma_cap.addr64);
+
+ /*
+ * If more than 32 bits can be addressed, make sure to
+ * enable enhanced addressing mode.
+ */
+ priv->plat->dma_cfg->eame = true;
} else {
ret = dma_set_mask_and_coherent(device, DMA_BIT_MASK(32));
if (ret) {
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 7ad7ae35cf88..d300ac907c76 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -92,6 +92,7 @@ struct stmmac_dma_cfg {
int fixed_burst;
int mixed_burst;
bool aal;
+ bool eame;
};
#define AXI_BLEN 7
--
2.23.0
^ permalink raw reply related
* [PATCH net-next 2/2] net: stmmac: Support enhanced addressing mode for DWMAC 4.10
From: Thierry Reding @ 2019-09-09 12:36 UTC (permalink / raw)
To: David S . Miller
Cc: Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu, Jon Hunter,
Bitan Biswas, netdev, linux-tegra
In-Reply-To: <20190909123627.29928-1-thierry.reding@gmail.com>
From: Thierry Reding <treding@nvidia.com>
The address width of the controller can be read from hardware feature
registers much like on XGMAC. Add support for parsing the ADDR64 field
so that the DMA mask can be set accordingly.
This avoids getting swiotlb involved for DMA on Tegra186 and later.
Also make sure that the upper 32 bits of the DMA address are written to
the DMA descriptors when enhanced addressing mode is used.
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 1 +
.../ethernet/stmicro/stmmac/dwmac4_descs.c | 4 ++--
.../net/ethernet/stmicro/stmmac/dwmac4_dma.c | 20 +++++++++++++++++++
.../net/ethernet/stmicro/stmmac/dwmac4_dma.h | 1 +
4 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 2ed11a581d80..f634fa09dffc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -183,6 +183,7 @@ enum power_event {
#define GMAC_HW_HASH_TB_SZ GENMASK(25, 24)
#define GMAC_HW_FEAT_AVSEL BIT(20)
#define GMAC_HW_TSOEN BIT(18)
+#define GMAC_HW_ADDR64 GENMASK(15, 14)
#define GMAC_HW_TXFIFOSIZE GENMASK(10, 6)
#define GMAC_HW_RXFIFOSIZE GENMASK(4, 0)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index dbde23e7e169..d546041d2fcd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -431,8 +431,8 @@ static void dwmac4_get_addr(struct dma_desc *p, unsigned int *addr)
static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr)
{
- p->des0 = cpu_to_le32(addr);
- p->des1 = 0;
+ p->des0 = cpu_to_le32(lower_32_bits(addr));
+ p->des1 = cpu_to_le32(upper_32_bits(addr));
}
static void dwmac4_clear(struct dma_desc *p)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 3ed5508586ef..23dfbd0efc37 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -132,6 +132,9 @@ static void dwmac4_dma_init(void __iomem *ioaddr,
if (dma_cfg->aal)
value |= DMA_SYS_BUS_AAL;
+ if (dma_cfg->eame)
+ value |= DMA_SYS_BUS_EAME;
+
writel(value, ioaddr + DMA_SYS_BUS_MODE);
}
@@ -354,6 +357,23 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24;
dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
+
+ dma_cap->addr64 = (hw_cap & GMAC_HW_ADDR64) >> 14;
+ switch (dma_cap->addr64) {
+ case 0:
+ dma_cap->addr64 = 32;
+ break;
+ case 1:
+ dma_cap->addr64 = 40;
+ break;
+ case 2:
+ dma_cap->addr64 = 48;
+ break;
+ default:
+ dma_cap->addr64 = 32;
+ break;
+ }
+
/* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by
* shifting and store the sizes in bytes.
*/
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index b66da0237d2a..d00776db20d6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -65,6 +65,7 @@
#define DMA_SYS_BUS_MB BIT(14)
#define DMA_AXI_1KBBE BIT(13)
#define DMA_SYS_BUS_AAL BIT(12)
+#define DMA_SYS_BUS_EAME BIT(11)
#define DMA_AXI_BLEN256 BIT(7)
#define DMA_AXI_BLEN128 BIT(6)
#define DMA_AXI_BLEN64 BIT(5)
--
2.23.0
^ permalink raw reply related
* Re: [PATCH v1 net-next 00/15] tc-taprio offload for SJA1105 DSA
From: Joergen Andreasen @ 2019-09-09 12:36 UTC (permalink / raw)
To: Andrew Lunn
Cc: Vladimir Oltean, David Miller, f.fainelli, vivien.didelot,
vinicius.gomes, vedang.patel, richardcochran, weifeng.voon, jiri,
m-karicheri2, Jose.Abreu, ilias.apalodimas, jhs, xiyou.wangcong,
kurt.kanzenbach, netdev
In-Reply-To: <20190908204224.GA2730@lunn.ch>
The 09/08/2019 22:42, Andrew Lunn wrote:
> On Sun, Sep 08, 2019 at 12:07:27PM +0100, Vladimir Oltean wrote:
> > I think Richard has been there when the taprio, etf qdiscs, SO_TXTIME
> > were first defined and developed:
> > https://patchwork.ozlabs.org/cover/808504/
> > I expect he is capable of delivering a competent review of the entire
> > series, possibly way more competent than my patch set itself.
> >
> > The reason why I'm not splitting it up is because I lose around 10 ns
> > of synchronization offset when using the hardware-corrected PTPCLKVAL
> > clock for timestamping rather than the PTPTSCLK free-running counter.
>
> Hi Vladimir
>
> I'm not suggesting anything is wrong with your concept, when i say
> split it up. It is more than when somebody sees 15 patches, they
> decide they don't have the time at the moment, and put it off until
> later. And often later never happens. If however they see a smaller
> number of patches, they think that yes they have time now, and do the
> review.
>
> So if you are struggling to get something reviewed, make it more
> appealing for the reviewer. Salami tactics.
>
> Andrew
I vote for splitting it up.
I don't know enough about PTP and taprio/qdisc to review the entire series
but the interface presented in patch 09/15 fits well with our future TSN
switches.
Joergen Andreasen, Microchip
^ permalink raw reply
* Re: [PATCH net-next 1/3] net: dsa: microchip: add KSZ9477 I2C driver
From: George McCollister @ 2019-09-09 12:54 UTC (permalink / raw)
To: Marek Vasut
Cc: netdev, Woojung Huh, Andrew Lunn, Florian Fainelli, Tristram Ha,
David S. Miller, open list
In-Reply-To: <b1e98d5e-50b7-1f2f-6874-9515fcf2b540@denx.de>
On Fri, Sep 6, 2019 at 4:42 PM Marek Vasut <marex@denx.de> wrote:
>
> On 9/6/19 11:30 PM, George McCollister wrote:
>
> [...]
>
> > --- /dev/null
> > +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
> > @@ -0,0 +1,100 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Microchip KSZ9477 series register access through I2C
> > + *
> > + * Copyright (C) 2018-2019 Microchip Technology Inc.
>
> Doesn't the copyright need update ?
I figured it wasn't necessary since you didn't update the copyright in
ksz9477_spi.c when you converted it to use regmap and made other
changes.
You're suggesting I add my copyright below this one, correct?
>
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/regmap.h>
> > +#include <linux/i2c.h>
>
> Please keep the headers sorted.
Ack. Moving linux/i2c.h before linux/kernel.h in v2.
>
> > +#include "ksz_common.h"
> > +
> > +KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0);
> > +
>
> The rest looks good.
>
> [...]
>
> --
> Best regards,
> Marek Vasut
^ permalink raw reply
* [PATCH v3 2/2] net: phy: adin: implement Energy Detect Powerdown mode via phy-tunable
From: Alexandru Ardelean @ 2019-09-09 13:12 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190909131251.3634-1-alexandru.ardelean@analog.com>
This driver becomes the first user of the kernel's `ETHTOOL_PHY_EDPD`
phy-tunable feature.
EDPD is also enabled by default on PHY config_init, but can be disabled via
the phy-tunable control.
When enabling EDPD, it's also a good idea (for the ADIN PHYs) to enable TX
periodic pulses, so that in case the other PHY is also on EDPD mode, there
is no lock-up situation where both sides are waiting for the other to
transmit.
Via the phy-tunable control, TX pulses can be disabled if specifying 0
`tx-interval` via ethtool.
The ADIN PHY supports only fixed 1 second intervals; they cannot be
configured. That is why the acceptable values are 1,
ETHTOOL_PHY_EDPD_DFLT_TX_INTERVAL and ETHTOOL_PHY_EDPD_NO_TX (which
disables TX pulses).
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
drivers/net/phy/adin.c | 61 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 4dec83df048d..5f5f73a58122 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -26,6 +26,11 @@
#define ADIN1300_RX_ERR_CNT 0x0014
+#define ADIN1300_PHY_CTRL_STATUS2 0x0015
+#define ADIN1300_NRG_PD_EN BIT(3)
+#define ADIN1300_NRG_PD_TX_EN BIT(2)
+#define ADIN1300_NRG_PD_STATUS BIT(1)
+
#define ADIN1300_PHY_CTRL2 0x0016
#define ADIN1300_DOWNSPEED_AN_100_EN BIT(11)
#define ADIN1300_DOWNSPEED_AN_10_EN BIT(10)
@@ -328,12 +333,62 @@ static int adin_set_downshift(struct phy_device *phydev, u8 cnt)
ADIN1300_DOWNSPEEDS_EN);
}
+static int adin_get_edpd(struct phy_device *phydev, u16 *tx_interval)
+{
+ int val;
+
+ val = phy_read(phydev, ADIN1300_PHY_CTRL_STATUS2);
+ if (val < 0)
+ return val;
+
+ if (ADIN1300_NRG_PD_EN & val) {
+ if (val & ADIN1300_NRG_PD_TX_EN)
+ /* default is 1 second */
+ *tx_interval = ETHTOOL_PHY_EDPD_DFLT_TX_INTERVAL;
+ else
+ *tx_interval = ETHTOOL_PHY_EDPD_NO_TX;
+ } else {
+ *tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
+ }
+
+ return 0;
+}
+
+static int adin_set_edpd(struct phy_device *phydev, u16 tx_interval)
+{
+ u16 val;
+
+ if (tx_interval == ETHTOOL_PHY_EDPD_DISABLE)
+ return phy_clear_bits(phydev, ADIN1300_PHY_CTRL_STATUS2,
+ (ADIN1300_NRG_PD_EN | ADIN1300_NRG_PD_TX_EN));
+
+ val = ADIN1300_NRG_PD_EN;
+
+ switch (tx_interval) {
+ case 1: /* second */
+ /* fallthrough */
+ case ETHTOOL_PHY_EDPD_DFLT_TX_INTERVAL:
+ val |= ADIN1300_NRG_PD_TX_EN;
+ /* fallthrough */
+ case ETHTOOL_PHY_EDPD_NO_TX:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return phy_modify(phydev, ADIN1300_PHY_CTRL_STATUS2,
+ (ADIN1300_NRG_PD_EN | ADIN1300_NRG_PD_TX_EN),
+ val);
+}
+
static int adin_get_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, void *data)
{
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return adin_get_downshift(phydev, data);
+ case ETHTOOL_PHY_EDPD:
+ return adin_get_edpd(phydev, data);
default:
return -EOPNOTSUPP;
}
@@ -345,6 +400,8 @@ static int adin_set_tunable(struct phy_device *phydev,
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return adin_set_downshift(phydev, *(const u8 *)data);
+ case ETHTOOL_PHY_EDPD:
+ return adin_set_edpd(phydev, *(const u16 *)data);
default:
return -EOPNOTSUPP;
}
@@ -368,6 +425,10 @@ static int adin_config_init(struct phy_device *phydev)
if (rc < 0)
return rc;
+ rc = adin_set_edpd(phydev, 1);
+ if (rc < 0)
+ return rc;
+
phydev_dbg(phydev, "PHY is using mode '%s'\n",
phy_modes(phydev->interface));
--
2.20.1
^ permalink raw reply related
* [PATCH v3 1/2] ethtool: implement Energy Detect Powerdown support via phy-tunable
From: Alexandru Ardelean @ 2019-09-09 13:12 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
In-Reply-To: <20190909131251.3634-1-alexandru.ardelean@analog.com>
The `phy_tunable_id` has been named `ETHTOOL_PHY_EDPD` since it looks like
this feature is common across other PHYs (like EEE), and defining
`ETHTOOL_PHY_ENERGY_DETECT_POWER_DOWN` seems too long.
The way EDPD works, is that the RX block is put to a lower power mode,
except for link-pulse detection circuits. The TX block is also put to low
power mode, but the PHY wakes-up periodically to send link pulses, to avoid
lock-ups in case the other side is also in EDPD mode.
Currently, there are 2 PHY drivers that look like they could use this new
PHY tunable feature: the `adin` && `micrel` PHYs.
The ADIN's datasheet mentions that TX pulses are at intervals of 1 second
default each, and they can be disabled. For the Micrel KSZ9031 PHY, the
datasheet does not mention whether they can be disabled, but mentions that
they can modified.
The way this change is structured, is similar to the PHY tunable downshift
control:
* a `ETHTOOL_PHY_EDPD_DFLT_TX_INTERVAL` value is exposed to cover a default
TX interval; some PHYs could specify a certain value that makes sense
* `ETHTOOL_PHY_EDPD_NO_TX` would disable TX when EDPD is enabled
* `ETHTOOL_PHY_EDPD_DISABLE` will disable EDPD
This should allow PHYs to:
* enable EDPD and not enable TX pulses (interval would be 0)
* enable EDPD and configure TX pulse interval; note that TX interval units
would be PHY specific; we could consider `seconds` as units, but it could
happen that some PHYs would be prefer milliseconds as a unit;
a maximum of 65533 units should be sufficient
* disable EDPD
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
include/uapi/linux/ethtool.h | 19 +++++++++++++++++++
net/core/ethtool.c | 6 ++++++
2 files changed, 25 insertions(+)
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index dd06302aa93e..5961b4984cb6 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -259,10 +259,29 @@ struct ethtool_tunable {
#define ETHTOOL_PHY_FAST_LINK_DOWN_ON 0
#define ETHTOOL_PHY_FAST_LINK_DOWN_OFF 0xff
+/* Energy Detect Power Down (EDPD) is a feature supported by some PHYs, where
+ * the PHY's RX & TX blocks are put into a low-power mode when there is no
+ * link detected (typically cable is un-plugged). For RX, only a minimal
+ * link-detection is available, and for TX the PHY wakes up to send link pulses
+ * to avoid any lock-ups in case the peer PHY may also be running in EDPD mode.
+ *
+ * Some PHYs may support configuration of the wake-up interval for TX pulses,
+ * and some PHYs may support only disabling TX pulses entirely. For the latter
+ * a special value is required (ETHTOOL_PHY_EDPD_NO_TX) so that this can be
+ * configured from userspace (should the user want it).
+ *
+ * The interval units for TX wake-up are PHY specific, as some PHYs may require
+ * seconds as intervals, and some would require milliseconds.
+ */
+#define ETHTOOL_PHY_EDPD_DFLT_TX_INTERVAL 0xffff
+#define ETHTOOL_PHY_EDPD_NO_TX 0xfffe
+#define ETHTOOL_PHY_EDPD_DISABLE 0
+
enum phy_tunable_id {
ETHTOOL_PHY_ID_UNSPEC,
ETHTOOL_PHY_DOWNSHIFT,
ETHTOOL_PHY_FAST_LINK_DOWN,
+ ETHTOOL_PHY_EDPD,
/*
* Add your fresh new phy tunable attribute above and remember to update
* phy_tunable_strings[] in net/core/ethtool.c
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6288e69e94fc..c763106c73fc 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -133,6 +133,7 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
[ETHTOOL_ID_UNSPEC] = "Unspec",
[ETHTOOL_PHY_DOWNSHIFT] = "phy-downshift",
[ETHTOOL_PHY_FAST_LINK_DOWN] = "phy-fast-link-down",
+ [ETHTOOL_PHY_EDPD] = "phy-energy-detect-power-down",
};
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
@@ -2451,6 +2452,11 @@ static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna)
tuna->type_id != ETHTOOL_TUNABLE_U8)
return -EINVAL;
break;
+ case ETHTOOL_PHY_EDPD:
+ if (tuna->len != sizeof(u16) ||
+ tuna->type_id != ETHTOOL_TUNABLE_U16)
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v3 0/2] ethtool: implement Energy Detect Powerdown support via phy-tunable
From: Alexandru Ardelean @ 2019-09-09 13:12 UTC (permalink / raw)
To: netdev, devicetree, linux-kernel
Cc: davem, robh+dt, mark.rutland, f.fainelli, hkallweit1, andrew,
Alexandru Ardelean
This changeset proposes a new control for PHY tunable to control Energy
Detect Power Down.
The `phy_tunable_id` has been named `ETHTOOL_PHY_EDPD` since it looks like
this feature is common across other PHYs (like EEE), and defining
`ETHTOOL_PHY_ENERGY_DETECT_POWER_DOWN` seems too long.
The way EDPD works, is that the RX block is put to a lower power mode,
except for link-pulse detection circuits. The TX block is also put to low
power mode, but the PHY wakes-up periodically to send link pulses, to avoid
lock-ups in case the other side is also in EDPD mode.
Currently, there are 2 PHY drivers that look like they could use this new
PHY tunable feature: the `adin` && `micrel` PHYs.
This series updates only the `adin` PHY driver to support this new feature,
as this chip has been tested. A change for `micrel` can be proposed after a
discussion of the PHY-tunable API is resolved.
Alexandru Ardelean (2):
ethtool: implement Energy Detect Powerdown support via phy-tunable
net: phy: adin: implement Energy Detect Powerdown mode via phy-tunable
drivers/net/phy/adin.c | 61 ++++++++++++++++++++++++++++++++++++
include/uapi/linux/ethtool.h | 19 +++++++++++
net/core/ethtool.c | 6 ++++
3 files changed, 86 insertions(+)
--
Changelog v2 -> v3:
* implement Andrew's review comments:
1. for patch `ethtool: implement Energy Detect Powerdown support via
phy-tunable`
- ETHTOOL_PHY_EDPD_DFLT_TX_INTERVAL == 0xffff
- ETHTOOL_PHY_EDPD_NO_TX == 0xfffe
- added comment in include/uapi/linux/ethtool.h
2. for patch `net: phy: adin: implement Energy Detect Powerdown mode via
phy-tunable`
- added comments about interval & units for the ADIN PHY
- in `adin_set_edpd()`: add a switch statement of all the valid values
- in `adin_get_edpd()`: return `ETHTOOL_PHY_EDPD_DFLT_TX_INTERVAL`
since the PHY only supports a single TX-interval value (1 second)
Changelog v1 -> v2:
* initial series was made up of 2 sub-series: 1 for kernel & 1 for ethtool
in userspace; v2 contains only the kernel series
2.20.1
^ permalink raw reply
* Re: [PATCH net-next 2/3] net: dsa: microchip: add ksz9567 to ksz9477 driver
From: George McCollister @ 2019-09-09 13:33 UTC (permalink / raw)
To: Marek Vasut
Cc: netdev, Woojung Huh, Andrew Lunn, Florian Fainelli, Tristram Ha,
David S. Miller, open list
In-Reply-To: <6d8a915f-5f05-c91c-c139-26497376147d@denx.de>
On Fri, Sep 6, 2019 at 4:42 PM Marek Vasut <marex@denx.de> wrote:
>
> On 9/6/19 11:30 PM, George McCollister wrote:
> > Add support for the KSZ9567 7-Port Gigabit Ethernet Switch to the
> > ksz9477 driver. The KSZ9567 supports both SPI and I2C. Oddly the
> > ksz9567 is already in the device tree binding documentation.
> >
> > Signed-off-by: George McCollister <george.mccollister@gmail.com>
> > ---
> > drivers/net/dsa/microchip/ksz9477.c | 9 +++++++++
> > drivers/net/dsa/microchip/ksz9477_i2c.c | 1 +
> > drivers/net/dsa/microchip/ksz9477_spi.c | 1 +
> > 3 files changed, 11 insertions(+)
> >
> > diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
> > index 187be42de5f1..50ffc63d6231 100644
> > --- a/drivers/net/dsa/microchip/ksz9477.c
> > +++ b/drivers/net/dsa/microchip/ksz9477.c
> > @@ -1529,6 +1529,15 @@ static const struct ksz_chip_data ksz9477_switch_chips[] = {
> > .cpu_ports = 0x07, /* can be configured as cpu port */
> > .port_cnt = 3, /* total port count */
> > },
> > + {
> > + .chip_id = 0x00956700,
> > + .dev_name = "KSZ9567",
> > + .num_vlans = 4096,
> > + .num_alus = 4096,
> > + .num_statics = 16,
> > + .cpu_ports = 0x7F, /* can be configured as cpu port */
> > + .port_cnt = 7, /* total physical port count */
>
> I might be wrong, and this is just an idea for future improvement, but
> is .cpu_ports = GEN_MASK(.port_cnt, 0) always ?
GENMASK, not GEN_MASK. And I think it would be .cpu_ports =
GENMASK(.port_cnt - 1, 0).
I'm not sure if it would always be that. TBH I'm not sure if 0x7F is
even correct. For instance if a port has a PHY should it be excluded
from this mask or only if it doesn't support tail tagging? Maybe
someone would hook the CPU port up with a PHY instead of
RGMII/MII/RMII but it seems quite an odd thing to do.
On the KSZ9567R datasheet it shows 1-7 for this so if actually correct
I believe all ports support tail tagging but maybe some other variants
don't:
Port Operation Control 0 Register
Port N: 1-7
Bit 2 - Tail Tag Enable
When tail tagging is enabled for a port, it designates that port to be
the “host” or “CPU” port. Do not enable tail tagging for more than one
port.
My inclination is to leave it as is until a more compelling reason for
changing it arises.
>
> > + },
> > };
> >
> > static int ksz9477_switch_init(struct ksz_device *dev)
> > diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c
> > index 85fd0fb43941..c1548a43b60d 100644
> > --- a/drivers/net/dsa/microchip/ksz9477_i2c.c
> > +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
> > @@ -77,6 +77,7 @@ MODULE_DEVICE_TABLE(i2c, ksz9477_i2c_id);
> > static const struct of_device_id ksz9477_dt_ids[] = {
> > { .compatible = "microchip,ksz9477" },
> > { .compatible = "microchip,ksz9897" },
> > + { .compatible = "microchip,ksz9567" },
> > {},
> > };
> > MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
> > diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c
> > index 2e402e4d866f..f4198d6f72be 100644
> > --- a/drivers/net/dsa/microchip/ksz9477_spi.c
> > +++ b/drivers/net/dsa/microchip/ksz9477_spi.c
> > @@ -81,6 +81,7 @@ static const struct of_device_id ksz9477_dt_ids[] = {
> > { .compatible = "microchip,ksz9893" },
> > { .compatible = "microchip,ksz9563" },
> > { .compatible = "microchip,ksz8563" },
> > + { .compatible = "microchip,ksz9567" },
> > {},
> > };
> > MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
> >
>
> Reviewed-by: Marek Vasut <marex@denx.de>
Thanks.
>
> --
> Best regards,
> Marek Vasut
^ permalink raw reply
* [PATCH net-next 00/11] net: aquantia: PTP support for AQC devices
From: Igor Russkikh @ 2019-09-09 13:38 UTC (permalink / raw)
To: netdev@vger.kernel.org
Cc: richardcochran@gmail.com, davem@davemloft.net, Egor Pomozov,
Sergey Samoilenko, Dmitry Bezrukov, Igor Russkikh
This patches introduce PTP feature support in Aquantia AQC atlantic driver.
This implementation is a joined effort from a number of aquantia developers:
Egor and Sergey are included as co-developers, Dmitry has implemented
PIN control functionality and helped me in the overall patchset preparation.
Feature was verified on AQC hardware with testptp tool, linuxptp,
gptp and with Motu hardware unit.
Dmitry Bezrukov (11):
net: aquantia: PTP skeleton declarations and callbacks
net: aquantia: unify styling of bit enums
net: aquantia: add basic ptp_clock callbacks
net: aquantia: add PTP rings infrastructure
net: aquantia: styling fixes on ptp related functions
net: aquantia: implement data PTP datapath
net: aquantia: rx filters for ptp
net: aquantia: add support for ptp ioctls
net: aquantia: implement get_ts_info ethtool
net: aquantia: add support for Phy access
net: aquantia: add support for PIN funcs
.../net/ethernet/aquantia/atlantic/Makefile | 2 +
.../net/ethernet/aquantia/atlantic/aq_cfg.h | 4 +-
.../ethernet/aquantia/atlantic/aq_ethtool.c | 35 +-
.../ethernet/aquantia/atlantic/aq_filters.c | 17 +-
.../net/ethernet/aquantia/atlantic/aq_hw.h | 45 +-
.../net/ethernet/aquantia/atlantic/aq_main.c | 103 +-
.../net/ethernet/aquantia/atlantic/aq_nic.c | 96 +-
.../net/ethernet/aquantia/atlantic/aq_nic.h | 16 +-
.../ethernet/aquantia/atlantic/aq_pci_func.c | 5 +-
.../net/ethernet/aquantia/atlantic/aq_phy.c | 147 ++
.../net/ethernet/aquantia/atlantic/aq_phy.h | 32 +
.../net/ethernet/aquantia/atlantic/aq_ptp.c | 1396 +++++++++++++++++
.../net/ethernet/aquantia/atlantic/aq_ptp.h | 57 +
.../net/ethernet/aquantia/atlantic/aq_ring.c | 63 +-
.../net/ethernet/aquantia/atlantic/aq_ring.h | 7 +-
.../aquantia/atlantic/hw_atl/hw_atl_b0.c | 318 +++-
.../atlantic/hw_atl/hw_atl_b0_internal.h | 9 +-
.../aquantia/atlantic/hw_atl/hw_atl_llh.c | 96 +-
.../aquantia/atlantic/hw_atl/hw_atl_llh.h | 58 +-
.../atlantic/hw_atl/hw_atl_llh_internal.h | 223 ++-
.../aquantia/atlantic/hw_atl/hw_atl_utils.c | 7 +-
.../aquantia/atlantic/hw_atl/hw_atl_utils.h | 172 +-
.../atlantic/hw_atl/hw_atl_utils_fw2x.c | 97 +-
23 files changed, 2871 insertions(+), 134 deletions(-)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_phy.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_phy.h
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
--
2.17.1
^ permalink raw reply
* [PATCH net-next 01/11] net: aquantia: PTP skeleton declarations and callbacks
From: Igor Russkikh @ 2019-09-09 13:38 UTC (permalink / raw)
To: netdev@vger.kernel.org
Cc: richardcochran@gmail.com, davem@davemloft.net, Egor Pomozov,
Sergey Samoilenko, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1568034880.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Here we add basic function for PTP clock register/unregister.
We also declare FW/HW capability bits used to control PTP feature
on device.
PTP device is created if network card has appropriate FW that has PTP
enabled in config. HW supports timestamping for PTPv2 802.AS1 and
PTPv2 IPv4 UDP packets.
It also supports basic PTP callbacks for getting/setting time, adjusting
frequency and time as well.
Co-developed-by: Egor Pomozov <egor.pomozov@aquantia.com>
Signed-off-by: Egor Pomozov <egor.pomozov@aquantia.com>
Co-developed-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
.../net/ethernet/aquantia/atlantic/Makefile | 1 +
.../net/ethernet/aquantia/atlantic/aq_nic.c | 10 +-
.../net/ethernet/aquantia/atlantic/aq_nic.h | 5 +-
.../net/ethernet/aquantia/atlantic/aq_ptp.c | 93 +++++++++++++++++++
.../net/ethernet/aquantia/atlantic/aq_ptp.h | 22 +++++
.../aquantia/atlantic/hw_atl/hw_atl_utils.h | 85 ++++++++++++++++-
6 files changed, 210 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile
index 131cab855be7..cd12d9d824ec 100644
--- a/drivers/net/ethernet/aquantia/atlantic/Makefile
+++ b/drivers/net/ethernet/aquantia/atlantic/Makefile
@@ -24,6 +24,7 @@ atlantic-objs := aq_main.o \
aq_ethtool.o \
aq_drvinfo.o \
aq_filters.o \
+ aq_ptp.o \
hw_atl/hw_atl_a0.o \
hw_atl/hw_atl_b0.o \
hw_atl/hw_atl_utils.o \
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 8f66e7817811..8721d43fd129 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File aq_nic.c: Definition of common code for NIC. */
@@ -12,6 +12,7 @@
#include "aq_hw.h"
#include "aq_pci_func.h"
#include "aq_main.h"
+#include "aq_ptp.h"
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
@@ -331,6 +332,10 @@ int aq_nic_init(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_init(aq_vec, self->aq_hw_ops, self->aq_hw);
+ err = aq_ptp_init(self, self->irqvecs - 1);
+ if (err < 0)
+ goto err_exit;
+
netif_carrier_off(self->ndev);
err_exit:
@@ -970,6 +975,9 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec);
+ aq_ptp_unregister(self);
+ aq_ptp_free(self);
+
if (likely(self->aq_fw_ops->deinit)) {
mutex_lock(&self->fwreq_mutex);
self->aq_fw_ops->deinit(self->aq_hw);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index 255b54a6ae07..d0979bba7ed3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File aq_nic.h: Declaration of common code for NIC. */
@@ -17,6 +17,7 @@ struct aq_ring_s;
struct aq_hw_ops;
struct aq_fw_s;
struct aq_vec_s;
+struct aq_ptp_s;
struct aq_nic_cfg_s {
const struct aq_hw_caps_s *aq_hw_caps;
@@ -108,6 +109,8 @@ struct aq_nic_s {
u32 irqvecs;
/* mutex to serialize FW interface access operations */
struct mutex fwreq_mutex;
+ /* PTP support */
+ struct aq_ptp_s *aq_ptp;
struct aq_hw_rx_fltrs_s aq_hw_rx_fltrs;
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
new file mode 100644
index 000000000000..c6cdcdc1a6aa
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2019 Aquantia Corporation. All rights reserved
+ */
+
+/* File aq_ptp.c:
+ * Definition of functions for Linux PTP support.
+ */
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/clocksource.h>
+
+#include "aq_nic.h"
+#include "aq_ptp.h"
+
+struct aq_ptp_s {
+ struct aq_nic_s *aq_nic;
+
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_info;
+};
+
+static struct ptp_clock_info aq_ptp_clock = {
+ .owner = THIS_MODULE,
+ .name = "atlantic ptp",
+ .n_ext_ts = 0,
+ .pps = 0,
+ .n_per_out = 0,
+ .n_pins = 0,
+ .pin_config = NULL,
+};
+
+int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
+{
+ struct hw_atl_utils_mbox mbox;
+ struct ptp_clock *clock;
+ struct aq_ptp_s *self;
+ int err = 0;
+
+ hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox);
+
+ if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) {
+ aq_nic->aq_ptp = NULL;
+ return 0;
+ }
+
+ self = kzalloc(sizeof(*self), GFP_KERNEL);
+ if (!self) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+ self->aq_nic = aq_nic;
+
+ self->ptp_info = aq_ptp_clock;
+ clock = ptp_clock_register(&self->ptp_info, &aq_nic->ndev->dev);
+ if (!clock) {
+ netdev_err(aq_nic->ndev, "ptp_clock_register failed\n");
+ err = 0;
+ goto err_exit;
+ }
+ self->ptp_clock = clock;
+
+ aq_nic->aq_ptp = self;
+
+ return 0;
+
+err_exit:
+ kfree(self);
+ aq_nic->aq_ptp = NULL;
+ return err;
+}
+
+void aq_ptp_unregister(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+
+ if (!self)
+ return;
+
+ ptp_clock_unregister(self->ptp_clock);
+}
+
+void aq_ptp_free(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+
+ if (!self)
+ return;
+
+ kfree(self);
+ aq_nic->aq_ptp = NULL;
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
new file mode 100644
index 000000000000..cea238959b20
--- /dev/null
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Aquantia Corporation Network Driver
+ * Copyright (C) 2014-2019 Aquantia Corporation. All rights reserved
+ */
+
+/* File aq_ptp.h: Declaration of PTP functions.
+ */
+#ifndef AQ_PTP_H
+#define AQ_PTP_H
+
+#include <linux/net_tstamp.h>
+#include <linux/version.h>
+
+/* Common functions */
+int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec);
+
+void aq_ptp_unregister(struct aq_nic_s *aq_nic);
+void aq_ptp_free(struct aq_nic_s *aq_nic);
+
+void aq_ptp_clock_init(struct aq_nic_s *aq_nic);
+
+#endif /* AQ_PTP_H */
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
index 692bed70e104..7121248954df 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_utils.h: Declaration of common functions for Atlantic hardware
@@ -168,6 +168,34 @@ struct __packed hw_atl_utils_mbox_header {
u32 error;
};
+struct __packed hw_aq_ptp_offset {
+ u16 ingress_100;
+ u16 egress_100;
+ u16 ingress_1000;
+ u16 egress_1000;
+ u16 ingress_2500;
+ u16 egress_2500;
+ u16 ingress_5000;
+ u16 egress_5000;
+ u16 ingress_10000;
+ u16 egress_10000;
+};
+
+enum gpio_pin_function {
+ GPIO_PIN_FUNCTION_NC,
+ GPIO_PIN_FUNCTION_VAUX_ENABLE,
+ GPIO_PIN_FUNCTION_EFUSE_BURN_ENABLE,
+ GPIO_PIN_FUNCTION_SFP_PLUS_DETECT,
+ GPIO_PIN_FUNCTION_TX_DISABLE,
+ GPIO_PIN_FUNCTION_RATE_SEL_0,
+ GPIO_PIN_FUNCTION_RATE_SEL_1,
+ GPIO_PIN_FUNCTION_TX_FAULT,
+ GPIO_PIN_FUNCTION_PTP0,
+ GPIO_PIN_FUNCTION_PTP1,
+ GPIO_PIN_FUNCTION_PTP2,
+ GPIO_PIN_FUNCTION_SIZE
+};
+
struct __packed hw_aq_info {
u8 reserved[6];
u16 phy_fault_code;
@@ -175,9 +203,23 @@ struct __packed hw_aq_info {
u8 cable_len;
u8 reserved1;
u32 cable_diag_data[4];
- u8 reserved2[32];
+ struct hw_aq_ptp_offset ptp_offset;
+ u8 reserved2[12];
u32 caps_lo;
u32 caps_hi;
+ u32 reserved_datapath;
+ u32 reserved3[7];
+ u32 reserved_simpleresp[3];
+ u32 reserved_linkstat[7];
+ u32 reserved_wakes_count;
+ u32 reserved_eee_stat[12];
+ u32 tx_stuck_cnt;
+ u32 setting_address;
+ u32 setting_length;
+ u32 caps_ex;
+ enum gpio_pin_function gpio_pin[3];
+ u32 pcie_aer_dump[18];
+ u16 snr_margin[4];
};
struct __packed hw_atl_utils_mbox {
@@ -372,7 +414,7 @@ enum hw_atl_fw2x_caps_hi {
CAPS_HI_2P5GBASET_FD_EEE,
CAPS_HI_5GBASET_FD_EEE,
CAPS_HI_10GBASET_FD_EEE,
- CAPS_HI_RESERVED5,
+ CAPS_HI_FW_REQUEST,
CAPS_HI_RESERVED6,
CAPS_HI_RESERVED7,
CAPS_HI_RESERVED8,
@@ -380,7 +422,7 @@ enum hw_atl_fw2x_caps_hi {
CAPS_HI_CABLE_DIAG,
CAPS_HI_TEMPERATURE,
CAPS_HI_DOWNSHIFT,
- CAPS_HI_PTP_AVB_EN,
+ CAPS_HI_PTP_AVB_EN_FW2X = 20,
CAPS_HI_MEDIA_DETECT,
CAPS_HI_LINK_DROP,
CAPS_HI_SLEEP_PROXY,
@@ -429,6 +471,41 @@ enum hw_atl_fw2x_ctrl {
CTRL_FORCE_RECONNECT,
};
+enum hw_atl_caps_ex {
+ CAPS_EX_LED_CONTROL = 0,
+ CAPS_EX_LED0_MODE_LO,
+ CAPS_EX_LED0_MODE_HI,
+ CAPS_EX_LED1_MODE_LO,
+ CAPS_EX_LED1_MODE_HI,
+ CAPS_EX_LED2_MODE_LO = 5,
+ CAPS_EX_LED2_MODE_HI,
+ CAPS_EX_RESERVED07,
+ CAPS_EX_RESERVED08,
+ CAPS_EX_RESERVED09,
+ CAPS_EX_RESERVED10 = 10,
+ CAPS_EX_RESERVED11,
+ CAPS_EX_RESERVED12,
+ CAPS_EX_RESERVED13,
+ CAPS_EX_RESERVED14,
+ CAPS_EX_RESERVED15 = 15,
+ CAPS_EX_PHY_PTP_EN,
+ CAPS_EX_MAC_PTP_EN,
+ CAPS_EX_EXT_CLK_EN,
+ CAPS_EX_SCHED_DMA_EN,
+ CAPS_EX_PTP_GPIO_EN = 20,
+ CAPS_EX_UPDATE_SETTINGS,
+ CAPS_EX_PHY_CTRL_TS_PIN,
+ CAPS_EX_SNR_OPERATING_MARGIN,
+ CAPS_EX_RESERVED24,
+ CAPS_EX_RESERVED25 = 25,
+ CAPS_EX_RESERVED26,
+ CAPS_EX_RESERVED27,
+ CAPS_EX_RESERVED28,
+ CAPS_EX_RESERVED29,
+ CAPS_EX_RESERVED30 = 30,
+ CAPS_EX_RESERVED31
+};
+
struct aq_hw_s;
struct aq_fw_ops;
struct aq_hw_caps_s;
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 02/11] net: aquantia: unify styling of bit enums
From: Igor Russkikh @ 2019-09-09 13:38 UTC (permalink / raw)
To: netdev@vger.kernel.org
Cc: richardcochran@gmail.com, davem@davemloft.net, Egor Pomozov,
Sergey Samoilenko, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1568034880.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Make some other bit-enums more clear about positioning,
this helps on debugging and development
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
.../aquantia/atlantic/hw_atl/hw_atl_utils.c | 2 +-
.../aquantia/atlantic/hw_atl/hw_atl_utils.h | 41 +++++++++++--------
2 files changed, 26 insertions(+), 17 deletions(-)
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
index 52646855495e..32512539ae86 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
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
index 7121248954df..766e02c7fd4e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -386,38 +386,44 @@ enum hw_atl_fw2x_rate {
FW2X_RATE_10G = 0x800,
};
+/* 0x370
+ * Link capabilities resolution register
+ */
enum hw_atl_fw2x_caps_lo {
- CAPS_LO_10BASET_HD = 0x00,
+ CAPS_LO_10BASET_HD = 0,
CAPS_LO_10BASET_FD,
CAPS_LO_100BASETX_HD,
CAPS_LO_100BASET4_HD,
CAPS_LO_100BASET2_HD,
- CAPS_LO_100BASETX_FD,
+ CAPS_LO_100BASETX_FD = 5,
CAPS_LO_100BASET2_FD,
CAPS_LO_1000BASET_HD,
CAPS_LO_1000BASET_FD,
CAPS_LO_2P5GBASET_FD,
- CAPS_LO_5GBASET_FD,
+ CAPS_LO_5GBASET_FD = 10,
CAPS_LO_10GBASET_FD,
};
+/* 0x374
+ * Status register
+ */
enum hw_atl_fw2x_caps_hi {
- CAPS_HI_RESERVED1 = 0x00,
+ CAPS_HI_RESERVED1 = 0,
CAPS_HI_10BASET_EEE,
CAPS_HI_RESERVED2,
CAPS_HI_PAUSE,
CAPS_HI_ASYMMETRIC_PAUSE,
- CAPS_HI_100BASETX_EEE,
+ CAPS_HI_100BASETX_EEE = 5,
CAPS_HI_RESERVED3,
CAPS_HI_RESERVED4,
CAPS_HI_1000BASET_FD_EEE,
CAPS_HI_2P5GBASET_FD_EEE,
- CAPS_HI_5GBASET_FD_EEE,
+ CAPS_HI_5GBASET_FD_EEE = 10,
CAPS_HI_10GBASET_FD_EEE,
CAPS_HI_FW_REQUEST,
CAPS_HI_RESERVED6,
CAPS_HI_RESERVED7,
- CAPS_HI_RESERVED8,
+ CAPS_HI_RESERVED8 = 15,
CAPS_HI_RESERVED9,
CAPS_HI_CABLE_DIAG,
CAPS_HI_TEMPERATURE,
@@ -427,47 +433,50 @@ enum hw_atl_fw2x_caps_hi {
CAPS_HI_LINK_DROP,
CAPS_HI_SLEEP_PROXY,
CAPS_HI_WOL,
- CAPS_HI_MAC_STOP,
+ CAPS_HI_MAC_STOP = 25,
CAPS_HI_EXT_LOOPBACK,
CAPS_HI_INT_LOOPBACK,
CAPS_HI_EFUSE_AGENT,
CAPS_HI_WOL_TIMER,
- CAPS_HI_STATISTICS,
+ CAPS_HI_STATISTICS = 30,
CAPS_HI_TRANSACTION_ID,
};
+/* 0x36C
+ * Control register
+ */
enum hw_atl_fw2x_ctrl {
- CTRL_RESERVED1 = 0x00,
+ CTRL_RESERVED1 = 0,
CTRL_RESERVED2,
CTRL_RESERVED3,
CTRL_PAUSE,
CTRL_ASYMMETRIC_PAUSE,
- CTRL_RESERVED4,
+ CTRL_RESERVED4 = 5,
CTRL_RESERVED5,
CTRL_RESERVED6,
CTRL_1GBASET_FD_EEE,
CTRL_2P5GBASET_FD_EEE,
- CTRL_5GBASET_FD_EEE,
+ CTRL_5GBASET_FD_EEE = 10,
CTRL_10GBASET_FD_EEE,
CTRL_THERMAL_SHUTDOWN,
CTRL_PHY_LOGS,
CTRL_EEE_AUTO_DISABLE,
- CTRL_PFC,
+ CTRL_PFC = 15,
CTRL_WAKE_ON_LINK,
CTRL_CABLE_DIAG,
CTRL_TEMPERATURE,
CTRL_DOWNSHIFT,
- CTRL_PTP_AVB,
+ CTRL_PTP_AVB = 20,
CTRL_RESERVED7,
CTRL_LINK_DROP,
CTRL_SLEEP_PROXY,
CTRL_WOL,
- CTRL_MAC_STOP,
+ CTRL_MAC_STOP = 25,
CTRL_EXT_LOOPBACK,
CTRL_INT_LOOPBACK,
CTRL_RESERVED8,
CTRL_WOL_TIMER,
- CTRL_STATISTICS,
+ CTRL_STATISTICS = 30,
CTRL_FORCE_RECONNECT,
};
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 03/11] net: aquantia: add basic ptp_clock callbacks
From: Igor Russkikh @ 2019-09-09 13:38 UTC (permalink / raw)
To: netdev@vger.kernel.org
Cc: richardcochran@gmail.com, davem@davemloft.net, Egor Pomozov,
Sergey Samoilenko, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1568034880.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Basic HW functions implemented for adjusting frequency, adjusting time,
getting and setting time.
Firmware interface for PTP requests and interactions.
Enable/disable PTP counters in HW on clock register/unregister
Co-developed-by: Egor Pomozov <egor.pomozov@aquantia.com>
Signed-off-by: Egor Pomozov <egor.pomozov@aquantia.com>
Co-developed-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
.../net/ethernet/aquantia/atlantic/aq_hw.h | 20 ++-
.../net/ethernet/aquantia/atlantic/aq_nic.c | 3 +
.../net/ethernet/aquantia/atlantic/aq_ptp.c | 116 ++++++++++++++++++
.../aquantia/atlantic/hw_atl/hw_atl_b0.c | 102 ++++++++++++++-
.../aquantia/atlantic/hw_atl/hw_atl_llh.c | 16 ++-
.../aquantia/atlantic/hw_atl/hw_atl_llh.h | 8 +-
.../atlantic/hw_atl/hw_atl_llh_internal.h | 18 ++-
.../aquantia/atlantic/hw_atl/hw_atl_utils.c | 5 +-
.../aquantia/atlantic/hw_atl/hw_atl_utils.h | 30 +++++
.../atlantic/hw_atl/hw_atl_utils_fw2x.c | 97 +++++++++++----
10 files changed, 385 insertions(+), 30 deletions(-)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 53d7478689a0..20f032ad41e1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File aq_hw.h: Declaration of abstract interface for NIC hardware specific
@@ -15,6 +15,9 @@
#include "aq_rss.h"
#include "hw_atl/hw_atl_utils.h"
+#define AQ_HW_MAC_COUNTER_HZ 312500000ll
+#define AQ_HW_PHY_COUNTER_HZ 160000000ll
+
#define AQ_RX_FIRST_LOC_FVLANID 0U
#define AQ_RX_LAST_LOC_FVLANID 15U
#define AQ_RX_FIRST_LOC_FETHERT 16U
@@ -94,6 +97,7 @@ struct aq_stats_s {
#define AQ_HW_FLAG_STOPPING 0x00000008U
#define AQ_HW_FLAG_RESETTING 0x00000010U
#define AQ_HW_FLAG_CLOSING 0x00000020U
+#define AQ_HW_PTP_AVAILABLE 0x01000000U
#define AQ_HW_LINK_DOWN 0x04000000U
#define AQ_HW_FLAG_ERR_UNPLUG 0x40000000U
#define AQ_HW_FLAG_ERR_HW 0x80000000U
@@ -235,6 +239,14 @@ struct aq_hw_ops {
int (*hw_set_offload)(struct aq_hw_s *self,
struct aq_nic_cfg_s *aq_nic_cfg);
+ void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp);
+
+ int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta);
+
+ int (*hw_adj_sys_clock)(struct aq_hw_s *self, s64 delta);
+
+ int (*hw_set_sys_clock)(struct aq_hw_s *self, u64 time, u64 ts);
+
int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc);
};
@@ -267,6 +279,12 @@ struct aq_fw_ops {
int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
u8 *mac);
+ int (*send_fw_request)(struct aq_hw_s *self,
+ const struct hw_fw_request_iface *fw_req,
+ size_t size);
+
+ void (*enable_ptp)(struct aq_hw_s *self, int enable);
+
int (*set_eee_rate)(struct aq_hw_s *self, u32 speed);
int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 8721d43fd129..8e01de6f22e3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -146,6 +146,9 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
self->aq_hw->aq_link_status.mbps);
aq_nic_update_interrupt_moderation_settings(self);
+ if (self->aq_ptp)
+ aq_ptp_clock_init(self);
+
/* Driver has to update flow control settings on RX block
* on any link event.
* We should query FW whether it negotiated FC.
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
index c6cdcdc1a6aa..0133745a89d0 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
@@ -16,15 +16,107 @@
struct aq_ptp_s {
struct aq_nic_s *aq_nic;
+ spinlock_t ptp_lock;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_info;
};
+/* aq_ptp_adjfreq
+ * @ptp: the ptp clock structure
+ * @ppb: parts per billion adjustment from base
+ *
+ * adjust the frequency of the ptp cycle counter by the
+ * indicated ppb from the base frequency.
+ */
+static int aq_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct aq_ptp_s *self = container_of(ptp, struct aq_ptp_s, ptp_info);
+ struct aq_nic_s *aq_nic = self->aq_nic;
+
+ mutex_lock(&aq_nic->fwreq_mutex);
+ aq_nic->aq_hw_ops->hw_adj_clock_freq(aq_nic->aq_hw, ppb);
+ mutex_unlock(&aq_nic->fwreq_mutex);
+
+ return 0;
+}
+
+/* aq_ptp_adjtime
+ * @ptp: the ptp clock structure
+ * @delta: offset to adjust the cycle counter by
+ *
+ * adjust the timer by resetting the timecounter structure.
+ */
+static int aq_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct aq_ptp_s *self = container_of(ptp, struct aq_ptp_s, ptp_info);
+ struct aq_nic_s *aq_nic = self->aq_nic;
+ unsigned long flags;
+
+ spin_lock_irqsave(&self->ptp_lock, flags);
+ aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, delta);
+ spin_unlock_irqrestore(&self->ptp_lock, flags);
+
+ return 0;
+}
+
+/* aq_ptp_gettime
+ * @ptp: the ptp clock structure
+ * @ts: timespec structure to hold the current time value
+ *
+ * read the timecounter and return the correct value on ns,
+ * after converting it into a struct timespec.
+ */
+static int aq_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
+{
+ struct aq_ptp_s *self = container_of(ptp, struct aq_ptp_s, ptp_info);
+ struct aq_nic_s *aq_nic = self->aq_nic;
+ unsigned long flags;
+ u64 ns;
+
+ spin_lock_irqsave(&self->ptp_lock, flags);
+ aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &ns);
+ spin_unlock_irqrestore(&self->ptp_lock, flags);
+
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+/* aq_ptp_settime
+ * @ptp: the ptp clock structure
+ * @ts: the timespec containing the new time for the cycle counter
+ *
+ * reset the timecounter to use a new base value instead of the kernel
+ * wall timer value.
+ */
+static int aq_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct aq_ptp_s *self = container_of(ptp, struct aq_ptp_s, ptp_info);
+ struct aq_nic_s *aq_nic = self->aq_nic;
+ unsigned long flags;
+ u64 ns = timespec64_to_ns(ts);
+ u64 now;
+
+ spin_lock_irqsave(&self->ptp_lock, flags);
+ aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &now);
+ aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, (s64)ns - (s64)now);
+
+ spin_unlock_irqrestore(&self->ptp_lock, flags);
+
+ return 0;
+}
+
static struct ptp_clock_info aq_ptp_clock = {
.owner = THIS_MODULE,
.name = "atlantic ptp",
+ .max_adj = 999999999,
.n_ext_ts = 0,
.pps = 0,
+ .adjfreq = aq_ptp_adjfreq,
+ .adjtime = aq_ptp_adjtime,
+ .gettime64 = aq_ptp_gettime,
+ .settime64 = aq_ptp_settime,
.n_per_out = 0,
.n_pins = 0,
.pin_config = NULL,
@@ -37,6 +129,16 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
struct aq_ptp_s *self;
int err = 0;
+ if (!aq_nic->aq_hw_ops->hw_get_ptp_ts) {
+ aq_nic->aq_ptp = NULL;
+ return 0;
+ }
+
+ if (!aq_nic->aq_fw_ops->enable_ptp) {
+ aq_nic->aq_ptp = NULL;
+ return 0;
+ }
+
hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox);
if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) {
@@ -52,6 +154,8 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
self->aq_nic = aq_nic;
+ spin_lock_init(&self->ptp_lock);
+
self->ptp_info = aq_ptp_clock;
clock = ptp_clock_register(&self->ptp_info, &aq_nic->ndev->dev);
if (!clock) {
@@ -63,6 +167,13 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
aq_nic->aq_ptp = self;
+ /* enable ptp counter */
+ aq_utils_obj_set(&aq_nic->aq_hw->flags, AQ_HW_PTP_AVAILABLE);
+ mutex_lock(&aq_nic->fwreq_mutex);
+ aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 1);
+ aq_ptp_clock_init(aq_nic);
+ mutex_unlock(&aq_nic->fwreq_mutex);
+
return 0;
err_exit:
@@ -88,6 +199,11 @@ void aq_ptp_free(struct aq_nic_s *aq_nic)
if (!self)
return;
+ /* disable ptp */
+ mutex_lock(&aq_nic->fwreq_mutex);
+ aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0);
+ mutex_unlock(&aq_nic->fwreq_mutex);
+
kfree(self);
aq_nic->aq_ptp = NULL;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 30f7fc4c97ff..f3550fbb1c59 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_b0.c: Definition of Atlantic hardware specific functions. */
@@ -86,6 +86,8 @@ const struct aq_hw_caps_s hw_atl_b0_caps_aqc109 = {
AQ_NIC_RATE_100M,
};
+static s64 ptp_clk_offset;
+
static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
{
int err = 0;
@@ -992,6 +994,96 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self,
return aq_hw_err_from_flags(self);
}
+#define get_ptp_ts_val_u64(self, indx) \
+ ((u64)(hw_atl_pcs_ptp_clock_get(self, indx) & 0xffff))
+
+static void hw_atl_b0_get_ptp_ts(struct aq_hw_s *self, u64 *stamp)
+{
+ u64 ns;
+
+ hw_atl_pcs_ptp_clock_read_enable(self, 1);
+ hw_atl_pcs_ptp_clock_read_enable(self, 0);
+ ns = (get_ptp_ts_val_u64(self, 0) +
+ (get_ptp_ts_val_u64(self, 1) << 16)) * 1000000000llu +
+ (get_ptp_ts_val_u64(self, 3) +
+ (get_ptp_ts_val_u64(self, 4) << 16));
+
+ *stamp = ns + ptp_clk_offset;
+}
+
+static void hw_atl_b0_adj_params_get(u64 freq, s64 adj, u32 *ns, u32 *fns)
+{
+ /* For accuracy, the digit is extended */
+ s64 divisor = 0, base_ns = ((adj + 1000000000ll) * 1000000000ll) / freq;
+ u32 nsi_frac = 0, nsi = base_ns / 1000000000ll;
+
+ if (base_ns != nsi * 1000000000ll) {
+ divisor = 1000000000000000000ll /
+ (base_ns - nsi * 1000000000ll);
+ nsi_frac = 0x100000000ll * 1000000000ll / divisor;
+ }
+
+ *ns = nsi;
+ *fns = nsi_frac;
+}
+
+static void
+hw_atl_b0_mac_adj_param_calc(struct hw_fw_request_ptp_adj_freq *ptp_adj_freq,
+ u64 phyfreq, u64 macfreq)
+{
+ s64 fns_in_sec_phy = phyfreq * (ptp_adj_freq->fns_phy +
+ 0x100000000ll * ptp_adj_freq->ns_phy);
+ s64 fns_in_sec_mac = macfreq * (ptp_adj_freq->fns_mac +
+ 0x100000000ll * ptp_adj_freq->ns_mac);
+ s64 fault_in_sec_phy = 0x100000000ll * 1000000000ll - fns_in_sec_phy;
+ s64 fault_in_sec_mac = 0x100000000ll * 1000000000ll - fns_in_sec_mac;
+ /* MAC MCP counter freq is macfreq / 4 */
+ s64 diff_in_mcp_overflow = (fault_in_sec_mac - fault_in_sec_phy) *
+ 0x400000000ll / AQ_HW_MAC_COUNTER_HZ;
+ s64 adj_fns_val = (ptp_adj_freq->fns_mac + 0x100000000ll *
+ ptp_adj_freq->ns_mac) + diff_in_mcp_overflow;
+
+ ptp_adj_freq->mac_ns_adj = adj_fns_val / 0x100000000ll;
+ ptp_adj_freq->mac_fns_adj = adj_fns_val - ptp_adj_freq->mac_ns_adj *
+ 0x100000000ll;
+}
+
+static int hw_atl_b0_adj_sys_clock(struct aq_hw_s *self, s64 delta)
+{
+ ptp_clk_offset += delta;
+
+ return 0;
+}
+
+static int hw_atl_b0_set_sys_clock(struct aq_hw_s *self, u64 time, u64 ts)
+{
+ s64 delta = time - (ptp_clk_offset + ts);
+
+ return hw_atl_b0_adj_sys_clock(self, delta);
+}
+
+static int hw_atl_b0_adj_clock_freq(struct aq_hw_s *self, s32 ppb)
+{
+ struct hw_fw_request_iface fwreq;
+ size_t size;
+
+ memset(&fwreq, 0, sizeof(fwreq));
+
+ fwreq.msg_id = HW_AQ_FW_REQUEST_PTP_ADJ_FREQ;
+ hw_atl_b0_adj_params_get(AQ_HW_MAC_COUNTER_HZ, ppb,
+ &fwreq.ptp_adj_freq.ns_mac,
+ &fwreq.ptp_adj_freq.fns_mac);
+ hw_atl_b0_adj_params_get(AQ_HW_PHY_COUNTER_HZ, ppb,
+ &fwreq.ptp_adj_freq.ns_phy,
+ &fwreq.ptp_adj_freq.fns_phy);
+ hw_atl_b0_mac_adj_param_calc(&fwreq.ptp_adj_freq,
+ AQ_HW_PHY_COUNTER_HZ,
+ AQ_HW_MAC_COUNTER_HZ);
+
+ size = sizeof(fwreq.msg_id) + sizeof(fwreq.ptp_adj_freq);
+ return self->aq_fw_ops->send_fw_request(self, &fwreq, size);
+}
+
static int hw_atl_b0_hw_fl3l4_clear(struct aq_hw_s *self,
struct aq_rx_filter_l3l4 *data)
{
@@ -1164,6 +1256,12 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
- .hw_set_offload = hw_atl_b0_hw_offload_set,
+
+ .hw_get_ptp_ts = hw_atl_b0_get_ptp_ts,
+ .hw_adj_sys_clock = hw_atl_b0_adj_sys_clock,
+ .hw_set_sys_clock = hw_atl_b0_set_sys_clock,
+ .hw_adj_clock_freq = hw_atl_b0_adj_clock_freq,
+
+ .hw_set_offload = hw_atl_b0_hw_offload_set,
.hw_set_fc = hw_atl_b0_set_fc,
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 1149812ae463..25e7261f6a44 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_llh.c: Definitions of bitfield and register access functions for
@@ -1513,6 +1513,20 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw,
glb_cpu_scratch_scp);
}
+void hw_atl_pcs_ptp_clock_read_enable(struct aq_hw_s *aq_hw,
+ u32 ptp_clock_read_enable)
+{
+ aq_hw_write_reg_bit(aq_hw, HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR,
+ HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSK,
+ HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT,
+ ptp_clock_read_enable);
+}
+
+u32 hw_atl_pcs_ptp_clock_get(struct aq_hw_s *aq_hw, u32 index)
+{
+ return aq_hw_read_reg(aq_hw, HW_ATL_PCS_PTP_TS_VAL_ADDR(index));
+}
+
void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index 0c37abbabca5..a62693e51a6b 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_llh.h: Declarations of bitfield and register access functions for
@@ -712,6 +712,12 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe);
/* set pci register reset disable */
void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis);
+/* pcs */
+void hw_atl_pcs_ptp_clock_read_enable(struct aq_hw_s *aq_hw,
+ u32 ptp_clock_read_enable);
+
+u32 hw_atl_pcs_ptp_clock_get(struct aq_hw_s *aq_hw, u32 index);
+
/* set uP Force Interrupt */
void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
index c3febcdfa92e..7716e0fc22b5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_llh_internal.h: Preprocessor definitions
@@ -2421,6 +2421,22 @@
/* default value of bitfield register write strobe */
#define HW_ATL_MSM_REG_WR_STROBE_DEFAULT 0x0
+/* register address for bitfield PTP Digital Clock Read Enable */
+#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR 0x00004628
+/* bitmask for bitfield PTP Digital Clock Read Enable */
+#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSK 0x00000010
+/* inverted bitmask for bitfield PTP Digital Clock Read Enable */
+#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSKN 0xFFFFFFEF
+/* lower bit position of bitfield PTP Digital Clock Read Enable */
+#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT 4
+/* width of bitfield PTP Digital Clock Read Enable */
+#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_WIDTH 1
+/* default value of bitfield PTP Digital Clock Read Enable */
+#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_DEFAULT 0x0
+
+/* register address for ptp counter reading */
+#define HW_ATL_PCS_PTP_TS_VAL_ADDR(index) (0x00004900 + (index) * 0x4)
+
/* mif soft reset bitfield definitions
* preprocessor definitions for the bitfield "soft reset".
* port="pif_glb_res_i"
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
index 32512539ae86..6fc5640065bd 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -327,8 +327,7 @@ int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
return err;
}
-static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
- u32 cnt)
+int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt)
{
u32 val;
int err = 0;
@@ -964,4 +963,6 @@ const struct aq_fw_ops aq_fw_1x_ops = {
.set_eee_rate = NULL,
.get_eee_rate = NULL,
.set_flow_control = NULL,
+ .send_fw_request = NULL,
+ .enable_ptp = NULL,
};
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
index 766e02c7fd4e..f2eb94f298e2 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -279,6 +279,34 @@ struct __packed offload_info {
u8 buf[0];
};
+/* Mailbox FW Request interface */
+struct __packed hw_fw_request_ptp_adj_freq {
+ u32 ns_mac;
+ u32 fns_mac;
+ u32 ns_phy;
+ u32 fns_phy;
+ u32 mac_ns_adj;
+ u32 mac_fns_adj;
+};
+
+struct __packed hw_fw_request_ptp_adj_clock {
+ u32 ns;
+ u32 sec;
+ int sign;
+};
+
+#define HW_AQ_FW_REQUEST_PTP_ADJ_FREQ 0x12
+#define HW_AQ_FW_REQUEST_PTP_ADJ_CLOCK 0x13
+
+struct __packed hw_fw_request_iface {
+ u32 msg_id;
+ union {
+ /* PTP FW Request */
+ struct hw_fw_request_ptp_adj_freq ptp_adj_freq;
+ struct hw_fw_request_ptp_adj_clock ptp_adj_clock;
+ };
+};
+
enum hw_atl_rx_action_with_traffic {
HW_ATL_RX_DISCARD,
HW_ATL_RX_HOST,
@@ -561,6 +589,8 @@ struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self);
int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
u32 *p, u32 cnt);
+int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt);
+
int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac);
int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index da726489e3c8..8b9824b1dc5e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
@@ -17,14 +17,17 @@
#include "hw_atl_utils.h"
#include "hw_atl_llh.h"
-#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334
+#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334
-#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360
-#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364
-#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368
-#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C
-#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370
-#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374
+#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360
+#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364
+#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368
+#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C
+#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370
+#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374
+
+#define HW_ATL_FW3X_EXT_CONTROL_ADDR 0x378
+#define HW_ATL_FW3X_EXT_STATE_ADDR 0x37c
#define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE)
#define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE)
@@ -444,6 +447,54 @@ static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
return err;
}
+static int aq_fw2x_send_fw_request(struct aq_hw_s *self,
+ const struct hw_fw_request_iface *fw_req,
+ size_t size)
+{
+ u32 ctrl2, orig_ctrl2;
+ u32 dword_cnt;
+ int err = 0;
+ u32 val;
+
+ /* Write data to drvIface Mailbox */
+ dword_cnt = size / sizeof(u32);
+ if (size % sizeof(u32))
+ dword_cnt++;
+ err = hw_atl_utils_fw_upload_dwords(self, aq_fw2x_rpc_get(self),
+ (void *)fw_req, dword_cnt);
+ if (err < 0)
+ goto err_exit;
+
+ /* Toggle statistics bit for FW to update */
+ ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+ orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST);
+ ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST);
+ aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2);
+
+ /* Wait FW to report back */
+ err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
+ orig_ctrl2 != (val &
+ BIT(CAPS_HI_FW_REQUEST)),
+ 1U, 10000U);
+
+err_exit:
+ return err;
+}
+
+static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable)
+{
+ u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR);
+ u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) |
+ BIT(CAPS_EX_PTP_GPIO_EN);
+
+ if (enable)
+ ptp_opts |= all_ptp_features;
+ else
+ ptp_opts &= ~all_ptp_features;
+
+ aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts);
+}
+
static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
@@ -534,19 +585,21 @@ static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
}
const struct aq_fw_ops aq_fw_2x_ops = {
- .init = aq_fw2x_init,
- .deinit = aq_fw2x_deinit,
- .reset = NULL,
- .renegotiate = aq_fw2x_renegotiate,
- .get_mac_permanent = aq_fw2x_get_mac_permanent,
- .set_link_speed = aq_fw2x_set_link_speed,
- .set_state = aq_fw2x_set_state,
+ .init = aq_fw2x_init,
+ .deinit = aq_fw2x_deinit,
+ .reset = NULL,
+ .renegotiate = aq_fw2x_renegotiate,
+ .get_mac_permanent = aq_fw2x_get_mac_permanent,
+ .set_link_speed = aq_fw2x_set_link_speed,
+ .set_state = aq_fw2x_set_state,
.update_link_status = aq_fw2x_update_link_status,
- .update_stats = aq_fw2x_update_stats,
- .get_phy_temp = aq_fw2x_get_phy_temp,
- .set_power = aq_fw2x_set_power,
- .set_eee_rate = aq_fw2x_set_eee_rate,
- .get_eee_rate = aq_fw2x_get_eee_rate,
- .set_flow_control = aq_fw2x_set_flow_control,
- .get_flow_control = aq_fw2x_get_flow_control
+ .update_stats = aq_fw2x_update_stats,
+ .get_phy_temp = aq_fw2x_get_phy_temp,
+ .set_power = aq_fw2x_set_power,
+ .set_eee_rate = aq_fw2x_set_eee_rate,
+ .get_eee_rate = aq_fw2x_get_eee_rate,
+ .set_flow_control = aq_fw2x_set_flow_control,
+ .get_flow_control = aq_fw2x_get_flow_control,
+ .send_fw_request = aq_fw2x_send_fw_request,
+ .enable_ptp = aq_fw3x_enable_ptp,
};
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 04/11] net: aquantia: add PTP rings infrastructure
From: Igor Russkikh @ 2019-09-09 13:38 UTC (permalink / raw)
To: netdev@vger.kernel.org
Cc: richardcochran@gmail.com, davem@davemloft.net, Egor Pomozov,
Sergey Samoilenko, Dmitry Bezrukov, Igor Russkikh
In-Reply-To: <cover.1568034880.git.igor.russkikh@aquantia.com>
From: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Add implementations of PTP rings alloc/free.
PTP desing on this device uses two separate rings on a separate traffic
class for traffic rx/tx.
Third ring (hwts) is not a traffic ring, but is used only to receive timestamps
of the transmitted packets.
Co-developed-by: Egor Pomozov <egor.pomozov@aquantia.com>
Signed-off-by: Egor Pomozov <egor.pomozov@aquantia.com>
Co-developed-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
---
.../net/ethernet/aquantia/atlantic/aq_hw.h | 4 +
.../net/ethernet/aquantia/atlantic/aq_nic.c | 16 ++
.../net/ethernet/aquantia/atlantic/aq_ptp.c | 231 ++++++++++++++++++
.../net/ethernet/aquantia/atlantic/aq_ptp.h | 8 +
.../net/ethernet/aquantia/atlantic/aq_ring.c | 33 ++-
.../net/ethernet/aquantia/atlantic/aq_ring.h | 6 +-
.../aquantia/atlantic/hw_atl/hw_atl_b0.c | 45 +++-
.../atlantic/hw_atl/hw_atl_b0_internal.h | 9 +-
.../aquantia/atlantic/hw_atl/hw_atl_llh.c | 14 ++
.../aquantia/atlantic/hw_atl/hw_atl_llh.h | 6 +
.../aquantia/atlantic/hw_atl/hw_atl_utils.h | 8 +
11 files changed, 368 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 20f032ad41e1..677453794ee8 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -239,6 +239,10 @@ struct aq_hw_ops {
int (*hw_set_offload)(struct aq_hw_s *self,
struct aq_nic_cfg_s *aq_nic_cfg);
+ int (*hw_tx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode);
+
+ int (*hw_rx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode);
+
void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp);
int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 8e01de6f22e3..87357755a72d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -339,6 +339,14 @@ int aq_nic_init(struct aq_nic_s *self)
if (err < 0)
goto err_exit;
+ err = aq_ptp_ring_alloc(self);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_ptp_ring_init(self);
+ if (err < 0)
+ goto err_exit;
+
netif_carrier_off(self->ndev);
err_exit:
@@ -369,6 +377,10 @@ int aq_nic_start(struct aq_nic_s *self)
goto err_exit;
}
+ err = aq_ptp_ring_start(self);
+ if (err < 0)
+ goto err_exit;
+
err = self->aq_hw_ops->hw_start(self->aq_hw);
if (err < 0)
goto err_exit;
@@ -963,6 +975,8 @@ int aq_nic_stop(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_stop(aq_vec);
+ aq_ptp_ring_stop(self);
+
return self->aq_hw_ops->hw_stop(self->aq_hw);
}
@@ -978,7 +992,9 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec);
+ aq_ptp_ring_deinit(self);
aq_ptp_unregister(self);
+ aq_ptp_ring_free(self);
aq_ptp_free(self);
if (likely(self->aq_fw_ops->deinit)) {
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
index 0133745a89d0..7305073c3845 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
@@ -12,15 +12,56 @@
#include "aq_nic.h"
#include "aq_ptp.h"
+#include "aq_ring.h"
+
+struct ptp_skb_ring {
+ struct sk_buff **buff;
+ spinlock_t lock;
+ unsigned int size;
+ unsigned int head;
+ unsigned int tail;
+};
struct aq_ptp_s {
struct aq_nic_s *aq_nic;
spinlock_t ptp_lock;
+ spinlock_t ptp_ring_lock;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_info;
+
+ struct aq_ring_param_s ptp_ring_param;
+
+ struct aq_ring_s ptp_tx;
+ struct aq_ring_s ptp_rx;
+ struct aq_ring_s hwts_rx;
+
+ struct ptp_skb_ring skb_ring;
};
+static int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size)
+{
+ struct sk_buff **buff = kmalloc(sizeof(*buff) * size, GFP_KERNEL);
+
+ if (!buff)
+ return -ENOMEM;
+
+ spin_lock_init(&ring->lock);
+
+ ring->buff = buff;
+ ring->size = size;
+ ring->head = 0;
+ ring->tail = 0;
+
+ return 0;
+}
+
+static void aq_ptp_skb_ring_release(struct ptp_skb_ring *ring)
+{
+ kfree(ring->buff);
+ ring->buff = NULL;
+}
+
/* aq_ptp_adjfreq
* @ptp: the ptp clock structure
* @ppb: parts per billion adjustment from base
@@ -107,6 +148,186 @@ static int aq_ptp_settime(struct ptp_clock_info *ptp,
return 0;
}
+int aq_ptp_ring_init(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+ int err = 0;
+
+ if (!self)
+ return 0;
+
+ err = aq_ring_init(&self->ptp_tx);
+ if (err < 0)
+ goto err_exit;
+ err = aq_nic->aq_hw_ops->hw_ring_tx_init(aq_nic->aq_hw,
+ &self->ptp_tx,
+ &self->ptp_ring_param);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_ring_init(&self->ptp_rx);
+ if (err < 0)
+ goto err_exit;
+ err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
+ &self->ptp_rx,
+ &self->ptp_ring_param);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_ring_rx_fill(&self->ptp_rx);
+ if (err < 0)
+ goto err_exit;
+ err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw,
+ &self->ptp_rx,
+ 0U);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_ring_init(&self->hwts_rx);
+ if (err < 0)
+ goto err_exit;
+ err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
+ &self->hwts_rx,
+ &self->ptp_ring_param);
+
+err_exit:
+ return err;
+}
+
+int aq_ptp_ring_start(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+ int err = 0;
+
+ if (!self)
+ return 0;
+
+ err = aq_nic->aq_hw_ops->hw_ring_tx_start(aq_nic->aq_hw, &self->ptp_tx);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, &self->ptp_rx);
+ if (err < 0)
+ goto err_exit;
+
+ err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw,
+ &self->hwts_rx);
+ if (err < 0)
+ goto err_exit;
+
+err_exit:
+ return err;
+}
+
+void aq_ptp_ring_stop(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+
+ if (!self)
+ return;
+
+ aq_nic->aq_hw_ops->hw_ring_tx_stop(aq_nic->aq_hw, &self->ptp_tx);
+ aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &self->ptp_rx);
+
+ aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &self->hwts_rx);
+}
+
+void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+
+ if (!self || !self->ptp_tx.aq_nic || !self->ptp_rx.aq_nic)
+ return;
+
+ aq_ring_tx_clean(&self->ptp_tx);
+ aq_ring_rx_deinit(&self->ptp_rx);
+}
+
+#define PTP_8TC_RING_IDX 8
+#define PTP_4TC_RING_IDX 16
+#define PTP_HWST_RING_IDX 31
+
+int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+ unsigned int tx_ring_idx, rx_ring_idx;
+ struct aq_ring_s *hwts = 0;
+ u32 tx_tc_mode, rx_tc_mode;
+ struct aq_ring_s *ring;
+ int err;
+
+ if (!self)
+ return 0;
+
+ /* Index must to be 8 (8 TCs) or 16 (4 TCs).
+ * It depends from Traffic Class mode.
+ */
+ aq_nic->aq_hw_ops->hw_tx_tc_mode_get(aq_nic->aq_hw, &tx_tc_mode);
+ if (tx_tc_mode == 0)
+ tx_ring_idx = PTP_8TC_RING_IDX;
+ else
+ tx_ring_idx = PTP_4TC_RING_IDX;
+
+ ring = aq_ring_tx_alloc(&self->ptp_tx, aq_nic,
+ tx_ring_idx, &aq_nic->aq_nic_cfg);
+ if (!ring) {
+ err = -ENOMEM;
+ goto err_exit_1;
+ }
+
+ aq_nic->aq_hw_ops->hw_rx_tc_mode_get(aq_nic->aq_hw, &rx_tc_mode);
+ if (rx_tc_mode == 0)
+ rx_ring_idx = PTP_8TC_RING_IDX;
+ else
+ rx_ring_idx = PTP_4TC_RING_IDX;
+
+ ring = aq_ring_rx_alloc(&self->ptp_rx, aq_nic,
+ rx_ring_idx, &aq_nic->aq_nic_cfg);
+ if (!ring) {
+ err = -ENOMEM;
+ goto err_exit_2;
+ }
+
+ hwts = aq_ring_hwts_rx_alloc(&self->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
+ aq_nic->aq_nic_cfg.rxds,
+ aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
+ if (!hwts) {
+ err = -ENOMEM;
+ goto err_exit_3;
+ }
+
+ err = aq_ptp_skb_ring_init(&self->skb_ring, aq_nic->aq_nic_cfg.rxds);
+ if (err != 0) {
+ err = -ENOMEM;
+ goto err_exit_4;
+ }
+
+ return 0;
+
+err_exit_4:
+ aq_ring_free(&self->hwts_rx);
+err_exit_3:
+ aq_ring_free(&self->ptp_rx);
+err_exit_2:
+ aq_ring_free(&self->ptp_tx);
+err_exit_1:
+ return err;
+}
+
+void aq_ptp_ring_free(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+
+ if (!self)
+ return;
+
+ aq_ring_free(&self->ptp_tx);
+ aq_ring_free(&self->ptp_rx);
+ aq_ring_free(&self->hwts_rx);
+
+ aq_ptp_skb_ring_release(&self->skb_ring);
+}
+
static struct ptp_clock_info aq_ptp_clock = {
.owner = THIS_MODULE,
.name = "atlantic ptp",
@@ -122,6 +343,15 @@ static struct ptp_clock_info aq_ptp_clock = {
.pin_config = NULL,
};
+void aq_ptp_clock_init(struct aq_nic_s *aq_nic)
+{
+ struct aq_ptp_s *self = aq_nic->aq_ptp;
+ struct timespec64 ts;
+
+ ktime_get_real_ts64(&ts);
+ aq_ptp_settime(&self->ptp_info, &ts);
+}
+
int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
{
struct hw_atl_utils_mbox mbox;
@@ -155,6 +385,7 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
self->aq_nic = aq_nic;
spin_lock_init(&self->ptp_lock);
+ spin_lock_init(&self->ptp_ring_lock);
self->ptp_info = aq_ptp_clock;
clock = ptp_clock_register(&self->ptp_info, &aq_nic->ndev->dev);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
index cea238959b20..32350f75e138 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
@@ -17,6 +17,14 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec);
void aq_ptp_unregister(struct aq_nic_s *aq_nic);
void aq_ptp_free(struct aq_nic_s *aq_nic);
+int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic);
+void aq_ptp_ring_free(struct aq_nic_s *aq_nic);
+
+int aq_ptp_ring_init(struct aq_nic_s *aq_nic);
+int aq_ptp_ring_start(struct aq_nic_s *aq_nic);
+void aq_ptp_ring_stop(struct aq_nic_s *aq_nic);
+void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic);
+
void aq_ptp_clock_init(struct aq_nic_s *aq_nic);
#endif /* AQ_PTP_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index 3901d7994ca1..6d57928f8a37 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File aq_ring.c: Definition of functions for Rx/Tx rings. */
@@ -177,6 +177,37 @@ struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
return self;
}
+struct aq_ring_s *
+aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
+ unsigned int idx, unsigned int size, unsigned int dx_size)
+{
+ struct device *dev = aq_nic_get_dev(aq_nic);
+ int err = 0;
+ size_t sz = size * dx_size + AQ_CFG_RXDS_DEF;
+
+ memset(self, 0, sizeof(*self));
+
+ self->aq_nic = aq_nic;
+ self->idx = idx;
+ self->size = size;
+ self->dx_size = dx_size;
+
+ self->dx_ring = dma_alloc_coherent(dev, sz, &self->dx_ring_pa,
+ GFP_KERNEL);
+ if (!self->dx_ring) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+err_exit:
+ if (err < 0) {
+ aq_ring_free(self);
+ return NULL;
+ }
+
+ return self;
+}
+
int aq_ring_init(struct aq_ring_s *self)
{
self->hw_head = 0;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
index 47abd09d06c2..068689f44bc9 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File aq_ring.h: Declaration of functions for Rx/Tx rings. */
@@ -174,4 +174,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
int budget);
int aq_ring_rx_fill(struct aq_ring_s *self);
+struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic, unsigned int idx,
+ unsigned int size, unsigned int dx_size);
+
#endif /* AQ_RING_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index f3550fbb1c59..0e92db5c56fa 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -126,13 +126,16 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U);
hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, 0U);
- hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, 0U);
- hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, 0U);
- hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, 0U);
- hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, 0U);
+ tc = 0;
+
+ /* TX Packet Scheduler Data TC0 */
+ hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, tc);
+ hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, tc);
+ hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, tc);
+ hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, tc);
- /* Tx buf size */
- buff_size = HW_ATL_B0_TXBUF_MAX;
+ /* Tx buf size TC0 */
+ buff_size = HW_ATL_B0_TXBUF_MAX - HW_ATL_B0_PTP_TXBUF_SIZE;
hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, buff_size, tc);
hw_atl_tpb_tx_buff_hi_threshold_per_tc_set(self,
@@ -143,10 +146,15 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
(buff_size *
(1024 / 32U) * 50U) /
100U, tc);
+ /* Init TC2 for PTP_TX */
+ tc = 2;
+
+ hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, HW_ATL_B0_PTP_TXBUF_SIZE,
+ tc);
/* QoS Rx buf size per TC */
tc = 0;
- buff_size = HW_ATL_B0_RXBUF_MAX;
+ buff_size = HW_ATL_B0_RXBUF_MAX - HW_ATL_B0_PTP_RXBUF_SIZE;
hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc);
hw_atl_rpb_rx_buff_hi_threshold_per_tc_set(self,
@@ -160,6 +168,14 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
hw_atl_b0_set_fc(self, self->aq_nic_cfg->flow_control, tc);
+ /* Init TC2 for PTP_RX */
+ tc = 2;
+
+ hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, HW_ATL_B0_PTP_RXBUF_SIZE,
+ tc);
+ /* No flow control for PTP */
+ hw_atl_rpb_rx_xoff_en_per_tc_set(self, 0U, tc);
+
/* QoS 802.1p priority -> TC mapping */
for (i_priority = 8U; i_priority--;)
hw_atl_rpf_rpb_user_priority_tc_map_set(self, i_priority, 0U);
@@ -994,6 +1010,18 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self,
return aq_hw_err_from_flags(self);
}
+static int hw_atl_b0_tx_tc_mode_get(struct aq_hw_s *self, u32 *tc_mode)
+{
+ *tc_mode = hw_atl_rpb_tps_tx_tc_mode_get(self);
+ return aq_hw_err_from_flags(self);
+}
+
+static int hw_atl_b0_rx_tc_mode_get(struct aq_hw_s *self, u32 *tc_mode)
+{
+ *tc_mode = hw_atl_rpb_rpf_rx_traf_class_mode_get(self);
+ return aq_hw_err_from_flags(self);
+}
+
#define get_ptp_ts_val_u64(self, indx) \
((u64)(hw_atl_pcs_ptp_clock_get(self, indx) & 0xffff))
@@ -1257,6 +1285,9 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
+ .hw_tx_tc_mode_get = hw_atl_b0_tx_tc_mode_get,
+ .hw_rx_tc_mode_get = hw_atl_b0_rx_tc_mode_get,
+
.hw_get_ptp_ts = hw_atl_b0_get_ptp_ts,
.hw_adj_sys_clock = hw_atl_b0_adj_sys_clock,
.hw_set_sys_clock = hw_atl_b0_set_sys_clock,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
index 808d8cd4252a..7ab23a1751d3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
- * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
+ * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/
/* File hw_atl_b0_internal.h: Definition of Atlantic B0 chip specific
@@ -64,8 +64,11 @@
#define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU
#define HW_ATL_B0_MPI_SPEED_SHIFT 16U
-#define HW_ATL_B0_TXBUF_MAX 160U
-#define HW_ATL_B0_RXBUF_MAX 320U
+#define HW_ATL_B0_TXBUF_MAX 160U
+#define HW_ATL_B0_PTP_TXBUF_SIZE 8U
+
+#define HW_ATL_B0_RXBUF_MAX 320U
+#define HW_ATL_B0_PTP_RXBUF_SIZE 16U
#define HW_ATL_B0_RSS_REDIRECTION_MAX 64U
#define HW_ATL_B0_RSS_REDIRECTION_BITS 3U
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 25e7261f6a44..e3c5e2b30c09 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -572,6 +572,13 @@ void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw,
rx_traf_class_mode);
}
+u32 hw_atl_rpb_rpf_rx_traf_class_mode_get(struct aq_hw_s *aq_hw)
+{
+ return aq_hw_read_reg_bit(aq_hw, HW_ATL_RPB_RPF_RX_TC_MODE_ADR,
+ HW_ATL_RPB_RPF_RX_TC_MODE_MSK,
+ HW_ATL_RPB_RPF_RX_TC_MODE_SHIFT);
+}
+
void hw_atl_rpb_rx_buff_en_set(struct aq_hw_s *aq_hw, u32 rx_buff_en)
{
aq_hw_write_reg_bit(aq_hw, HW_ATL_RPB_RX_BUF_EN_ADR,
@@ -1277,6 +1284,13 @@ void hw_atl_tpb_tx_buff_en_set(struct aq_hw_s *aq_hw, u32 tx_buff_en)
HW_ATL_TPB_TX_BUF_EN_SHIFT, tx_buff_en);
}
+u32 hw_atl_rpb_tps_tx_tc_mode_get(struct aq_hw_s *aq_hw)
+{
+ return aq_hw_read_reg_bit(aq_hw, HW_ATL_TPB_TX_TC_MODE_ADDR,
+ HW_ATL_TPB_TX_TC_MODE_MSK,
+ HW_ATL_TPB_TX_TC_MODE_SHIFT);
+}
+
void hw_atl_rpb_tps_tx_tc_mode_set(struct aq_hw_s *aq_hw,
u32 tx_traf_class_mode)
{
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index a62693e51a6b..d5042cc7ffeb 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -292,6 +292,9 @@ void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk);
void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw,
u32 rx_traf_class_mode);
+/* get rx traffic class mode */
+u32 hw_atl_rpb_rpf_rx_traf_class_mode_get(struct aq_hw_s *aq_hw);
+
/* set rx buffer enable */
void hw_atl_rpb_rx_buff_en_set(struct aq_hw_s *aq_hw, u32 rx_buff_en);
@@ -602,6 +605,9 @@ void hw_atl_thm_lso_tcp_flag_of_middle_pkt_set(struct aq_hw_s *aq_hw,
void hw_atl_rpb_tps_tx_tc_mode_set(struct aq_hw_s *aq_hw,
u32 tx_traf_class_mode);
+/* get TX Traffic Class Mode */
+u32 hw_atl_rpb_tps_tx_tc_mode_get(struct aq_hw_s *aq_hw);
+
/* set tx buffer enable */
void hw_atl_tpb_tx_buff_en_set(struct aq_hw_s *aq_hw, u32 tx_buff_en);
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
index f2eb94f298e2..77132bda4696 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -44,6 +44,14 @@ struct __packed hw_atl_rxd_wb_s {
u16 vlan;
};
+/* Hardware rx HW TIMESTAMP writeback */
+struct __packed hw_atl_rxd_hwts_wb_s {
+ u32 sec_hw;
+ u32 ns;
+ u32 sec_lw0;
+ u32 sec_lw1;
+};
+
struct __packed hw_atl_stats_s {
u32 uprc;
u32 mprc;
--
2.17.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox