* Re: [PATCH net-next 1/2] net: phy: broadcom: set features explicitly for BCM54616S
From: Andrew Lunn @ 2019-07-30 3:35 UTC (permalink / raw)
To: Tao Ren
Cc: Florian Fainelli, Heiner Kallweit, David S . Miller,
Arun Parameswaran, Justin Chen, Vladimir Oltean, netdev,
linux-kernel, Andrew Jeffery, openbmc
In-Reply-To: <20190730002532.85509-1-taoren@fb.com>
On Mon, Jul 29, 2019 at 05:25:32PM -0700, Tao Ren wrote:
> BCM54616S feature "PHY_GBIT_FEATURES" was removed by commit dcdecdcfe1fc
> ("net: phy: switch drivers to use dynamic feature detection"). As dynamic
> feature detection doesn't work when BCM54616S is working in RGMII-Fiber
> mode (different sets of MII Control/Status registers being used), let's
> set "PHY_GBIT_FEATURES" for BCM54616S explicitly.
Hi Tao
What exactly does it get wrong?
Thanks
Andrew
^ permalink raw reply
* Re: [PATCH] net: phy: phy_led_triggers: Fix a possible null-pointer dereference in phy_led_trigger_change_speed()
From: Andrew Lunn @ 2019-07-30 3:32 UTC (permalink / raw)
To: Jia-Ju Bai; +Cc: f.fainelli, hkallweit1, davem, netdev, linux-kernel
In-Reply-To: <f603f3c3-f7c9-8dff-5f30-74174282819c@gmail.com>
On Tue, Jul 30, 2019 at 10:25:36AM +0800, Jia-Ju Bai wrote:
>
>
> On 2019/7/29 21:45, Andrew Lunn wrote:
> >On Mon, Jul 29, 2019 at 05:24:24PM +0800, Jia-Ju Bai wrote:
> >>In phy_led_trigger_change_speed(), there is an if statement on line 48
> >>to check whether phy->last_triggered is NULL:
> >> if (!phy->last_triggered)
> >>
> >>When phy->last_triggered is NULL, it is used on line 52:
> >> led_trigger_event(&phy->last_triggered->trigger, LED_OFF);
> >>
> >>Thus, a possible null-pointer dereference may occur.
> >>
> >>To fix this bug, led_trigger_event(&phy->last_triggered->trigger,
> >>LED_OFF) is called when phy->last_triggered is not NULL.
> >>
> >>This bug is found by a static analysis tool STCheck written by us.
> >Who is 'us'?
>
> Me and my colleague...
Well, we can leave it very vague, giving no idea who 'us' is. But
often you want to name the company behind it, or the university, or
the sponsor, etc.
Andrew
^ permalink raw reply
* RE: [PATCH] rtw88: pci: Use general byte arrays as the elements of RX ring
From: Tony Chuang @ 2019-07-30 3:11 UTC (permalink / raw)
To: Jian-Hong Pan, David Laight
Cc: Kalle Valo, David S . Miller, linux-wireless@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux@endlessm.com, stable@vger.kernel.org
In-Reply-To: <CAPpJ_eey7+KCMFj2YVQD8ziWR_xf-==k9MYb49-32Z5E6vTdHA@mail.gmail.com>
> > > > While allocating all 512 buffers in one block (just over 4MB)
> > > > is probably not a good idea, you may need to allocated (and dma map)
> > > > then in groups.
> > >
> > > Thanks for reviewing. But got questions here to double confirm the
> idea.
> > > According to original code, it allocates 512 skbs for RX ring and dma
> > > mapping one by one. So, the new code allocates memory buffer 512
> > > times to get 512 buffer arrays. Will the 512 buffers arrays be in one
> > > block? Do you mean aggregate the buffers as a scatterlist and use
> > > dma_map_sg?
> >
> > If you malloc a buffer of size (8192+32) the allocator will either
> > round it up to a whole number of (often 4k) pages or to a power of
> > 2 of pages - so either 12k of 16k.
> > I think the Linux allocator does the latter.
> > Some of the allocators also 'steal' a bit from the front of the buffer
> > for 'red tape'.
> >
> > OTOH malloc the space 15 buffers and the allocator will round the
> > 15*(8192 + 32) up to 32*4k - and you waste under 8k across all the
> > buffers.
> >
> > You then dma_map the large buffer and split into the actual rx buffers.
> > Repeat until you've filled the entire ring.
> > The only complication is remembering the base address (and size) for
> > the dma_unmap and free.
> > Although there is plenty of padding to extend the buffer structure
> > significantly without using more memory.
> > Allocate in 15's and you (probably) have 512 bytes per buffer.
> > Allocate in 31's and you have 256 bytes.
> >
> > The problem is that larger allocates are more likely to fail
> > (especially if the system has been running for some time).
> > So you almost certainly want to be able to fall back to smaller
> > allocates even though they use more memory.
> >
> > I also wonder if you actually need 512 8k rx buffers to cover
> > interrupt latency?
> > I've not done any measurements for 20 years!
>
> Thanks for the explanation.
> I am not sure the combination of 512 8k RX buffers. Maybe Realtek
> folks can give us some idea.
> Tony Chuang any comment?
>
> Jian-Hong Pan
>
512 RX buffers is not necessary I think. But I haven't had a chance to
test if reduce the number of RX SKBs could affect the latency.
I can run some throughput tests and then decide a minimum numbers
that RX ring requires. Or if you can try it.
Thanks.
Yan-Hsuan
^ permalink raw reply
* Re: [PATCH v3] net: dsa: qca8k: enable port flow control
From: xiaofeis @ 2019-07-30 3:01 UTC (permalink / raw)
To: Andrew Lunn
Cc: davem, vkoul, netdev, linux-arm-msm, bjorn.andersson,
vivien.didelot, f.fainelli, niklas.cassel, xiazha
In-Reply-To: <20190729132342.GA4110@lunn.ch>
On 2019-07-29 21:23, Andrew Lunn wrote:
>> But our qca8k HW can auto sync the pause status to MAC from phy with
>> the
>> auto-negotiated result.
>> So no need to set in qca8k_adjust_link, since there is one setting in
>> qca8k_port_set_status: mask |= QCA8K_PORT_STATUS_LINK_AUTO;
>
> How does the auto-sync actually work? Does the MAC make MDIO reads to
> the PHY? That is generally unsafe, since some PHYs support pages, and
> the PHY driver might be using a different page while the MAC tries to
> access the auto-neg results.
>
> Do any of the ports support an external PHY? The auto-sync might not
> work in that condition as well. Different register layout, c45 not
> c22, etc.
>
> The safest option is to explicitly set the MAC flow configuration
> based on the values in phydev.
>
Hi Andrew
To explicitly set the configuration is one option, but then we need
disable QCA8K_PORT_STATUS_LINK_AUTO, and not only flow control,
speed/duplex all need to be set explicitly.
Here the qca8k driver is only support qca,qca8337/qca8334 switch family.
The phy is internal phy. There is signals internaly
to sync the status from phy to mac directly which is HW specific
implementation, it doesn't support to connect external phy.
Thanks
Xiaofeis
^ permalink raw reply
* [PATCH V2] can: flexcan: fix deadlock when using self wakeup
From: Joakim Zhang @ 2019-07-30 2:51 UTC (permalink / raw)
To: mkl@pengutronix.de, linux-can@vger.kernel.org, sean@geanix.com
Cc: wg@grandegger.com, netdev@vger.kernel.org, dl-linux-imx,
Joakim Zhang
As reproted by Sean Nyekjaer below:
When suspending, when there is still can traffic on the interfaces the
flexcan immediately wakes the platform again. As it should :-). But it
throws this error msg:
[ 3169.378661] PM: noirq suspend of devices failed
On the way down to suspend the interface that throws the error message does
call flexcan_suspend but fails to call flexcan_noirq_suspend. That means the
flexcan_enter_stop_mode is called, but on the way out of suspend the driver
only calls flexcan_resume and skips flexcan_noirq_resume, thus it doesn't call
flexcan_exit_stop_mode. This leaves the flexcan in stop mode, and with the
current driver it can't recover from this even with a soft reboot, it requires
a hard reboot.
The best way to exit stop mode is in Wake Up interrupt context, and then
suspend() and resume() functions can be symmetric. However, stop mode
request and ack will be controlled by SCU(System Control Unit) firmware(manage
clock,power,stop mode, etc. by Cortex-M4 core) in coming i.MX8(QM/QXP). And SCU
firmware interface can't be available in interrupt context.
For compatibillity, the wake up mechanism can't be symmetric, so we need
in_stop_mode hack.
Fixes: de3578c198c6 ("can: flexcan: add self wakeup support")
Reported-by: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Changelog:
V1->V2:
* add Reported-by tag.
* rebase on patch: can:flexcan:fix stop mode acknowledgment.
---
drivers/net/can/flexcan.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index fcec8bcb53d6..1dbec868d3ea 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -282,6 +282,7 @@ struct flexcan_priv {
const struct flexcan_devtype_data *devtype_data;
struct regulator *reg_xceiver;
struct flexcan_stop_mode stm;
+ bool in_stop_mode;
/* Read and Write APIs */
u32 (*read)(void __iomem *addr);
@@ -1635,6 +1636,8 @@ static int __maybe_unused flexcan_suspend(struct device *device)
err = flexcan_enter_stop_mode(priv);
if (err)
return err;
+
+ priv->in_stop_mode = true;
} else {
err = flexcan_chip_disable(priv);
if (err)
@@ -1659,6 +1662,15 @@ static int __maybe_unused flexcan_resume(struct device *device)
netif_device_attach(dev);
netif_start_queue(dev);
if (device_may_wakeup(device)) {
+ if (priv->in_stop_mode) {
+ flexcan_enable_wakeup_irq(priv, false);
+ err = flexcan_exit_stop_mode(priv);
+ if (err)
+ return err;
+
+ priv->in_stop_mode = false;
+ }
+
disable_irq_wake(dev->irq);
} else {
err = flexcan_chip_enable(priv);
@@ -1674,6 +1686,11 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device)
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
+ /* Need to enable wakeup interrupt in noirq suspend stage. Otherwise,
+ * it will trigger continuously wakeup interrupt if the wakeup event
+ * comes before noirq suspend stage, and simultaneously it has enter
+ * the stop mode.
+ */
if (netif_running(dev) && device_may_wakeup(device))
flexcan_enable_wakeup_irq(priv, true);
@@ -1686,11 +1703,17 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
struct flexcan_priv *priv = netdev_priv(dev);
int err;
+ /* Need to exit stop mode in noirq resume stage. Otherwise, it will
+ * trigger continuously wakeup interrupt if the wakeup event comes,
+ * and simultaneously it has still in stop mode.
+ */
if (netif_running(dev) && device_may_wakeup(device)) {
flexcan_enable_wakeup_irq(priv, false);
err = flexcan_exit_stop_mode(priv);
if (err)
return err;
+
+ priv->in_stop_mode = false;
}
return 0;
--
2.17.1
^ permalink raw reply related
* [PATCH v2] Fix typo reigster to register
From: Pei-Hsuan Hung @ 2019-07-30 2:42 UTC (permalink / raw)
Cc: Pei-Hsuan Hung, trivial, Russell Currey, Sam Bobroff,
Oliver O'Halloran, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Jeremy Kerr, Arnd Bergmann, MyungJoo Ham,
Chanwoo Choi, Liviu Dudau, Brian Starkey, David Airlie,
Daniel Vetter, Ping-Ke Shih, Kalle Valo, David S. Miller,
James Smart, Dick Kennedy, James E.J. Bottomley,
Martin K. Petersen, Alexander Viro, Larry Finger, linuxppc-dev,
linux-kernel, dri-devel, linux-wireless, netdev, linux-scsi,
linux-fsdevel
Signed-off-by: Pei-Hsuan Hung <afcidk@gmail.com>
Acked-by: Liviu Dudau <liviu.dudau@arm.com>
Cc: trivial@kernel.org
---
Hi Liviu, thanks for your reply.
This patch is generated by a script so at first I didn't notice there is
also a typo in the word coefficient. I've fixed the typo in this
version.
arch/powerpc/kernel/eeh.c | 2 +-
arch/powerpc/platforms/cell/spufs/switch.c | 4 ++--
drivers/extcon/extcon-rt8973a.c | 2 +-
drivers/gpu/drm/arm/malidp_regs.h | 2 +-
drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.h | 2 +-
drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +-
fs/userfaultfd.c | 2 +-
7 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index c0e4b73191f3..d75c9c24ec4d 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -1030,7 +1030,7 @@ int __init eeh_ops_register(struct eeh_ops *ops)
}
/**
- * eeh_ops_unregister - Unreigster platform dependent EEH operations
+ * eeh_ops_unregister - Unregister platform dependent EEH operations
* @name: name of EEH platform operations
*
* Unregister the platform dependent EEH operation callback
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 5c3f5d088c3b..9548a086937b 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -574,7 +574,7 @@ static inline void save_mfc_rag(struct spu_state *csa, struct spu *spu)
{
/* Save, Step 38:
* Save RA_GROUP_ID register and the
- * RA_ENABLE reigster in the CSA.
+ * RA_ENABLE register in the CSA.
*/
csa->priv1.resource_allocation_groupID_RW =
spu_resource_allocation_groupID_get(spu);
@@ -1227,7 +1227,7 @@ static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu)
{
/* Restore, Step 29:
* Restore RA_GROUP_ID register and the
- * RA_ENABLE reigster from the CSA.
+ * RA_ENABLE register from the CSA.
*/
spu_resource_allocation_groupID_set(spu,
csa->priv1.resource_allocation_groupID_RW);
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index 40c07f4d656e..e75c03792398 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -270,7 +270,7 @@ static int rt8973a_muic_get_cable_type(struct rt8973a_muic_info *info)
}
cable_type = adc & RT8973A_REG_ADC_MASK;
- /* Read Device 1 reigster to identify correct cable type */
+ /* Read Device 1 register to identify correct cable type */
ret = regmap_read(info->regmap, RT8973A_REG_DEV1, &dev1);
if (ret) {
dev_err(info->dev, "failed to read DEV1 register\n");
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
index 993031542fa1..9b4f95d8ccec 100644
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -145,7 +145,7 @@
#define MALIDP_SE_COEFFTAB_DATA_MASK 0x3fff
#define MALIDP_SE_SET_COEFFTAB_DATA(x) \
((x) & MALIDP_SE_COEFFTAB_DATA_MASK)
-/* Enhance coeffents reigster offset */
+/* Enhance coefficients register offset */
#define MALIDP_SE_IMAGE_ENH 0x3C
/* ENH_LIMITS offset 0x0 */
#define MALIDP_SE_ENH_LOW_LEVEL 24
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.h
index 99c6f7eefd85..d03c8f12a15c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.h
@@ -58,7 +58,7 @@ struct fw_priv {
/* 0x81: PCI-AP, 01:PCIe, 02: 92S-U,
* 0x82: USB-AP, 0x12: 72S-U, 03:SDIO */
u8 hci_sel;
- /* the same value as reigster value */
+ /* the same value as register value */
u8 chip_version;
/* customer ID low byte */
u8 customer_id_0;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 28ecaa7fc715..42b125602d72 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -6551,7 +6551,7 @@ lpfc_sli4_unregister_fcf(struct lpfc_hba *phba)
* lpfc_unregister_fcf_rescan - Unregister currently registered fcf and rescan
* @phba: Pointer to hba context object.
*
- * This function unregisters the currently reigstered FCF. This function
+ * This function unregisters the currently registered FCF. This function
* also tries to find another FCF for discovery by rescan the HBA FCF table.
*/
void
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index ccbdbd62f0d8..612dc1240f90 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -267,7 +267,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
#endif /* CONFIG_HUGETLB_PAGE */
/*
- * Verify the pagetables are still not ok after having reigstered into
+ * Verify the pagetables are still not ok after having registered into
* the fault_pending_wqh to avoid userland having to UFFDIO_WAKE any
* userfault that has already been resolved, if userfaultfd_read and
* UFFDIO_COPY|ZEROPAGE are being run simultaneously on two different
--
2.17.1
^ permalink raw reply related
* [PATCH net v2] net: ipv6: Fix a bug in ndisc_send_ns when netdev only has a global address
From: Su Yanjun @ 2019-07-30 2:35 UTC (permalink / raw)
To: davem, kuznet, yoshfuji; +Cc: netdev, linux-kernel, suyj.fnst
When the egress interface does not have a link local address, it can
not communicate with other hosts.
In RFC4861, 7.2.2 says
"If the source address of the packet prompting the solicitation is the
same as one of the addresses assigned to the outgoing interface, that
address SHOULD be placed in the IP Source Address of the outgoing
solicitation. Otherwise, any one of the addresses assigned to the
interface should be used."
In this patch we try get a global address if we get ll address failed.
Signed-off-by: Su Yanjun <suyj.fnst@cn.fujitsu.com>
---
Changes since V1:
- Change patch description and code optimization at
David Ahern's suggestion
---
include/net/addrconf.h | 2 ++
net/ipv6/addrconf.c | 34 ++++++++++++++++++++++++++++++++++
net/ipv6/ndisc.c | 9 ++++++---
3 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index becdad5..ce1561e 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -107,6 +107,8 @@ int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
u32 banned_flags);
int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
u32 banned_flags);
+int ipv6_get_addr(struct net_device *dev, struct in6_addr *addr,
+ u32 banned_flags);
bool inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
bool match_wildcard);
bool inet_rcv_saddr_any(const struct sock *sk);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 521e320..9467457 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1870,6 +1870,40 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
return err;
}
+int __ipv6_get_addr(struct inet6_dev *idev, struct in6_addr *addr,
+ u32 banned_flags)
+{
+ struct inet6_ifaddr *ifp;
+ int err = -EADDRNOTAVAIL;
+
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
+ if (ifp->scope == 0 &&
+ !(ifp->flags & banned_flags)) {
+ *addr = ifp->addr;
+ err = 0;
+ break;
+ }
+ }
+ return err;
+}
+
+int ipv6_get_addr(struct net_device *dev, struct in6_addr *addr,
+ u32 banned_flags)
+{
+ struct inet6_dev *idev;
+ int err = -EADDRNOTAVAIL;
+
+ rcu_read_lock();
+ idev = __in6_dev_get(dev);
+ if (idev) {
+ read_lock_bh(&idev->lock);
+ err = __ipv6_get_addr(idev, addr, banned_flags);
+ read_unlock_bh(&idev->lock);
+ }
+ rcu_read_unlock();
+ return err;
+}
+
static int ipv6_count_addresses(const struct inet6_dev *idev)
{
const struct inet6_ifaddr *ifp;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 083cc1c..156c027 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -603,11 +603,14 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
int inc_opt = dev->addr_len;
int optlen = 0;
struct nd_msg *msg;
+ u32 banned_flags = IFA_F_TENTATIVE | IFA_F_OPTIMISTIC;
if (!saddr) {
- if (ipv6_get_lladdr(dev, &addr_buf,
- (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
- return;
+ if (ipv6_get_lladdr(dev, &addr_buf, banned_flags)) {
+ /* try global address */
+ if (ipv6_get_addr(dev, &addr_buf, banned_flags))
+ return;
+ }
saddr = &addr_buf;
}
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] net: phy: phy_led_triggers: Fix a possible null-pointer dereference in phy_led_trigger_change_speed()
From: Jia-Ju Bai @ 2019-07-30 2:25 UTC (permalink / raw)
To: Andrew Lunn; +Cc: f.fainelli, hkallweit1, davem, netdev, linux-kernel
In-Reply-To: <20190729134553.GC4110@lunn.ch>
On 2019/7/29 21:45, Andrew Lunn wrote:
> On Mon, Jul 29, 2019 at 05:24:24PM +0800, Jia-Ju Bai wrote:
>> In phy_led_trigger_change_speed(), there is an if statement on line 48
>> to check whether phy->last_triggered is NULL:
>> if (!phy->last_triggered)
>>
>> When phy->last_triggered is NULL, it is used on line 52:
>> led_trigger_event(&phy->last_triggered->trigger, LED_OFF);
>>
>> Thus, a possible null-pointer dereference may occur.
>>
>> To fix this bug, led_trigger_event(&phy->last_triggered->trigger,
>> LED_OFF) is called when phy->last_triggered is not NULL.
>>
>> This bug is found by a static analysis tool STCheck written by us.
> Who is 'us'?
Me and my colleague...
Best wishes,
Jia-Ju Bai
^ permalink raw reply
* Re: [PATCH 2/4] net: phy: Add mdio-aspeed
From: Andrew Jeffery @ 2019-07-30 2:23 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, David Miller, Rob Herring, mark.rutland, Joel Stanley,
Florian Fainelli, Heiner Kallweit, devicetree, linux-arm-kernel,
linux-aspeed, linux-kernel
In-Reply-To: <20190729133250.GB4110@lunn.ch>
On Mon, 29 Jul 2019, at 23:03, Andrew Lunn wrote:
> On Mon, Jul 29, 2019 at 02:09:24PM +0930, Andrew Jeffery wrote:
> > The AST2600 design separates the MDIO controllers from the MAC, which is
> > where they were placed in the AST2400 and AST2500. Further, the register
> > interface is reworked again, so now we have three possible different
> > interface implementations, however this driver only supports the
> > interface provided by the AST2600. The AST2400 and AST2500 will continue
> > to be supported by the MDIO support embedded in the FTGMAC100 driver.
> >
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> > drivers/net/phy/Kconfig | 13 +++
> > drivers/net/phy/Makefile | 1 +
> > drivers/net/phy/mdio-aspeed.c | 159 ++++++++++++++++++++++++++++++++++
> > 3 files changed, 173 insertions(+)
> > create mode 100644 drivers/net/phy/mdio-aspeed.c
> >
> > diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> > index 20f14c5fbb7e..206d8650ee7f 100644
> > --- a/drivers/net/phy/Kconfig
> > +++ b/drivers/net/phy/Kconfig
> > @@ -21,6 +21,19 @@ config MDIO_BUS
> >
> > if MDIO_BUS
> >
> > +config MDIO_ASPEED
> > + tristate "ASPEED MDIO bus controller"
> > + depends on ARCH_ASPEED || COMPILE_TEST
> > + depends on OF_MDIO && HAS_IOMEM
> > + help
> > + This module provides a driver for the independent MDIO bus
> > + controllers found in the ASPEED AST2600 SoC. This is a driver for the
> > + third revision of the ASPEED MDIO register interface - the first two
> > + revisions are the "old" and "new" interfaces found in the AST2400 and
> > + AST2500, embedded in the MAC. For legacy reasons, FTGMAC100 driver
> > + continues to drive the embedded MDIO controller for the AST2400 and
> > + AST2500 SoCs, so say N if AST2600 support is not required.
> > +
> > config MDIO_BCM_IPROC
> > tristate "Broadcom iProc MDIO bus controller"
> > depends on ARCH_BCM_IPROC || COMPILE_TEST
> > diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> > index 839acb292c38..ba07c27e4208 100644
> > --- a/drivers/net/phy/Makefile
> > +++ b/drivers/net/phy/Makefile
> > @@ -22,6 +22,7 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_led_triggers.o
> > obj-$(CONFIG_PHYLINK) += phylink.o
> > obj-$(CONFIG_PHYLIB) += libphy.o
> >
> > +obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o
> > obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
> > obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
> > obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
> > diff --git a/drivers/net/phy/mdio-aspeed.c b/drivers/net/phy/mdio-aspeed.c
> > new file mode 100644
> > index 000000000000..71496a9ff54a
> > --- /dev/null
> > +++ b/drivers/net/phy/mdio-aspeed.c
> > @@ -0,0 +1,159 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/* Copyright (C) 2019 IBM Corp. */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/delay.h>
> > +#include <linux/mdio.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_mdio.h>
> > +#include <linux/phy.h>
> > +#include <linux/platform_device.h>
> > +
> > +#define DRV_NAME "mdio-aspeed"
> > +
> > +#define ASPEED_MDIO_CTRL 0x0
> > +#define ASPEED_MDIO_CTRL_FIRE BIT(31)
> > +#define ASPEED_MDIO_CTRL_ST BIT(28)
> > +#define ASPEED_MDIO_CTRL_ST_C45 0
> > +#define ASPEED_MDIO_CTRL_ST_C22 1
> > +#define ASPEED_MDIO_CTRL_OP GENMASK(27, 26)
> > +#define MDIO_C22_OP_WRITE 0b01
> > +#define MDIO_C22_OP_READ 0b10
> > +#define ASPEED_MDIO_CTRL_PHYAD GENMASK(25, 21)
> > +#define ASPEED_MDIO_CTRL_REGAD GENMASK(20, 16)
> > +#define ASPEED_MDIO_CTRL_MIIWDATA GENMASK(15, 0)
> > +
> > +#define ASPEED_MDIO_DATA 0x4
> > +#define ASPEED_MDIO_DATA_MDC_THRES GENMASK(31, 24)
> > +#define ASPEED_MDIO_DATA_MDIO_EDGE BIT(23)
> > +#define ASPEED_MDIO_DATA_MDIO_LATCH GENMASK(22, 20)
> > +#define ASPEED_MDIO_DATA_IDLE BIT(16)
> > +#define ASPEED_MDIO_DATA_MIIRDATA GENMASK(15, 0)
> > +
> > +#define ASPEED_MDIO_RETRIES 10
> > +
> > +struct aspeed_mdio {
> > + void __iomem *base;
> > +};
> > +
> > +static int aspeed_mdio_read(struct mii_bus *bus, int addr, int regnum)
> > +{
> > + struct aspeed_mdio *ctx = bus->priv;
> > + u32 ctrl;
> > + int i;
> > +
> > + dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d\n", __func__, addr,
> > + regnum);
> > +
> > + /* Just clause 22 for the moment */
> > + ctrl = ASPEED_MDIO_CTRL_FIRE
>
> Hi Andrew
>
> In the binding, you say C45 is supported. Here you don't. It would be
> nice to be consistent.
Right - but the bindings describe the hardware, and the hardware is capable.
Just that the driver as it stands can't drive it that way.
Having said that I do need to do more digging to understand how to cater to
C45 PHYs wrt the read/write calls.
>
>
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_READ)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum);
> > +
> > + iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
> > +
> > + for (i = 0; i < ASPEED_MDIO_RETRIES; i++) {
> > + u32 data;
> > +
> > + data = ioread32(ctx->base + ASPEED_MDIO_DATA);
> > + if (data & ASPEED_MDIO_DATA_IDLE)
> > + return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data);
> > +
> > + udelay(100);
> > + }
>
> One of the readx_poll_timeout functions could be used.
Thanks, I'll take a look.
>
> > +
> > + dev_err(&bus->dev, "MDIO read failed\n");
> > + return -EIO;
> > +}
> > +
> > +static int aspeed_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
> > +{
> > + struct aspeed_mdio *ctx = bus->priv;
> > + u32 ctrl;
> > + int i;
> > +
> > + dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d, val: 0x%x\n",
> > + __func__, addr, regnum, val);
> > +
> > + /* Just clause 22 for the moment */
> > + ctrl = ASPEED_MDIO_CTRL_FIRE
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_WRITE)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum)
> > + | FIELD_PREP(ASPEED_MDIO_CTRL_MIIWDATA, val);
> > +
> > + iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
> > +
> > + for (i = 0; i < ASPEED_MDIO_RETRIES; i++) {
> > + ctrl = ioread32(ctx->base + ASPEED_MDIO_CTRL);
> > + if (!(ctrl & ASPEED_MDIO_CTRL_FIRE))
> > + return 0;
> > +
> > + udelay(100);
> > + }
>
> readx_poll_timeout() here as well.
>
> Otherwise this looks good.
Thanks for the review!
Andrew
^ permalink raw reply
* [net-next:master 57/61] arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: error: storage size of 'pip_sft_rst' isn't known
From: kbuild test robot @ 2019-07-29 23:23 UTC (permalink / raw)
To: Matthew Wilcox (Oracle); +Cc: kbuild-all, netdev
[-- Attachment #1: Type: text/plain, Size: 33791 bytes --]
tree: https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next.git master
head: 85fd8011475e86265beff7b7617c493c247f5356
commit: 171a9bae68c72f2d1260c3825203760856e6793b [57/61] staging/octeon: Allow test build on !MIPS
config: mips-allmodconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 7.4.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout 171a9bae68c72f2d1260c3825203760856e6793b
# save the attached .config to linux build tree
GCC_VERSION=7.4.0 make.cross ARCH=mips
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All error/warnings (new ones prefixed by >>):
In file included from arch/mips/include/asm/octeon/octeon.h:11:0,
from drivers/staging/octeon/octeon-ethernet.h:19,
from drivers/staging/octeon/ethernet.c:22:
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_writeq_csr':
>> arch/mips/include/asm/octeon/cvmx.h:282:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
cvmx_write_csr((__force uint64_t)csr_addr, val);
^
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_readq_csr':
arch/mips/include/asm/octeon/cvmx.h:299:23: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
return cvmx_read_csr((__force uint64_t) csr_addr);
^
In file included from drivers/staging/octeon/octeon-ethernet.h:27:0,
from drivers/staging/octeon/ethernet.c:22:
arch/mips/include/asm/octeon/cvmx-ipd.h: In function 'cvmx_ipd_free_ptr':
>> arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: error: storage size of 'pip_sft_rst' isn't known
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
>> arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: error: 'CVMX_PIP_SFT_RST' undeclared (first use in this function); did you mean 'CVMX_CIU_SOFT_RST'?
pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST);
^~~~~~~~~~~~~~~~
CVMX_CIU_SOFT_RST
arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: note: each undeclared identifier is reported only once for each function it appears in
arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: warning: unused variable 'pip_sft_rst' [-Wunused-variable]
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
--
In file included from arch/mips/include/asm/octeon/octeon.h:11:0,
from drivers/staging/octeon/octeon-ethernet.h:19,
from drivers/staging/octeon/ethernet-rx.c:26:
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_writeq_csr':
>> arch/mips/include/asm/octeon/cvmx.h:282:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
cvmx_write_csr((__force uint64_t)csr_addr, val);
^
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_readq_csr':
arch/mips/include/asm/octeon/cvmx.h:299:23: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
return cvmx_read_csr((__force uint64_t) csr_addr);
^
In file included from drivers/staging/octeon/octeon-ethernet.h:27:0,
from drivers/staging/octeon/ethernet-rx.c:26:
arch/mips/include/asm/octeon/cvmx-ipd.h: In function 'cvmx_ipd_free_ptr':
>> arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: error: storage size of 'pip_sft_rst' isn't known
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
>> arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: error: 'CVMX_PIP_SFT_RST' undeclared (first use in this function); did you mean 'CVMX_CIU_SOFT_RST'?
pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST);
^~~~~~~~~~~~~~~~
CVMX_CIU_SOFT_RST
arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: note: each undeclared identifier is reported only once for each function it appears in
arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: warning: unused variable 'pip_sft_rst' [-Wunused-variable]
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
In file included from drivers/staging/octeon/ethernet-rx.c:27:0:
drivers/staging/octeon/ethernet-rx.c: In function 'cvm_oct_poll':
>> drivers/staging/octeon/ethernet-defines.h:30:38: error: 'CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE' undeclared (first use in this function); did you mean 'CONFIG_MDIO_OCTEON_MODULE'?
#define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
^
>> drivers/staging/octeon/ethernet-rx.c:190:6: note: in expansion of macro 'USE_ASYNC_IOBDMA'
if (USE_ASYNC_IOBDMA) {
^~~~~~~~~~~~~~~~
drivers/staging/octeon/ethernet-rx.c: In function 'cvm_oct_rx_initialize':
>> drivers/staging/octeon/ethernet-rx.c:472:25: error: 'OCTEON_IRQ_WORKQ0' undeclared (first use in this function); did you mean 'OCTEON_IS_MODEL'?
oct_rx_group[i].irq = OCTEON_IRQ_WORKQ0 + i;
^~~~~~~~~~~~~~~~~
OCTEON_IS_MODEL
--
In file included from arch/mips/include/asm/octeon/octeon.h:11:0,
from drivers/staging/octeon/octeon-ethernet.h:19,
from drivers/staging/octeon/ethernet-spi.c:13:
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_writeq_csr':
>> arch/mips/include/asm/octeon/cvmx.h:282:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
cvmx_write_csr((__force uint64_t)csr_addr, val);
^
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_readq_csr':
arch/mips/include/asm/octeon/cvmx.h:299:23: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
return cvmx_read_csr((__force uint64_t) csr_addr);
^
In file included from drivers/staging/octeon/octeon-ethernet.h:27:0,
from drivers/staging/octeon/ethernet-spi.c:13:
arch/mips/include/asm/octeon/cvmx-ipd.h: In function 'cvmx_ipd_free_ptr':
>> arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: error: storage size of 'pip_sft_rst' isn't known
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
>> arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: error: 'CVMX_PIP_SFT_RST' undeclared (first use in this function); did you mean 'CVMX_CIU_SOFT_RST'?
pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST);
^~~~~~~~~~~~~~~~
CVMX_CIU_SOFT_RST
arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: note: each undeclared identifier is reported only once for each function it appears in
arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: warning: unused variable 'pip_sft_rst' [-Wunused-variable]
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
drivers/staging/octeon/ethernet-spi.c: In function 'cvm_oct_spi_init':
>> drivers/staging/octeon/ethernet-spi.c:198:19: error: 'OCTEON_IRQ_RML' undeclared (first use in this function); did you mean 'OCTEON_IS_MODEL'?
r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt,
^~~~~~~~~~~~~~
OCTEON_IS_MODEL
drivers/staging/octeon/ethernet-spi.c: In function 'cvm_oct_spi_uninit':
drivers/staging/octeon/ethernet-spi.c:224:12: error: 'OCTEON_IRQ_RML' undeclared (first use in this function); did you mean 'OCTEON_IS_MODEL'?
free_irq(OCTEON_IRQ_RML, &number_spi_ports);
^~~~~~~~~~~~~~
OCTEON_IS_MODEL
--
In file included from arch/mips/include/asm/octeon/octeon.h:11:0,
from drivers/staging/octeon/octeon-ethernet.h:19,
from drivers/staging/octeon/ethernet-tx.c:25:
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_writeq_csr':
>> arch/mips/include/asm/octeon/cvmx.h:282:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
cvmx_write_csr((__force uint64_t)csr_addr, val);
^
arch/mips/include/asm/octeon/cvmx.h: In function 'cvmx_readq_csr':
arch/mips/include/asm/octeon/cvmx.h:299:23: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
return cvmx_read_csr((__force uint64_t) csr_addr);
^
In file included from drivers/staging/octeon/octeon-ethernet.h:27:0,
from drivers/staging/octeon/ethernet-tx.c:25:
arch/mips/include/asm/octeon/cvmx-ipd.h: In function 'cvmx_ipd_free_ptr':
>> arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: error: storage size of 'pip_sft_rst' isn't known
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
>> arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: error: 'CVMX_PIP_SFT_RST' undeclared (first use in this function); did you mean 'CVMX_CIU_SOFT_RST'?
pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST);
^~~~~~~~~~~~~~~~
CVMX_CIU_SOFT_RST
arch/mips/include/asm/octeon/cvmx-ipd.h:331:36: note: each undeclared identifier is reported only once for each function it appears in
arch/mips/include/asm/octeon/cvmx-ipd.h:330:27: warning: unused variable 'pip_sft_rst' [-Wunused-variable]
union cvmx_pip_sft_rst pip_sft_rst;
^~~~~~~~~~~
In file included from drivers/staging/octeon/ethernet-tx.c:26:0:
drivers/staging/octeon/ethernet-tx.c: In function 'cvm_oct_xmit':
>> drivers/staging/octeon/ethernet-defines.h:30:38: error: 'CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE' undeclared (first use in this function); did you mean 'CONFIG_MDIO_OCTEON_MODULE'?
#define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
^
>> drivers/staging/octeon/ethernet-tx.c:169:6: note: in expansion of macro 'USE_ASYNC_IOBDMA'
if (USE_ASYNC_IOBDMA) {
^~~~~~~~~~~~~~~~
In file included from arch/mips/include/asm/barrier.h:11:0,
from include/linux/compiler.h:256,
from include/linux/kernel.h:11,
from include/linux/list.h:9,
from include/linux/module.h:9,
from drivers/staging/octeon/ethernet-tx.c:8:
drivers/staging/octeon/ethernet-tx.c:264:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data);
^
arch/mips/include/asm/addrspace.h:128:30: note: in definition of macro 'XKPHYS_TO_PHYS'
#define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK)
^
drivers/staging/octeon/ethernet-tx.c:268:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data);
^
arch/mips/include/asm/addrspace.h:128:30: note: in definition of macro 'XKPHYS_TO_PHYS'
#define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK)
^
drivers/staging/octeon/ethernet-tx.c:276:20: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
XKPHYS_TO_PHYS((u64)skb_frag_address(fs));
^
arch/mips/include/asm/addrspace.h:128:30: note: in definition of macro 'XKPHYS_TO_PHYS'
#define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK)
^
drivers/staging/octeon/ethernet-tx.c:280:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)CVM_OCT_SKB_CB(skb));
^
arch/mips/include/asm/addrspace.h:128:30: note: in definition of macro 'XKPHYS_TO_PHYS'
#define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK)
^
drivers/staging/octeon/ethernet-tx.c: In function 'cvm_oct_tx_initialize':
>> drivers/staging/octeon/ethernet-tx.c:706:18: error: 'OCTEON_IRQ_TIMER1' undeclared (first use in this function); did you mean 'OCTEON_IS_MODEL'?
i = request_irq(OCTEON_IRQ_TIMER1,
^~~~~~~~~~~~~~~~~
OCTEON_IS_MODEL
drivers/staging/octeon/ethernet-tx.c: In function 'cvm_oct_tx_shutdown':
drivers/staging/octeon/ethernet-tx.c:717:11: error: 'OCTEON_IRQ_TIMER1' undeclared (first use in this function); did you mean 'OCTEON_IS_MODEL'?
free_irq(OCTEON_IRQ_TIMER1, cvm_oct_device);
^~~~~~~~~~~~~~~~~
OCTEON_IS_MODEL
vim +330 arch/mips/include/asm/octeon/cvmx-ipd.h
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 154
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 155 /**
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 156 * Supportive function for cvmx_fpa_shutdown_pool.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 157 */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 158 static inline void cvmx_ipd_free_ptr(void)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 159 {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 160 /* Only CN38XXp{1,2} cannot read pointer out of the IPD */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 161 if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 162 && !OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 163 int no_wptr = 0;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 164 union cvmx_ipd_ptr_count ipd_ptr_count;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 165 ipd_ptr_count.u64 = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 166
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 167 /* Handle Work Queue Entry in cn56xx and cn52xx */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 168 if (octeon_has_feature(OCTEON_FEATURE_NO_WPTR)) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 169 union cvmx_ipd_ctl_status ipd_ctl_status;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 170 ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 171 if (ipd_ctl_status.s.no_wptr)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 172 no_wptr = 1;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 173 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 174
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 175 /* Free the prefetched WQE */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 176 if (ipd_ptr_count.s.wqev_cnt) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 177 union cvmx_ipd_wqe_ptr_valid ipd_wqe_ptr_valid;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 178 ipd_wqe_ptr_valid.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 179 cvmx_read_csr(CVMX_IPD_WQE_PTR_VALID);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 180 if (no_wptr)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 181 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 182 ((uint64_t) ipd_wqe_ptr_valid.s.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 183 ptr << 7), CVMX_FPA_PACKET_POOL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 184 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 185 else
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 186 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 187 ((uint64_t) ipd_wqe_ptr_valid.s.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 188 ptr << 7), CVMX_FPA_WQE_POOL, 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 189 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 190
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 191 /* Free all WQE in the fifo */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 192 if (ipd_ptr_count.s.wqe_pcnt) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 193 int i;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 194 union cvmx_ipd_pwp_ptr_fifo_ctl ipd_pwp_ptr_fifo_ctl;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 195 ipd_pwp_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 196 cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 197 for (i = 0; i < ipd_ptr_count.s.wqe_pcnt; i++) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 198 ipd_pwp_ptr_fifo_ctl.s.cena = 0;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 199 ipd_pwp_ptr_fifo_ctl.s.raddr =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 200 ipd_pwp_ptr_fifo_ctl.s.max_cnts +
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 201 (ipd_pwp_ptr_fifo_ctl.s.wraddr +
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 202 i) % ipd_pwp_ptr_fifo_ctl.s.max_cnts;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 203 cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 204 ipd_pwp_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 205 ipd_pwp_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 206 cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 207 if (no_wptr)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 208 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 209 ((uint64_t)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 210 ipd_pwp_ptr_fifo_ctl.s.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 211 ptr << 7),
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 212 CVMX_FPA_PACKET_POOL, 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 213 else
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 214 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 215 ((uint64_t)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 216 ipd_pwp_ptr_fifo_ctl.s.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 217 ptr << 7),
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 218 CVMX_FPA_WQE_POOL, 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 219 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 220 ipd_pwp_ptr_fifo_ctl.s.cena = 1;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 221 cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 222 ipd_pwp_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 223 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 224
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 225 /* Free the prefetched packet */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 226 if (ipd_ptr_count.s.pktv_cnt) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 227 union cvmx_ipd_pkt_ptr_valid ipd_pkt_ptr_valid;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 228 ipd_pkt_ptr_valid.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 229 cvmx_read_csr(CVMX_IPD_PKT_PTR_VALID);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 230 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 231 (ipd_pkt_ptr_valid.s.ptr << 7),
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 232 CVMX_FPA_PACKET_POOL, 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 233 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 234
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 235 /* Free the per port prefetched packets */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 236 if (1) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 237 int i;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 238 union cvmx_ipd_prc_port_ptr_fifo_ctl
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 239 ipd_prc_port_ptr_fifo_ctl;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 240 ipd_prc_port_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 241 cvmx_read_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 242
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 243 for (i = 0; i < ipd_prc_port_ptr_fifo_ctl.s.max_pkt;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 244 i++) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 245 ipd_prc_port_ptr_fifo_ctl.s.cena = 0;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 246 ipd_prc_port_ptr_fifo_ctl.s.raddr =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 247 i % ipd_prc_port_ptr_fifo_ctl.s.max_pkt;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 248 cvmx_write_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 249 ipd_prc_port_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 250 ipd_prc_port_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 251 cvmx_read_csr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 252 (CVMX_IPD_PRC_PORT_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 253 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 254 ((uint64_t)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 255 ipd_prc_port_ptr_fifo_ctl.s.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 256 ptr << 7), CVMX_FPA_PACKET_POOL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 257 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 258 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 259 ipd_prc_port_ptr_fifo_ctl.s.cena = 1;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 260 cvmx_write_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 261 ipd_prc_port_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 262 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 263
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 264 /* Free all packets in the holding fifo */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 265 if (ipd_ptr_count.s.pfif_cnt) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 266 int i;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 267 union cvmx_ipd_prc_hold_ptr_fifo_ctl
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 268 ipd_prc_hold_ptr_fifo_ctl;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 269
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 270 ipd_prc_hold_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 271 cvmx_read_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 272
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 273 for (i = 0; i < ipd_ptr_count.s.pfif_cnt; i++) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 274 ipd_prc_hold_ptr_fifo_ctl.s.cena = 0;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 275 ipd_prc_hold_ptr_fifo_ctl.s.raddr =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 276 (ipd_prc_hold_ptr_fifo_ctl.s.praddr +
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 277 i) % ipd_prc_hold_ptr_fifo_ctl.s.max_pkt;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 278 cvmx_write_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 279 ipd_prc_hold_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 280 ipd_prc_hold_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 281 cvmx_read_csr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 282 (CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 283 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 284 ((uint64_t)
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 285 ipd_prc_hold_ptr_fifo_ctl.s.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 286 ptr << 7), CVMX_FPA_PACKET_POOL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 287 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 288 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 289 ipd_prc_hold_ptr_fifo_ctl.s.cena = 1;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 290 cvmx_write_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 291 ipd_prc_hold_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 292 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 293
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 294 /* Free all packets in the fifo */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 295 if (ipd_ptr_count.s.pkt_pcnt) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 296 int i;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 297 union cvmx_ipd_pwp_ptr_fifo_ctl ipd_pwp_ptr_fifo_ctl;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 298 ipd_pwp_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 299 cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 300
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 301 for (i = 0; i < ipd_ptr_count.s.pkt_pcnt; i++) {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 302 ipd_pwp_ptr_fifo_ctl.s.cena = 0;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 303 ipd_pwp_ptr_fifo_ctl.s.raddr =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 304 (ipd_pwp_ptr_fifo_ctl.s.praddr +
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 305 i) % ipd_pwp_ptr_fifo_ctl.s.max_cnts;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 306 cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 307 ipd_pwp_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 308 ipd_pwp_ptr_fifo_ctl.u64 =
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 309 cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 310 cvmx_fpa_free(cvmx_phys_to_ptr
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 311 ((uint64_t) ipd_pwp_ptr_fifo_ctl.
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 312 s.ptr << 7),
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 313 CVMX_FPA_PACKET_POOL, 0);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 314 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 315 ipd_pwp_ptr_fifo_ctl.s.cena = 1;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 316 cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL,
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 317 ipd_pwp_ptr_fifo_ctl.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 318 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 319
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 320 /* Reset the IPD to get all buffers out of it */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 321 {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 322 union cvmx_ipd_ctl_status ipd_ctl_status;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 323 ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 324 ipd_ctl_status.s.reset = 1;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 325 cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 326 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 327
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 328 /* Reset the PIP */
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 329 {
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 @330 union cvmx_pip_sft_rst pip_sft_rst;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 @331 pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 332 pip_sft_rst.s.rst = 1;
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 333 cvmx_write_csr(CVMX_PIP_SFT_RST, pip_sft_rst.u64);
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 334 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 335 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 336 }
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 337
80ff0fd3ab64514 drivers/staging/octeon/cvmx-ipd.h David Daney 2009-05-05 338 #endif /* __CVMX_IPD_H__ */
:::::: The code at line 330 was first introduced by commit
:::::: 80ff0fd3ab6451407a20c19b80c1643c4a6d6434 Staging: Add octeon-ethernet driver files.
:::::: TO: David Daney <ddaney@caviumnetworks.com>
:::::: CC: Ralf Baechle <ralf@linux-mips.org>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 61515 bytes --]
^ permalink raw reply
* Re: [PATCH net-next 2/2] net: phy: broadcom: add 1000Base-X support for BCM54616S
From: Vladimir Oltean @ 2019-07-30 1:32 UTC (permalink / raw)
To: Tao Ren
Cc: Andrew Lunn, Florian Fainelli, Heiner Kallweit, David S . Miller,
Arun Parameswaran, Justin Chen, netdev, lkml, Andrew Jeffery,
openbmc
In-Reply-To: <20190730002549.86824-1-taoren@fb.com>
Hi Tao,
On Tue, 30 Jul 2019 at 03:31, Tao Ren <taoren@fb.com> wrote:
>
> Configure the BCM54616S for 1000Base-X mode when "brcm-phy-mode-1000bx"
> is set in device tree. This is needed when the PHY is used for fiber and
> backplane connections.
>
> The patch is inspired by commit cd9af3dac6d1 ("PHYLIB: Add 1000Base-X
> support for Broadcom bcm5482").
As far as I can see, for the commit you referenced,
PHY_BCM_FLAGS_MODE_1000BX is referenced from nowhere in the entire
mainline kernel:
https://elixir.bootlin.com/linux/latest/ident/PHY_BCM_FLAGS_MODE_1000BX
(it is supposed to be put by the MAC driver in phydev->dev_flags prior
to calling phy_connect). But I don't see the point to this - can't you
check for phydev->interface == PHY_INTERFACE_MODE_1000BASEX?
This has the advantage that no MAC driver will need to know that it's
talking to a Broadcom PHY. Additionally, no custom DT bindings are
needed.
Also, for backplane connections you probably want 1000Base-KX which
has its own AN/LT, not plain 1000Base-X.
>
> Signed-off-by: Tao Ren <taoren@fb.com>
> ---
> drivers/net/phy/broadcom.c | 58 +++++++++++++++++++++++++++++++++++---
> include/linux/brcmphy.h | 4 +--
> 2 files changed, 56 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
> index 2b4e41a9d35a..6c22ac3a844b 100644
> --- a/drivers/net/phy/broadcom.c
> +++ b/drivers/net/phy/broadcom.c
> @@ -383,9 +383,9 @@ static int bcm5482_config_init(struct phy_device *phydev)
> /*
> * Select 1000BASE-X register set (primary SerDes)
> */
> - reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
> - bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
> - reg | BCM5482_SHD_MODE_1000BX);
> + reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
> + bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE,
> + reg | BCM54XX_SHD_MODE_1000BX);
>
> /*
> * LED1=ACTIVITYLED, LED3=LINKSPD[2]
> @@ -451,6 +451,34 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
> return ret;
> }
>
> +static int bcm54616s_config_init(struct phy_device *phydev)
> +{
> + int err, reg;
> + struct device_node *np = phydev->mdio.dev.of_node;
> +
> + err = bcm54xx_config_init(phydev);
> +
> + if (of_property_read_bool(np, "brcm-phy-mode-1000bx")) {
> + /* Select 1000BASE-X register set. */
> + reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
> + bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE,
> + reg | BCM54XX_SHD_MODE_1000BX);
> +
> + /* Auto-negotiation doesn't seem to work quite right
> + * in this mode, so we disable it and force it to the
> + * right speed/duplex setting. Only 'link status'
> + * is important.
> + */
> + phydev->autoneg = AUTONEG_DISABLE;
> + phydev->speed = SPEED_1000;
> + phydev->duplex = DUPLEX_FULL;
> +
1000Base-X AN does not include speed negotiation, so hardcoding
SPEED_1000 is probably correct.
What is wrong with the AN of duplex settings?
> + phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX;
> + }
> +
> + return err;
> +}
> +
> static int bcm54616s_config_aneg(struct phy_device *phydev)
> {
> int ret;
> @@ -464,6 +492,27 @@ static int bcm54616s_config_aneg(struct phy_device *phydev)
> return ret;
> }
>
> +static int bcm54616s_read_status(struct phy_device *phydev)
> +{
> + int ret;
> +
> + ret = genphy_read_status(phydev);
> + if (ret < 0)
> + return ret;
> +
> + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
> + /* Only link status matters for 1000Base-X mode, so force
> + * 1000 Mbit/s full-duplex status.
> + */
> + if (phydev->link) {
> + phydev->speed = SPEED_1000;
> + phydev->duplex = DUPLEX_FULL;
> + }
> + }
> +
> + return 0;
> +}
> +
> static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
> {
> int val;
> @@ -651,8 +700,9 @@ static struct phy_driver broadcom_drivers[] = {
> .phy_id_mask = 0xfffffff0,
> .name = "Broadcom BCM54616S",
> .features = PHY_GBIT_FEATURES,
> - .config_init = bcm54xx_config_init,
> + .config_init = bcm54616s_config_init,
> .config_aneg = bcm54616s_config_aneg,
> + .read_status = bcm54616s_read_status,
> .ack_interrupt = bcm_phy_ack_intr,
> .config_intr = bcm_phy_config_intr,
> }, {
> diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
> index 6db2d9a6e503..82030155558c 100644
> --- a/include/linux/brcmphy.h
> +++ b/include/linux/brcmphy.h
> @@ -200,8 +200,8 @@
> #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */
> #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */
> #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */
> -#define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */
> -#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */
> +#define BCM54XX_SHD_MODE 0x1f /* 11111: Mode Control Register */
> +#define BCM54XX_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */
These registers are also present on my BCM5464, probably safe to
assume they're generic for the entire family.
So if you make the registers definitions common, you can probably make
the 1000Base-X configuration common as well.
>
>
> /*
> --
> 2.17.1
>
Regards,
-Vladimir
^ permalink raw reply
* Re: [PATCH stable 4.9] tcp: reset sk_send_head in tcp_write_queue_purge
From: maowenan @ 2019-07-30 1:31 UTC (permalink / raw)
To: Sasha Levin; +Cc: gregkh, stable, netdev, linux-kernel
In-Reply-To: <20190729153218.GA29162@sasha-vm>
On 2019/7/29 23:32, Sasha Levin wrote:
> On Mon, Jul 29, 2019 at 09:21:08PM +0800, Mao Wenan wrote:
>> From: Soheil Hassas Yeganeh <soheil@google.com>
>>
>> tcp_write_queue_purge clears all the SKBs in the write queue
>> but does not reset the sk_send_head. As a result, we can have
>> a NULL pointer dereference anywhere that we use tcp_send_head
>> instead of the tcp_write_queue_tail.
>>
>> For example, after a27fd7a8ed38 (tcp: purge write queue upon RST),
>> we can purge the write queue on RST. Prior to
>> 75c119afe14f (tcp: implement rb-tree based retransmit queue),
>> tcp_push will only check tcp_send_head and then accesses
>> tcp_write_queue_tail to send the actual SKB. As a result, it will
>> dereference a NULL pointer.
>>
>> This has been reported twice for 4.14 where we don't have
>> 75c119afe14f:
>>
>> By Timofey Titovets:
>>
>> [ 422.081094] BUG: unable to handle kernel NULL pointer dereference
>> at 0000000000000038
>> [ 422.081254] IP: tcp_push+0x42/0x110
>> [ 422.081314] PGD 0 P4D 0
>> [ 422.081364] Oops: 0002 [#1] SMP PTI
>>
>> By Yongjian Xu:
>>
>> BUG: unable to handle kernel NULL pointer dereference at 0000000000000038
>> IP: tcp_push+0x48/0x120
>> PGD 80000007ff77b067 P4D 80000007ff77b067 PUD 7fd989067 PMD 0
>> Oops: 0002 [#18] SMP PTI
>> Modules linked in: tcp_diag inet_diag tcp_bbr sch_fq iTCO_wdt
>> iTCO_vendor_support pcspkr ixgbe mdio i2c_i801 lpc_ich joydev input_leds shpchp
>> e1000e igb dca ptp pps_core hwmon mei_me mei ipmi_si ipmi_msghandler sg ses
>> scsi_transport_sas enclosure ext4 jbd2 mbcache sd_mod ahci libahci megaraid_sas
>> wmi ast ttm dm_mirror dm_region_hash dm_log dm_mod dax
>> CPU: 6 PID: 14156 Comm: [ET_NET 6] Tainted: G D 4.14.26-1.el6.x86_64 #1
>> Hardware name: LENOVO ThinkServer RD440 /ThinkServer RD440, BIOS A0TS80A
>> 09/22/2014
>> task: ffff8807d78d8140 task.stack: ffffc9000e944000
>> RIP: 0010:tcp_push+0x48/0x120
>> RSP: 0018:ffffc9000e947a88 EFLAGS: 00010246
>> RAX: 00000000000005b4 RBX: ffff880f7cce9c00 RCX: 0000000000000000
>> RDX: 0000000000000000 RSI: 0000000000000040 RDI: ffff8807d00f5000
>> RBP: ffffc9000e947aa8 R08: 0000000000001c84 R09: 0000000000000000
>> R10: ffff8807d00f5158 R11: 0000000000000000 R12: ffff8807d00f5000
>> R13: 0000000000000020 R14: 00000000000256d4 R15: 0000000000000000
>> FS: 00007f5916de9700(0000) GS:ffff88107fd00000(0000) knlGS:0000000000000000
>> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>> CR2: 0000000000000038 CR3: 00000007f8226004 CR4: 00000000001606e0
>> Call Trace:
>> tcp_sendmsg_locked+0x33d/0xe50
>> tcp_sendmsg+0x37/0x60
>> inet_sendmsg+0x39/0xc0
>> sock_sendmsg+0x49/0x60
>> sock_write_iter+0xb6/0x100
>> do_iter_readv_writev+0xec/0x130
>> ? rw_verify_area+0x49/0xb0
>> do_iter_write+0x97/0xd0
>> vfs_writev+0x7e/0xe0
>> ? __wake_up_common_lock+0x80/0xa0
>> ? __fget_light+0x2c/0x70
>> ? __do_page_fault+0x1e7/0x530
>> do_writev+0x60/0xf0
>> ? inet_shutdown+0xac/0x110
>> SyS_writev+0x10/0x20
>> do_syscall_64+0x6f/0x140
>> ? prepare_exit_to_usermode+0x8b/0xa0
>> entry_SYSCALL_64_after_hwframe+0x3d/0xa2
>> RIP: 0033:0x3135ce0c57
>> RSP: 002b:00007f5916de4b00 EFLAGS: 00000293 ORIG_RAX: 0000000000000014
>> RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 0000003135ce0c57
>> RDX: 0000000000000002 RSI: 00007f5916de4b90 RDI: 000000000000606f
>> RBP: 0000000000000000 R08: 0000000000000000 R09: 00007f5916de8c38
>> R10: 0000000000000000 R11: 0000000000000293 R12: 00000000000464cc
>> R13: 00007f5916de8c30 R14: 00007f58d8bef080 R15: 0000000000000002
>> Code: 48 8b 97 60 01 00 00 4c 8d 97 58 01 00 00 41 b9 00 00 00 00 41 89 f3 4c 39
>> d2 49 0f 44 d1 41 81 e3 00 80 00 00 0f 85 b0 00 00 00 <80> 4a 38 08 44 8b 8f 74
>> 06 00 00 44 89 8f 7c 06 00 00 83 e6 01
>> RIP: tcp_push+0x48/0x120 RSP: ffffc9000e947a88
>> CR2: 0000000000000038
>> ---[ end trace 8d545c2e93515549 ]---
>>
>> There is other scenario which found in stable 4.4:
>> Allocated:
>> [<ffffffff82f380a6>] __alloc_skb+0xe6/0x600 net/core/skbuff.c:218
>> [<ffffffff832466c3>] alloc_skb_fclone include/linux/skbuff.h:856 [inline]
>> [<ffffffff832466c3>] sk_stream_alloc_skb+0xa3/0x5d0 net/ipv4/tcp.c:833
>> [<ffffffff83249164>] tcp_sendmsg+0xd34/0x2b00 net/ipv4/tcp.c:1178
>> [<ffffffff83300ef3>] inet_sendmsg+0x203/0x4d0 net/ipv4/af_inet.c:755
>> Freed:
>> [<ffffffff82f372fd>] __kfree_skb+0x1d/0x20 net/core/skbuff.c:676
>> [<ffffffff83288834>] sk_wmem_free_skb include/net/sock.h:1447 [inline]
>> [<ffffffff83288834>] tcp_write_queue_purge include/net/tcp.h:1460 [inline]
>> [<ffffffff83288834>] tcp_connect_init net/ipv4/tcp_output.c:3122 [inline]
>> [<ffffffff83288834>] tcp_connect+0xb24/0x30c0 net/ipv4/tcp_output.c:3261
>> [<ffffffff8329b991>] tcp_v4_connect+0xf31/0x1890 net/ipv4/tcp_ipv4.c:246
>>
>> BUG: KASAN: use-after-free in tcp_skb_pcount include/net/tcp.h:796 [inline]
>> BUG: KASAN: use-after-free in tcp_init_tso_segs net/ipv4/tcp_output.c:1619 [inline]
>> BUG: KASAN: use-after-free in tcp_write_xmit+0x3fc2/0x4cb0 net/ipv4/tcp_output.c:2056
>> [<ffffffff81515cd5>] kasan_report.cold.7+0x175/0x2f7 mm/kasan/report.c:408
>> [<ffffffff814f9784>] __asan_report_load2_noabort+0x14/0x20 mm/kasan/report.c:427
>> [<ffffffff83286582>] tcp_skb_pcount include/net/tcp.h:796 [inline]
>> [<ffffffff83286582>] tcp_init_tso_segs net/ipv4/tcp_output.c:1619 [inline]
>> [<ffffffff83286582>] tcp_write_xmit+0x3fc2/0x4cb0 net/ipv4/tcp_output.c:2056
>> [<ffffffff83287a40>] __tcp_push_pending_frames+0xa0/0x290 net/ipv4/tcp_output.c:2307
>>
>> stable 4.4 and stable 4.9 don't have the commit abb4a8b870b5 ("tcp: purge write queue upon RST")
>> which is referred in dbbf2d1e4077,
>> in tcp_connect_init, it calls tcp_write_queue_purge, and does not reset sk_send_head, then UAF.
>>
>> stable 4.14 have the commit abb4a8b870b5 ("tcp: purge write queue upon RST"),
>> in tcp_reset, it calls tcp_write_queue_purge(sk), and does not reset sk_send_head, then UAF.
>>
>> So this patch can be used to fix stable 4.4 and 4.9.
>>
>> Fixes: a27fd7a8ed38 (tcp: purge write queue upon RST)
>> Reported-by: Timofey Titovets <nefelim4ag@gmail.com>
>> Reported-by: Yongjian Xu <yongjianchn@gmail.com>
>> Signed-off-by: Eric Dumazet <edumazet@google.com>
>> Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com>
>> Tested-by: Yongjian Xu <yongjianchn@gmail.com>
>>
>> Signed-off-by: David S. Miller <davem@davemloft.net>
>> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Signed-off-by: Mao Wenan <maowenan@huawei.com>
>
> So the "Fixes:" commit in the commit message is wrong? What's the actual
> commit that this fixes?
Upstream commit is 7f582b248d0a ("tcp: purge write queue in tcp_connect_init()")
linux-4.4.y
Fixes: 5bbe138a250e ("tcp: purge write queue in tcp_connect_init()")
linux-4.9.y
Fixes: 74a4c09d4b05 ("tcp: purge write queue in tcp_connect_init()")
linux-4.14.y
Fixes: a27fd7a8ed38 ("tcp: purge write queue upon RST")
>
> --
> Thanks,
> Sasha
>
> .
>
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: net: Add aspeed,ast2600-mdio binding
From: Andrew Jeffery @ 2019-07-30 0:47 UTC (permalink / raw)
To: Rob Herring
Cc: netdev, David Miller, Mark Rutland, Joel Stanley, Andrew Lunn,
Florian Fainelli, Heiner Kallweit, devicetree,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
linux-aspeed, linux-kernel@vger.kernel.org
In-Reply-To: <CAL_JsqLytwfsoyS6TSnpPgTjRTOR0TeQwroX21AHqj3A1mPJ5Q@mail.gmail.com>
On Tue, 30 Jul 2019, at 09:07, Rob Herring wrote:
> On Sun, Jul 28, 2019 at 10:39 PM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > The AST2600 splits out the MDIO bus controller from the MAC into its own
> > IP block and rearranges the register layout. Add a new binding to
> > describe the new hardware.
> >
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> > .../bindings/net/aspeed,ast2600-mdio.yaml | 61 +++++++++++++++++++
> > 1 file changed, 61 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> > new file mode 100644
> > index 000000000000..fa86f6438473
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
> > @@ -0,0 +1,61 @@
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/net/aspeed,ast2600-mdio.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: ASPEED AST2600 MDIO Controller
> > +
> > +maintainers:
> > + - Andrew Jeffery <andrew@aj.id.au>
> > +
> > +description: |+
> > + The ASPEED AST2600 MDIO controller is the third iteration of ASPEED's MDIO
> > + bus register interface, this time also separating out the controller from the
> > + MAC.
> > +
>
> Should have a:
>
> allOf:
> - $ref: "mdio.yaml#"
Ack.
>
> > +properties:
> > + compatible:
> > + const: aspeed,ast2600-mdio
> > + reg:
> > + maxItems: 1
> > + description: The register range of the MDIO controller instance
>
> > + "#address-cells":
> > + const: 1
> > + "#size-cells":
> > + const: 0
>
> Then you can drop these 2.
Great.
>
> > +
> > +patternProperties:
> > + "^ethernet-phy@[a-f0-9]$":
> > + properties:
> > + reg:
> > + description:
> > + The MDIO bus index of the PHY
>
> And this.
>
> > + compatible:
> > + enum:
> > + - ethernet-phy-ieee802.3-c22
> > + - ethernet-phy-ieee802.3-c45
>
> This isn't specific to ASpeed either and is already covered by
> ethernet-phy.yaml.
>
> So that means none of the child node schema is needed here.
Bah, I'd developed the patches on v5.2 while waiting for v5.3-rc1 to come
out.
>
> > + required:
> > + - reg
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - "#address-cells"
> > + - "#size-cells"
> > +
> > +examples:
> > + - |
> > + mdio0: mdio@1e650000 {
> > + compatible = "aspeed,ast2600-mdio";
> > + reg = <0x1e650000 0x8>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + status = "okay";
>
> Don't show status in examples.
Sorry, copy/paste at fault.
Thanks for the feedback.
Andrew
>
> > +
> > + ethphy0: ethernet-phy@0 {
> > + compatible = "ethernet-phy-ieee802.3-c22";
> > + reg = <0>;
> > + };
> > + };
> > --
> > 2.20.1
> >
>
^ permalink raw reply
* Re: [PATCH net] net: ipv6: Fix a bug in ndisc_send_ns when netdev only has a global address
From: David Ahern @ 2019-07-30 0:23 UTC (permalink / raw)
To: Su Yanjun, davem, kuznet, yoshfuji; +Cc: netdev, linux-kernel
In-Reply-To: <1564368591-42301-1-git-send-email-suyj.fnst@cn.fujitsu.com>
On 7/28/19 8:49 PM, Su Yanjun wrote:
> When we send mpls packets and the interface only has a
> manual global ipv6 address, then the two hosts cant communicate.
> I find that in ndisc_send_ns it only tries to get a ll address.
> In my case, the executive path is as below.
> ip6_output
> ->ip6_finish_output
> ->lwtunnel_xmit
> ->mpls_xmit
> ->neigh_resolve_output
> ->neigh_probe
> ->ndisc_solicit
> ->ndisc_send_ns
for the archives, this is not an MPLS problem but a general IPv6
forwarding problem when the egress interface does not have a link local
address.
>
> In RFC4861, 7.2.2 says
> "If the source address of the packet prompting the solicitation is the
> same as one of the addresses assigned to the outgoing interface, that
> address SHOULD be placed in the IP Source Address of the outgoing
> solicitation. Otherwise, any one of the addresses assigned to the
> interface should be used."
>
> In this patch we try get a global address if we get ll address failed.
>
> Signed-off-by: Su Yanjun <suyj.fnst@cn.fujitsu.com>
> ---
> include/net/addrconf.h | 4 ++++
> net/ipv6/addrconf.c | 34 ++++++++++++++++++++++++++++++++++
> net/ipv6/ndisc.c | 8 ++++++--
> 3 files changed, 44 insertions(+), 2 deletions(-)
>
> diff --git a/include/net/addrconf.h b/include/net/addrconf.h
> index becdad5..006db8e 100644
> --- a/include/net/addrconf.h
> +++ b/include/net/addrconf.h
> @@ -107,6 +107,10 @@ int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
> u32 banned_flags);
> int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
> u32 banned_flags);
> +int __ipv6_get_addr(struct inet6_dev *idev, struct in6_addr *addr,
> + u32 banned_flags);
no reason to export __ipv6_get_addr. I suspect you copied
__ipv6_get_lladdr but it has an external (to addrconf.c) user. In this
case only ipv6_get_addr needs to be exported.
> +int ipv6_get_addr(struct net_device *dev, struct in6_addr *addr,
> + u32 banned_flags);
> bool inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
> bool match_wildcard);
> bool inet_rcv_saddr_any(const struct sock *sk);
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 521e320..4c0a43f 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -1870,6 +1870,40 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
> return err;
> }
>
> +int __ipv6_get_addr(struct inet6_dev *idev, struct in6_addr *addr,
> + u32 banned_flags)
> +{
> + struct inet6_ifaddr *ifp;
> + int err = -EADDRNOTAVAIL;
> +
> + list_for_each_entry_reverse(ifp, &idev->addr_list, if_list) {
Addresses are ordered by scope. __ipv6_get_lladdr uses
list_for_each_entry_reverse because the LLA's are after the globals.
Since this is falling back to 'give an address' from this interface, I
think you can just use list_for_each_entry.
> + if (ifp->scope == 0 &&
> + !(ifp->flags & banned_flags)) {
> + *addr = ifp->addr;
> + err = 0;
> + break;
> + }
> + }
> + return err;
> +}
> +
> +int ipv6_get_addr(struct net_device *dev, struct in6_addr *addr,
> + u32 banned_flags)
> +{
> + struct inet6_dev *idev;
> + int err = -EADDRNOTAVAIL;
> +
> + rcu_read_lock();
> + idev = __in6_dev_get(dev);
> + if (idev) {
> + read_lock_bh(&idev->lock);
> + err = __ipv6_get_addr(idev, addr, banned_flags);
> + read_unlock_bh(&idev->lock);
> + }
> + rcu_read_unlock();
> + return err;
> +}
> +
> static int ipv6_count_addresses(const struct inet6_dev *idev)
> {
> const struct inet6_ifaddr *ifp;
> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
> index 083cc1c..18ac2fb 100644
> --- a/net/ipv6/ndisc.c
> +++ b/net/ipv6/ndisc.c
> @@ -606,8 +606,12 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
>
> if (!saddr) {
And since you are going to do a v2, another nit - define a local banned
flags and use it for both lookups just to make it clear.
u32 banned_flags = IFA_F_TENTATIVE | IFA_F_OPTIMISTIC;
> if (ipv6_get_lladdr(dev, &addr_buf,
> - (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
> - return;
> + (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC))) {
> + /* try global address */
> + if (ipv6_get_addr(dev, &addr_buf,
> + (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)))
> + return;
> + }
> saddr = &addr_buf;
> }
>
>
^ permalink raw reply
* Re: [PATCH net-next v4 2/3] flow_offload: Support get default block from tc immediately
From: wenxu @ 2019-07-30 0:10 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: pablo, fw, netfilter-devel, netdev
In-Reply-To: <20190729095526.17214c4d@cakuba.netronome.com>
在 2019/7/30 0:55, Jakub Kicinski 写道:
> On Mon, 29 Jul 2019 15:18:03 +0800, wenxu wrote:
>> On 7/29/2019 12:42 PM, Jakub Kicinski wrote:
>>> On Mon, 29 Jul 2019 10:43:56 +0800, wenxu wrote:
>>>> On 7/29/2019 4:16 AM, Jakub Kicinski wrote:
>>>>> I don't know the nft code, but it seems unlikely it wouldn't have the
>>>>> same problem/need..
>>>> nft don't have the same problem. The offload rule can only attached
>>>> to offload base chain.
>>>>
>>>> Th offload base chain is created after the device driver loaded (the
>>>> device exist).
>>> For indirect blocks the block is on the tunnel device and the offload
>>> target is another device. E.g. you offload rules from a VXLAN device
>>> onto the ASIC. The ASICs driver does not have to be loaded when VXLAN
>>> device is created.
>>>
>>> So I feel like either the chain somehow directly references the offload
>>> target (in which case the indirect infrastructure with hash lookup etc
>>> is not needed for nft), or indirect infra is needed, and we need to take
>>> care of replays.
>> I think the nft is different with tc.
>>
>> In tc case we can create vxlan device add a ingress qdisc with a block success
>>
>> Then the ASIC driver loaded, then register the vxlan indr-dev and get the block
>> adn replay it to hardware
>>
>> But in the nft case, The base chain flags with offload. Create an offload netdev
>> base chain on vxlan device will fail if there is no indr-device to offload.
> Can you show us the offload chain spec? Does it specify offload to the
> vxlan device or the ASIC device?
nft add chain netdev firewall aclout { type filter hook ingress offload device vxlan0 priority - 300 \; }
>
> Indir-devs can come and go, how do you handle a situation where offload
> chain was installed with indir listener present, but then the ASIC
> driver got removed?
yes, I think nft is also need to get the default block in the indr-regster-cb
for the go aways and reload again case
>
^ permalink raw reply
* [net-next 11/13] net/mlx5e: Eswitch, use state_lock to synchronize vlan change
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
esw->state_lock is already used to protect vlan vport configuration change.
However, all preparation and correctness checks, and code that sets vport
data are not protected by this lock and assume external synchronization by
rtnl lock. In order to remove dependency on rtnl lock, extend
esw->state_lock protection to whole eswitch vlan add/del functions.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 15 ++++++++-------
.../mellanox/mlx5/core/eswitch_offloads.c | 17 ++++++++++++-----
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index d365551d2f10..7a0888470fae 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -2086,23 +2086,19 @@ int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
if (vlan > 4095 || qos > 7)
return -EINVAL;
- mutex_lock(&esw->state_lock);
-
err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set_flags);
if (err)
- goto unlock;
+ return err;
evport->info.vlan = vlan;
evport->info.qos = qos;
if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY) {
err = esw_vport_ingress_config(esw, evport);
if (err)
- goto unlock;
+ return err;
err = esw_vport_egress_config(esw, evport);
}
-unlock:
- mutex_unlock(&esw->state_lock);
return err;
}
@@ -2110,11 +2106,16 @@ int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
u16 vport, u16 vlan, u8 qos)
{
u8 set_flags = 0;
+ int err;
if (vlan || qos)
set_flags = SET_VLAN_STRIP | SET_VLAN_INSERT;
- return __mlx5_eswitch_set_vport_vlan(esw, vport, vlan, qos, set_flags);
+ mutex_lock(&esw->state_lock);
+ err = __mlx5_eswitch_set_vport_vlan(esw, vport, vlan, qos, set_flags);
+ mutex_unlock(&esw->state_lock);
+
+ return err;
}
int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 244ad1893691..d502c91c148c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -442,9 +442,11 @@ int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
fwd = !!((attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
!attr->dest_chain);
+ mutex_lock(&esw->state_lock);
+
err = esw_add_vlan_action_check(attr, push, pop, fwd);
if (err)
- return err;
+ goto unlock;
attr->vlan_handled = false;
@@ -457,11 +459,11 @@ int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
attr->vlan_handled = true;
}
- return 0;
+ goto unlock;
}
if (!push && !pop)
- return 0;
+ goto unlock;
if (!(offloads->vlan_push_pop_refcount)) {
/* it's the 1st vlan rule, apply global vlan pop policy */
@@ -486,6 +488,8 @@ int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
out:
if (!err)
attr->vlan_handled = true;
+unlock:
+ mutex_unlock(&esw->state_lock);
return err;
}
@@ -508,6 +512,8 @@ int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
+ mutex_lock(&esw->state_lock);
+
vport = esw_vlan_action_get_vport(attr, push, pop);
if (!push && !pop && fwd) {
@@ -515,7 +521,7 @@ int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK)
vport->vlan_refcount--;
- return 0;
+ goto out;
}
if (push) {
@@ -533,12 +539,13 @@ int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
skip_unset_push:
offloads->vlan_push_pop_refcount--;
if (offloads->vlan_push_pop_refcount)
- return 0;
+ goto out;
/* no more vlan rules, stop global vlan pop policy */
err = esw_set_global_vlan_pop(esw, 0);
out:
+ mutex_unlock(&esw->state_lock);
return err;
}
--
2.21.0
^ permalink raw reply related
* [net-next 07/13] net/mlx5e: Change flow flags type to unsigned long
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
To remove dependency on rtnl lock and allow concurrent modification of
'flags' field of tc flow structure, change flow flag type to unsigned long
and use atomic bit ops for reading and changing the flags. Implement
auxiliary functions for setting, resetting and getting specific flag, and
for checking most often used flag values.
Always set flags with smp_mb__before_atomic() to ensure that all
mlx5e_tc_flow are updated before concurrent readers can read new flags
value. Rearrange all code paths to actually set flow->rule[] pointers
before setting the OFFLOADED flag. On read side, use smp_mb__after_atomic()
when accessing flags to ensure that offload-related flow fields are only
read after the flags.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/en_main.c | 8 +-
.../net/ethernet/mellanox/mlx5/core/en_rep.c | 6 +-
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 206 +++++++++++-------
.../net/ethernet/mellanox/mlx5/core/en_tc.h | 26 ++-
4 files changed, 149 insertions(+), 97 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 266783295124..b2618dd6dd10 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -3429,7 +3429,7 @@ static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv,
#ifdef CONFIG_MLX5_ESWITCH
static int mlx5e_setup_tc_cls_flower(struct mlx5e_priv *priv,
struct flow_cls_offload *cls_flower,
- int flags)
+ unsigned long flags)
{
switch (cls_flower->command) {
case FLOW_CLS_REPLACE:
@@ -3449,12 +3449,12 @@ static int mlx5e_setup_tc_cls_flower(struct mlx5e_priv *priv,
static int mlx5e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
+ unsigned long flags = MLX5_TC_FLAG(INGRESS) | MLX5_TC_FLAG(NIC_OFFLOAD);
struct mlx5e_priv *priv = cb_priv;
switch (type) {
case TC_SETUP_CLSFLOWER:
- return mlx5e_setup_tc_cls_flower(priv, type_data, MLX5E_TC_INGRESS |
- MLX5E_TC_NIC_OFFLOAD);
+ return mlx5e_setup_tc_cls_flower(priv, type_data, flags);
default:
return -EOPNOTSUPP;
}
@@ -3647,7 +3647,7 @@ static int set_feature_tc_num_filters(struct net_device *netdev, bool enable)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
- if (!enable && mlx5e_tc_num_filters(priv, MLX5E_TC_NIC_OFFLOAD)) {
+ if (!enable && mlx5e_tc_num_filters(priv, MLX5_TC_FLAG(NIC_OFFLOAD))) {
netdev_err(netdev,
"Active offloaded tc filters, can't turn hw_tc_offload off\n");
return -EINVAL;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 496d3034e278..69f7ac8fc9be 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -659,8 +659,8 @@ mlx5e_rep_indr_offload(struct net_device *netdev,
struct flow_cls_offload *flower,
struct mlx5e_rep_indr_block_priv *indr_priv)
{
+ unsigned long flags = MLX5_TC_FLAG(EGRESS) | MLX5_TC_FLAG(ESW_OFFLOAD);
struct mlx5e_priv *priv = netdev_priv(indr_priv->rpriv->netdev);
- int flags = MLX5E_TC_EGRESS | MLX5E_TC_ESW_OFFLOAD;
int err = 0;
switch (flower->command) {
@@ -1159,12 +1159,12 @@ mlx5e_rep_setup_tc_cls_flower(struct mlx5e_priv *priv,
static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
+ unsigned long flags = MLX5_TC_FLAG(INGRESS) | MLX5_TC_FLAG(ESW_OFFLOAD);
struct mlx5e_priv *priv = cb_priv;
switch (type) {
case TC_SETUP_CLSFLOWER:
- return mlx5e_rep_setup_tc_cls_flower(priv, type_data, MLX5E_TC_INGRESS |
- MLX5E_TC_ESW_OFFLOAD);
+ return mlx5e_rep_setup_tc_cls_flower(priv, type_data, flags);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index e2b87f723819..241157b699df 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -66,19 +66,19 @@ struct mlx5_nic_flow_attr {
struct mlx5_fc *counter;
};
-#define MLX5E_TC_FLOW_BASE (MLX5E_TC_LAST_EXPORTED_BIT + 1)
+#define MLX5E_TC_FLOW_BASE (MLX5E_TC_FLAG_LAST_EXPORTED_BIT + 1)
enum {
- MLX5E_TC_FLOW_INGRESS = MLX5E_TC_INGRESS,
- MLX5E_TC_FLOW_EGRESS = MLX5E_TC_EGRESS,
- MLX5E_TC_FLOW_ESWITCH = MLX5E_TC_ESW_OFFLOAD,
- MLX5E_TC_FLOW_NIC = MLX5E_TC_NIC_OFFLOAD,
- MLX5E_TC_FLOW_OFFLOADED = BIT(MLX5E_TC_FLOW_BASE),
- MLX5E_TC_FLOW_HAIRPIN = BIT(MLX5E_TC_FLOW_BASE + 1),
- MLX5E_TC_FLOW_HAIRPIN_RSS = BIT(MLX5E_TC_FLOW_BASE + 2),
- MLX5E_TC_FLOW_SLOW = BIT(MLX5E_TC_FLOW_BASE + 3),
- MLX5E_TC_FLOW_DUP = BIT(MLX5E_TC_FLOW_BASE + 4),
- MLX5E_TC_FLOW_NOT_READY = BIT(MLX5E_TC_FLOW_BASE + 5),
+ MLX5E_TC_FLOW_FLAG_INGRESS = MLX5E_TC_FLAG_INGRESS_BIT,
+ MLX5E_TC_FLOW_FLAG_EGRESS = MLX5E_TC_FLAG_EGRESS_BIT,
+ MLX5E_TC_FLOW_FLAG_ESWITCH = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT,
+ MLX5E_TC_FLOW_FLAG_NIC = MLX5E_TC_FLAG_NIC_OFFLOAD_BIT,
+ MLX5E_TC_FLOW_FLAG_OFFLOADED = MLX5E_TC_FLOW_BASE,
+ MLX5E_TC_FLOW_FLAG_HAIRPIN = MLX5E_TC_FLOW_BASE + 1,
+ MLX5E_TC_FLOW_FLAG_HAIRPIN_RSS = MLX5E_TC_FLOW_BASE + 2,
+ MLX5E_TC_FLOW_FLAG_SLOW = MLX5E_TC_FLOW_BASE + 3,
+ MLX5E_TC_FLOW_FLAG_DUP = MLX5E_TC_FLOW_BASE + 4,
+ MLX5E_TC_FLOW_FLAG_NOT_READY = MLX5E_TC_FLOW_BASE + 5,
};
#define MLX5E_TC_MAX_SPLITS 1
@@ -109,7 +109,7 @@ struct mlx5e_tc_flow {
struct rhash_head node;
struct mlx5e_priv *priv;
u64 cookie;
- u16 flags;
+ unsigned long flags;
struct mlx5_flow_handle *rule[MLX5E_TC_MAX_SPLITS + 1];
/* Flow can be associated with multiple encap IDs.
* The number of encaps is bounded by the number of supported
@@ -205,6 +205,47 @@ static void mlx5e_flow_put(struct mlx5e_priv *priv,
}
}
+static void __flow_flag_set(struct mlx5e_tc_flow *flow, unsigned long flag)
+{
+ /* Complete all memory stores before setting bit. */
+ smp_mb__before_atomic();
+ set_bit(flag, &flow->flags);
+}
+
+#define flow_flag_set(flow, flag) __flow_flag_set(flow, MLX5E_TC_FLOW_FLAG_##flag)
+
+static void __flow_flag_clear(struct mlx5e_tc_flow *flow, unsigned long flag)
+{
+ /* Complete all memory stores before clearing bit. */
+ smp_mb__before_atomic();
+ clear_bit(flag, &flow->flags);
+}
+
+#define flow_flag_clear(flow, flag) __flow_flag_clear(flow, \
+ MLX5E_TC_FLOW_FLAG_##flag)
+
+static bool __flow_flag_test(struct mlx5e_tc_flow *flow, unsigned long flag)
+{
+ bool ret = test_bit(flag, &flow->flags);
+
+ /* Read fields of flow structure only after checking flags. */
+ smp_mb__after_atomic();
+ return ret;
+}
+
+#define flow_flag_test(flow, flag) __flow_flag_test(flow, \
+ MLX5E_TC_FLOW_FLAG_##flag)
+
+static bool mlx5e_is_eswitch_flow(struct mlx5e_tc_flow *flow)
+{
+ return flow_flag_test(flow, ESWITCH);
+}
+
+static bool mlx5e_is_offloaded_flow(struct mlx5e_tc_flow *flow)
+{
+ return flow_flag_test(flow, OFFLOADED);
+}
+
static inline u32 hash_mod_hdr_info(struct mod_hdr_key *key)
{
return jhash(key->actions,
@@ -226,9 +267,9 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
int num_actions, actions_size, namespace, err;
+ bool found = false, is_eswitch_flow;
struct mlx5e_mod_hdr_entry *mh;
struct mod_hdr_key key;
- bool found = false;
u32 hash_key;
num_actions = parse_attr->num_mod_hdr_actions;
@@ -239,7 +280,8 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
hash_key = hash_mod_hdr_info(&key);
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
+ is_eswitch_flow = mlx5e_is_eswitch_flow(flow);
+ if (is_eswitch_flow) {
namespace = MLX5_FLOW_NAMESPACE_FDB;
hash_for_each_possible(esw->offloads.mod_hdr_tbl, mh,
mod_hdr_hlist, hash_key) {
@@ -278,14 +320,14 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
if (err)
goto out_err;
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
+ if (is_eswitch_flow)
hash_add(esw->offloads.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key);
else
hash_add(priv->fs.tc.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key);
attach_flow:
list_add(&flow->mod_hdr, &mh->flows);
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
+ if (is_eswitch_flow)
flow->esw_attr->mod_hdr_id = mh->mod_hdr_id;
else
flow->nic_attr->mod_hdr_id = mh->mod_hdr_id;
@@ -700,7 +742,7 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
attach_flow:
if (hpe->hp->num_channels > 1) {
- flow->flags |= MLX5E_TC_FLOW_HAIRPIN_RSS;
+ flow_flag_set(flow, HAIRPIN_RSS);
flow->nic_attr->hairpin_ft = hpe->hp->ttc.ft.t;
} else {
flow->nic_attr->hairpin_tirn = hpe->hp->tirn;
@@ -761,12 +803,12 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
flow_context->flow_tag = attr->flow_tag;
- if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) {
+ if (flow_flag_test(flow, HAIRPIN)) {
err = mlx5e_hairpin_flow_add(priv, flow, parse_attr, extack);
if (err)
return err;
- if (flow->flags & MLX5E_TC_FLOW_HAIRPIN_RSS) {
+ if (flow_flag_test(flow, HAIRPIN_RSS)) {
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[dest_ix].ft = attr->hairpin_ft;
} else {
@@ -849,7 +891,7 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
mlx5_del_flow_rules(flow->rule[0]);
mlx5_fc_destroy(priv->mdev, counter);
- if (!mlx5e_tc_num_filters(priv, MLX5E_TC_NIC_OFFLOAD) && priv->fs.tc.t) {
+ if (!mlx5e_tc_num_filters(priv, MLX5_TC_FLAG(NIC_OFFLOAD)) && priv->fs.tc.t) {
mlx5_destroy_flow_table(priv->fs.tc.t);
priv->fs.tc.t = NULL;
}
@@ -857,7 +899,7 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
mlx5e_detach_mod_hdr(priv, flow);
- if (flow->flags & MLX5E_TC_FLOW_HAIRPIN)
+ if (flow_flag_test(flow, HAIRPIN))
mlx5e_hairpin_flow_del(priv, flow);
}
@@ -892,7 +934,6 @@ mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw,
}
}
- flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
return rule;
}
@@ -901,7 +942,7 @@ mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw,
struct mlx5e_tc_flow *flow,
struct mlx5_esw_flow_attr *attr)
{
- flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
+ flow_flag_clear(flow, OFFLOADED);
if (attr->split_count)
mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr);
@@ -924,7 +965,7 @@ mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw,
rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr);
if (!IS_ERR(rule))
- flow->flags |= MLX5E_TC_FLOW_SLOW;
+ flow_flag_set(flow, SLOW);
return rule;
}
@@ -939,7 +980,7 @@ mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw,
slow_attr->split_count = 0;
slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN;
mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr);
- flow->flags &= ~MLX5E_TC_FLOW_SLOW;
+ flow_flag_clear(flow, SLOW);
}
static void add_unready_flow(struct mlx5e_tc_flow *flow)
@@ -952,14 +993,14 @@ static void add_unready_flow(struct mlx5e_tc_flow *flow)
rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
uplink_priv = &rpriv->uplink_priv;
- flow->flags |= MLX5E_TC_FLOW_NOT_READY;
+ flow_flag_set(flow, NOT_READY);
list_add_tail(&flow->unready, &uplink_priv->unready_flows);
}
static void remove_unready_flow(struct mlx5e_tc_flow *flow)
{
list_del(&flow->unready);
- flow->flags &= ~MLX5E_TC_FLOW_NOT_READY;
+ flow_flag_clear(flow, NOT_READY);
}
static int
@@ -1049,6 +1090,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
if (IS_ERR(flow->rule[0]))
return PTR_ERR(flow->rule[0]);
+ else
+ flow_flag_set(flow, OFFLOADED);
return 0;
}
@@ -1074,14 +1117,14 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
struct mlx5_esw_flow_attr slow_attr;
int out_index;
- if (flow->flags & MLX5E_TC_FLOW_NOT_READY) {
+ if (flow_flag_test(flow, NOT_READY)) {
remove_unready_flow(flow);
kvfree(attr->parse_attr);
return;
}
- if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
- if (flow->flags & MLX5E_TC_FLOW_SLOW)
+ if (mlx5e_is_offloaded_flow(flow)) {
+ if (flow_flag_test(flow, SLOW))
mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr);
else
mlx5e_tc_unoffload_fdb_rules(esw, flow, attr);
@@ -1166,8 +1209,9 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
}
mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr);
- flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when slow path rule removed */
flow->rule[0] = rule;
+ /* was unset when slow path rule removed */
+ flow_flag_set(flow, OFFLOADED);
loop_cont:
mlx5e_flow_put(priv, flow);
@@ -1205,8 +1249,9 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
}
mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr);
- flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when fast path rule removed */
flow->rule[0] = rule;
+ /* was unset when fast path rule removed */
+ flow_flag_set(flow, OFFLOADED);
loop_cont:
mlx5e_flow_put(priv, flow);
@@ -1219,7 +1264,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow)
{
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
+ if (mlx5e_is_eswitch_flow(flow))
return flow->esw_attr->counter;
else
return flow->nic_attr->counter;
@@ -1255,7 +1300,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
if (IS_ERR(mlx5e_flow_get(flow)))
continue;
- if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
+ if (mlx5e_is_offloaded_flow(flow)) {
counter = mlx5e_tc_get_counter(flow);
mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
@@ -1315,15 +1360,15 @@ static void __mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow)
{
struct mlx5_eswitch *esw = flow->priv->mdev->priv.eswitch;
- if (!(flow->flags & MLX5E_TC_FLOW_ESWITCH) ||
- !(flow->flags & MLX5E_TC_FLOW_DUP))
+ if (!flow_flag_test(flow, ESWITCH) ||
+ !flow_flag_test(flow, DUP))
return;
mutex_lock(&esw->offloads.peer_mutex);
list_del(&flow->peer);
mutex_unlock(&esw->offloads.peer_mutex);
- flow->flags &= ~MLX5E_TC_FLOW_DUP;
+ flow_flag_clear(flow, DUP);
mlx5e_tc_del_fdb_flow(flow->peer_flow->priv, flow->peer_flow);
kvfree(flow->peer_flow);
@@ -1347,7 +1392,7 @@ static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow)
static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow)
{
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
+ if (mlx5e_is_eswitch_flow(flow)) {
mlx5e_tc_del_fdb_peer_flow(flow);
mlx5e_tc_del_fdb_flow(priv, flow);
} else {
@@ -1845,11 +1890,13 @@ static int parse_cls_flower(struct mlx5e_priv *priv,
struct mlx5e_rep_priv *rpriv = priv->ppriv;
u8 match_level, tunnel_match_level = MLX5_MATCH_NONE;
struct mlx5_eswitch_rep *rep;
+ bool is_eswitch_flow;
int err;
err = __parse_cls_flower(priv, spec, f, filter_dev, &match_level, &tunnel_match_level);
- if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH)) {
+ is_eswitch_flow = mlx5e_is_eswitch_flow(flow);
+ if (!err && is_eswitch_flow) {
rep = rpriv->rep;
if (rep->vport != MLX5_VPORT_UPLINK &&
(esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE &&
@@ -1863,7 +1910,7 @@ static int parse_cls_flower(struct mlx5e_priv *priv,
}
}
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
+ if (is_eswitch_flow) {
flow->esw_attr->match_level = match_level;
flow->esw_attr->tunnel_match_level = tunnel_match_level;
} else {
@@ -2384,12 +2431,12 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
{
u32 actions;
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
+ if (mlx5e_is_eswitch_flow(flow))
actions = flow->esw_attr->action;
else
actions = flow->nic_attr->action;
- if (flow->flags & MLX5E_TC_FLOW_EGRESS &&
+ if (flow_flag_test(flow, EGRESS) &&
!((actions & MLX5_FLOW_CONTEXT_ACTION_DECAP) ||
(actions & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP)))
return false;
@@ -2541,7 +2588,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
if (priv->netdev->netdev_ops == peer_dev->netdev_ops &&
same_hw_devs(priv, netdev_priv(peer_dev))) {
parse_attr->mirred_ifindex[0] = peer_dev->ifindex;
- flow->flags |= MLX5E_TC_FLOW_HAIRPIN;
+ flow_flag_set(flow, HAIRPIN);
action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
} else {
@@ -3065,19 +3112,19 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
return 0;
}
-static void get_flags(int flags, u16 *flow_flags)
+static void get_flags(int flags, unsigned long *flow_flags)
{
- u16 __flow_flags = 0;
+ unsigned long __flow_flags = 0;
- if (flags & MLX5E_TC_INGRESS)
- __flow_flags |= MLX5E_TC_FLOW_INGRESS;
- if (flags & MLX5E_TC_EGRESS)
- __flow_flags |= MLX5E_TC_FLOW_EGRESS;
+ if (flags & MLX5_TC_FLAG(INGRESS))
+ __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_INGRESS);
+ if (flags & MLX5_TC_FLAG(EGRESS))
+ __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_EGRESS);
- if (flags & MLX5E_TC_ESW_OFFLOAD)
- __flow_flags |= MLX5E_TC_FLOW_ESWITCH;
- if (flags & MLX5E_TC_NIC_OFFLOAD)
- __flow_flags |= MLX5E_TC_FLOW_NIC;
+ if (flags & MLX5_TC_FLAG(ESW_OFFLOAD))
+ __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_ESWITCH);
+ if (flags & MLX5_TC_FLAG(NIC_OFFLOAD))
+ __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_NIC);
*flow_flags = __flow_flags;
}
@@ -3089,12 +3136,13 @@ static const struct rhashtable_params tc_ht_params = {
.automatic_shrinking = true,
};
-static struct rhashtable *get_tc_ht(struct mlx5e_priv *priv, int flags)
+static struct rhashtable *get_tc_ht(struct mlx5e_priv *priv,
+ unsigned long flags)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5e_rep_priv *uplink_rpriv;
- if (flags & MLX5E_TC_ESW_OFFLOAD) {
+ if (flags & MLX5_TC_FLAG(ESW_OFFLOAD)) {
uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
return &uplink_rpriv->uplink_priv.tc_ht;
} else /* NIC offload */
@@ -3105,7 +3153,7 @@ static bool is_peer_flow_needed(struct mlx5e_tc_flow *flow)
{
struct mlx5_esw_flow_attr *attr = flow->esw_attr;
bool is_rep_ingress = attr->in_rep->vport != MLX5_VPORT_UPLINK &&
- flow->flags & MLX5E_TC_FLOW_INGRESS;
+ flow_flag_test(flow, INGRESS);
bool act_is_encap = !!(attr->action &
MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT);
bool esw_paired = mlx5_devcom_is_paired(attr->in_mdev->priv.devcom,
@@ -3124,7 +3172,7 @@ static bool is_peer_flow_needed(struct mlx5e_tc_flow *flow)
static int
mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
- struct flow_cls_offload *f, u16 flow_flags,
+ struct flow_cls_offload *f, unsigned long flow_flags,
struct mlx5e_tc_flow_parse_attr **__parse_attr,
struct mlx5e_tc_flow **__flow)
{
@@ -3186,7 +3234,7 @@ mlx5e_flow_esw_attr_init(struct mlx5_esw_flow_attr *esw_attr,
static struct mlx5e_tc_flow *
__mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
struct flow_cls_offload *f,
- u16 flow_flags,
+ unsigned long flow_flags,
struct net_device *filter_dev,
struct mlx5_eswitch_rep *in_rep,
struct mlx5_core_dev *in_mdev)
@@ -3197,7 +3245,7 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow;
int attr_size, err;
- flow_flags |= MLX5E_TC_FLOW_ESWITCH;
+ flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_ESWITCH);
attr_size = sizeof(struct mlx5_esw_flow_attr);
err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags,
&parse_attr, &flow);
@@ -3236,7 +3284,7 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
struct mlx5e_tc_flow *flow,
- u16 flow_flags)
+ unsigned long flow_flags)
{
struct mlx5e_priv *priv = flow->priv, *peer_priv;
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch, *peer_esw;
@@ -3274,7 +3322,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
}
flow->peer_flow = peer_flow;
- flow->flags |= MLX5E_TC_FLOW_DUP;
+ flow_flag_set(flow, DUP);
mutex_lock(&esw->offloads.peer_mutex);
list_add_tail(&flow->peer, &esw->offloads.peer_flows);
mutex_unlock(&esw->offloads.peer_mutex);
@@ -3287,7 +3335,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
static int
mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
struct flow_cls_offload *f,
- u16 flow_flags,
+ unsigned long flow_flags,
struct net_device *filter_dev,
struct mlx5e_tc_flow **__flow)
{
@@ -3321,7 +3369,7 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
static int
mlx5e_add_nic_flow(struct mlx5e_priv *priv,
struct flow_cls_offload *f,
- u16 flow_flags,
+ unsigned long flow_flags,
struct net_device *filter_dev,
struct mlx5e_tc_flow **__flow)
{
@@ -3335,7 +3383,7 @@ mlx5e_add_nic_flow(struct mlx5e_priv *priv,
if (!tc_cls_can_offload_and_chain0(priv->netdev, &f->common))
return -EOPNOTSUPP;
- flow_flags |= MLX5E_TC_FLOW_NIC;
+ flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_NIC);
attr_size = sizeof(struct mlx5_nic_flow_attr);
err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags,
&parse_attr, &flow);
@@ -3356,7 +3404,7 @@ mlx5e_add_nic_flow(struct mlx5e_priv *priv,
if (err)
goto err_free;
- flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
+ flow_flag_set(flow, OFFLOADED);
kvfree(parse_attr);
*__flow = flow;
@@ -3372,12 +3420,12 @@ mlx5e_add_nic_flow(struct mlx5e_priv *priv,
static int
mlx5e_tc_add_flow(struct mlx5e_priv *priv,
struct flow_cls_offload *f,
- int flags,
+ unsigned long flags,
struct net_device *filter_dev,
struct mlx5e_tc_flow **flow)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
- u16 flow_flags;
+ unsigned long flow_flags;
int err;
get_flags(flags, &flow_flags);
@@ -3396,7 +3444,7 @@ mlx5e_tc_add_flow(struct mlx5e_priv *priv,
}
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct flow_cls_offload *f, int flags)
+ struct flow_cls_offload *f, unsigned long flags)
{
struct netlink_ext_ack *extack = f->common.extack;
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
@@ -3430,19 +3478,17 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
return err;
}
-#define DIRECTION_MASK (MLX5E_TC_INGRESS | MLX5E_TC_EGRESS)
-#define FLOW_DIRECTION_MASK (MLX5E_TC_FLOW_INGRESS | MLX5E_TC_FLOW_EGRESS)
-
static bool same_flow_direction(struct mlx5e_tc_flow *flow, int flags)
{
- if ((flow->flags & FLOW_DIRECTION_MASK) == (flags & DIRECTION_MASK))
- return true;
+ bool dir_ingress = !!(flags & MLX5_TC_FLAG(INGRESS));
+ bool dir_egress = !!(flags & MLX5_TC_FLAG(EGRESS));
- return false;
+ return flow_flag_test(flow, INGRESS) == dir_ingress &&
+ flow_flag_test(flow, EGRESS) == dir_egress;
}
int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct flow_cls_offload *f, int flags)
+ struct flow_cls_offload *f, unsigned long flags)
{
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
struct mlx5e_tc_flow *flow;
@@ -3459,7 +3505,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
}
int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct flow_cls_offload *f, int flags)
+ struct flow_cls_offload *f, unsigned long flags)
{
struct mlx5_devcom *devcom = priv->mdev->priv.devcom;
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
@@ -3481,7 +3527,7 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
goto errout;
}
- if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
+ if (mlx5e_is_offloaded_flow(flow)) {
counter = mlx5e_tc_get_counter(flow);
if (!counter)
goto errout;
@@ -3496,8 +3542,8 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
if (!peer_esw)
goto out;
- if ((flow->flags & MLX5E_TC_FLOW_DUP) &&
- (flow->peer_flow->flags & MLX5E_TC_FLOW_OFFLOADED)) {
+ if (flow_flag_test(flow, DUP) &&
+ flow_flag_test(flow->peer_flow, OFFLOADED)) {
u64 bytes2;
u64 packets2;
u64 lastuse2;
@@ -3622,7 +3668,7 @@ void mlx5e_tc_esw_cleanup(struct rhashtable *tc_ht)
rhashtable_free_and_destroy(tc_ht, _mlx5e_tc_del_flow, NULL);
}
-int mlx5e_tc_num_filters(struct mlx5e_priv *priv, int flags)
+int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags)
{
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
index 3ab39275ca7d..1cb66bf76997 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
@@ -40,13 +40,15 @@
#ifdef CONFIG_MLX5_ESWITCH
enum {
- MLX5E_TC_INGRESS = BIT(0),
- MLX5E_TC_EGRESS = BIT(1),
- MLX5E_TC_NIC_OFFLOAD = BIT(2),
- MLX5E_TC_ESW_OFFLOAD = BIT(3),
- MLX5E_TC_LAST_EXPORTED_BIT = 3,
+ MLX5E_TC_FLAG_INGRESS_BIT,
+ MLX5E_TC_FLAG_EGRESS_BIT,
+ MLX5E_TC_FLAG_NIC_OFFLOAD_BIT,
+ MLX5E_TC_FLAG_ESW_OFFLOAD_BIT,
+ MLX5E_TC_FLAG_LAST_EXPORTED_BIT = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT,
};
+#define MLX5_TC_FLAG(flag) BIT(MLX5E_TC_FLAG_##flag##_BIT)
+
int mlx5e_tc_nic_init(struct mlx5e_priv *priv);
void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv);
@@ -54,12 +56,12 @@ int mlx5e_tc_esw_init(struct rhashtable *tc_ht);
void mlx5e_tc_esw_cleanup(struct rhashtable *tc_ht);
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct flow_cls_offload *f, int flags);
+ struct flow_cls_offload *f, unsigned long flags);
int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct flow_cls_offload *f, int flags);
+ struct flow_cls_offload *f, unsigned long flags);
int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct flow_cls_offload *f, int flags);
+ struct flow_cls_offload *f, unsigned long flags);
struct mlx5e_encap_entry;
void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
@@ -70,7 +72,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
struct mlx5e_neigh_hash_entry;
void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe);
-int mlx5e_tc_num_filters(struct mlx5e_priv *priv, int flags);
+int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags);
void mlx5e_tc_reoffload_flows_work(struct work_struct *work);
@@ -80,7 +82,11 @@ bool mlx5e_is_valid_eswitch_fwd_dev(struct mlx5e_priv *priv,
#else /* CONFIG_MLX5_ESWITCH */
static inline int mlx5e_tc_nic_init(struct mlx5e_priv *priv) { return 0; }
static inline void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv) {}
-static inline int mlx5e_tc_num_filters(struct mlx5e_priv *priv, int flags) { return 0; }
+static inline int mlx5e_tc_num_filters(struct mlx5e_priv *priv,
+ unsigned long flags)
+{
+ return 0;
+}
#endif
#endif /* __MLX5_EN_TC_H__ */
--
2.21.0
^ permalink raw reply related
* [net-next 13/13] net/mlx5e: Protect tc flow table with mutex
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
TC flow table is created when first flow is added, and destroyed when last
flow is removed. This assumes that all accesses to the table are externally
synchronized with rtnl lock. To remove dependency on rtnl lock, add new
mutex mlx5e_tc_table->t_lock and use it to protect the flow table.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en/fs.h | 2 ++
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 7 +++++++
2 files changed, 9 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
index eb70ada89b09..4518ce19112e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
@@ -10,6 +10,8 @@ enum {
};
struct mlx5e_tc_table {
+ /* protects flow table */
+ struct mutex t_lock;
struct mlx5_flow_table *t;
struct rhashtable ht;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 595a4c5667ea..f3ed028d5017 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -854,6 +854,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
return err;
}
+ mutex_lock(&priv->fs.tc.t_lock);
if (IS_ERR_OR_NULL(priv->fs.tc.t)) {
int tc_grp_size, tc_tbl_size;
u32 max_flow_counter;
@@ -873,6 +874,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
MLX5E_TC_TABLE_NUM_GROUPS,
MLX5E_TC_FT_LEVEL, 0);
if (IS_ERR(priv->fs.tc.t)) {
+ mutex_unlock(&priv->fs.tc.t_lock);
NL_SET_ERR_MSG_MOD(extack,
"Failed to create tc offload table\n");
netdev_err(priv->netdev,
@@ -886,6 +888,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
flow->rule[0] = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
&flow_act, dest, dest_ix);
+ mutex_unlock(&priv->fs.tc.t_lock);
if (IS_ERR(flow->rule[0]))
return PTR_ERR(flow->rule[0]);
@@ -904,10 +907,12 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
mlx5_del_flow_rules(flow->rule[0]);
mlx5_fc_destroy(priv->mdev, counter);
+ mutex_lock(&priv->fs.tc.t_lock);
if (!mlx5e_tc_num_filters(priv, MLX5_TC_FLAG(NIC_OFFLOAD)) && priv->fs.tc.t) {
mlx5_destroy_flow_table(priv->fs.tc.t);
priv->fs.tc.t = NULL;
}
+ mutex_unlock(&priv->fs.tc.t_lock);
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
mlx5e_detach_mod_hdr(priv, flow);
@@ -3684,6 +3689,7 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
struct mlx5e_tc_table *tc = &priv->fs.tc;
int err;
+ mutex_init(&tc->t_lock);
hash_init(tc->mod_hdr_tbl);
hash_init(tc->hairpin_tbl);
@@ -3722,6 +3728,7 @@ void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv)
mlx5_destroy_flow_table(tc->t);
tc->t = NULL;
}
+ mutex_destroy(&tc->t_lock);
}
int mlx5e_tc_esw_init(struct rhashtable *tc_ht)
--
2.21.0
^ permalink raw reply related
* [net-next 12/13] net/mlx5e: Rely on rcu instead of rtnl lock when getting upper dev
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
Function netdev_master_upper_dev_get() generates warning if caller doesn't
hold rtnl lock. Modify rules update path to use rcu version of that
function.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/en/tc_tun.c | 14 +++++++++++++-
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 6 +++++-
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
index ae439d95f5a3..4c4620db3d31 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
@@ -31,11 +31,23 @@ static int get_route_and_out_devs(struct mlx5e_priv *priv,
real_dev = is_vlan_dev(dev) ? vlan_dev_real_dev(dev) : dev;
uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
- uplink_upper = netdev_master_upper_dev_get(uplink_dev);
+
+ rcu_read_lock();
+ uplink_upper = netdev_master_upper_dev_get_rcu(uplink_dev);
+ /* mlx5_lag_is_sriov() is a blocking function which can't be called
+ * while holding rcu read lock. Take the net_device for correctness
+ * sake.
+ */
+ if (uplink_upper)
+ dev_hold(uplink_upper);
+ rcu_read_unlock();
+
dst_is_lag_dev = (uplink_upper &&
netif_is_lag_master(uplink_upper) &&
real_dev == uplink_upper &&
mlx5_lag_is_sriov(priv->mdev));
+ if (uplink_upper)
+ dev_put(uplink_upper);
/* if the egress device isn't on the same HW e-switch or
* it's a LAG device, use the uplink
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 714aa9d7180b..595a4c5667ea 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -2978,12 +2978,16 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
if (netdev_port_same_parent_id(priv->netdev, out_dev)) {
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct net_device *uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
- struct net_device *uplink_upper = netdev_master_upper_dev_get(uplink_dev);
+ struct net_device *uplink_upper;
+ rcu_read_lock();
+ uplink_upper =
+ netdev_master_upper_dev_get_rcu(uplink_dev);
if (uplink_upper &&
netif_is_lag_master(uplink_upper) &&
uplink_upper == out_dev)
out_dev = uplink_dev;
+ rcu_read_unlock();
if (is_vlan_dev(out_dev)) {
err = add_vlan_push_action(priv, attr,
--
2.21.0
^ permalink raw reply related
* [net-next 10/13] net/mlx5e: Eswitch, change offloads num_flows type to atomic64
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
Eswitch implements its own locking by means of state_lock mutex and
multiple fine-grained lock in containing data structures, and is supposed
to not rely on rtnl lock. However, eswitch offloads num_flows type is a
regular long long integer and cannot be modified concurrently. This is an
implicit assumptions that mlx5 tc is serialized (by rtnl lock or any other
means). In order to remove implicit dependency on rtnl lock, change
num_flows type to atomic64 to allow concurrent modifications.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 1 +
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 3 ++-
.../net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 10 +++++-----
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 1f3891fde2eb..d365551d2f10 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1933,6 +1933,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
hash_init(esw->offloads.encap_tbl);
hash_init(esw->offloads.mod_hdr_tbl);
+ atomic64_set(&esw->offloads.num_flows, 0);
mutex_init(&esw->state_lock);
mlx5_esw_for_all_vports(esw, i, vport) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index a38e8a3c7c9a..60f0c62b447b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -35,6 +35,7 @@
#include <linux/if_ether.h>
#include <linux/if_link.h>
+#include <linux/atomic.h>
#include <net/devlink.h>
#include <linux/mlx5/device.h>
#include <linux/mlx5/eswitch.h>
@@ -179,7 +180,7 @@ struct mlx5_esw_offload {
struct mutex termtbl_mutex; /* protects termtbl hash */
const struct mlx5_eswitch_rep_ops *rep_ops[NUM_REP_TYPES];
u8 inline_mode;
- u64 num_flows;
+ atomic64_t num_flows;
enum devlink_eswitch_encap_mode encap;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 089ae4d48a82..244ad1893691 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -233,7 +233,7 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
if (IS_ERR(rule))
goto err_add_rule;
else
- esw->offloads.num_flows++;
+ atomic64_inc(&esw->offloads.num_flows);
return rule;
@@ -298,7 +298,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
if (IS_ERR(rule))
goto add_err;
- esw->offloads.num_flows++;
+ atomic64_inc(&esw->offloads.num_flows);
return rule;
add_err:
@@ -326,7 +326,7 @@ __mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
mlx5_eswitch_termtbl_put(esw, attr->dests[i].termtbl);
}
- esw->offloads.num_flows--;
+ atomic64_dec(&esw->offloads.num_flows);
if (fwd_rule) {
esw_put_prio_table(esw, attr->chain, attr->prio, 1);
@@ -2349,7 +2349,7 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
break;
}
- if (esw->offloads.num_flows > 0) {
+ if (atomic64_read(&esw->offloads.num_flows) > 0) {
NL_SET_ERR_MSG_MOD(extack,
"Can't set inline mode when flows are configured");
return -EOPNOTSUPP;
@@ -2459,7 +2459,7 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
if (esw->offloads.encap == encap)
return 0;
- if (esw->offloads.num_flows > 0) {
+ if (atomic64_read(&esw->offloads.num_flows) > 0) {
NL_SET_ERR_MSG_MOD(extack,
"Can't set encapsulation when flows are configured");
return -EOPNOTSUPP;
--
2.21.0
^ permalink raw reply related
* [net-next 09/13] net/mlx5e: Protect unready flows with dedicated lock
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
In order to remove dependency on rtnl lock for protecting unready_flows
list when reoffloading unready flows on workqueue, extend representor
uplink private structure with dedicated 'unready_flows_lock' mutex. Take
the lock in all users of unready_flows list before accessing it. Implement
helper functions to add and delete unready flow.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/en_rep.c | 2 +
.../net/ethernet/mellanox/mlx5/core/en_rep.h | 2 +
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 43 ++++++++++++++++---
3 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 69f7ac8fc9be..6edf0aeb1e26 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -1560,6 +1560,7 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
if (rpriv->rep->vport == MLX5_VPORT_UPLINK) {
uplink_priv = &rpriv->uplink_priv;
+ mutex_init(&uplink_priv->unready_flows_lock);
INIT_LIST_HEAD(&uplink_priv->unready_flows);
/* init shared tc flow table */
@@ -1604,6 +1605,7 @@ static void mlx5e_cleanup_rep_tx(struct mlx5e_priv *priv)
/* delete shared tc flow table */
mlx5e_tc_esw_cleanup(&rpriv->uplink_priv.tc_ht);
+ mutex_destroy(&rpriv->uplink_priv.unready_flows_lock);
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
index c56e6ee4350c..10fafd5fa17b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
@@ -75,6 +75,8 @@ struct mlx5_rep_uplink_priv {
struct mlx5_tun_entropy tun_entropy;
+ /* protects unready_flows */
+ struct mutex unready_flows_lock;
struct list_head unready_flows;
struct work_struct reoffload_flows_work;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index a39f8a07de0a..714aa9d7180b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -996,6 +996,25 @@ mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw,
flow_flag_clear(flow, SLOW);
}
+/* Caller must obtain uplink_priv->unready_flows_lock mutex before calling this
+ * function.
+ */
+static void unready_flow_add(struct mlx5e_tc_flow *flow,
+ struct list_head *unready_flows)
+{
+ flow_flag_set(flow, NOT_READY);
+ list_add_tail(&flow->unready, unready_flows);
+}
+
+/* Caller must obtain uplink_priv->unready_flows_lock mutex before calling this
+ * function.
+ */
+static void unready_flow_del(struct mlx5e_tc_flow *flow)
+{
+ list_del(&flow->unready);
+ flow_flag_clear(flow, NOT_READY);
+}
+
static void add_unready_flow(struct mlx5e_tc_flow *flow)
{
struct mlx5_rep_uplink_priv *uplink_priv;
@@ -1006,14 +1025,24 @@ static void add_unready_flow(struct mlx5e_tc_flow *flow)
rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
uplink_priv = &rpriv->uplink_priv;
- flow_flag_set(flow, NOT_READY);
- list_add_tail(&flow->unready, &uplink_priv->unready_flows);
+ mutex_lock(&uplink_priv->unready_flows_lock);
+ unready_flow_add(flow, &uplink_priv->unready_flows);
+ mutex_unlock(&uplink_priv->unready_flows_lock);
}
static void remove_unready_flow(struct mlx5e_tc_flow *flow)
{
- list_del(&flow->unready);
- flow_flag_clear(flow, NOT_READY);
+ struct mlx5_rep_uplink_priv *uplink_priv;
+ struct mlx5e_rep_priv *rpriv;
+ struct mlx5_eswitch *esw;
+
+ esw = flow->priv->mdev->priv.eswitch;
+ rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
+ uplink_priv = &rpriv->uplink_priv;
+
+ mutex_lock(&uplink_priv->unready_flows_lock);
+ unready_flow_del(flow);
+ mutex_unlock(&uplink_priv->unready_flows_lock);
}
static int
@@ -3723,10 +3752,10 @@ void mlx5e_tc_reoffload_flows_work(struct work_struct *work)
reoffload_flows_work);
struct mlx5e_tc_flow *flow, *tmp;
- rtnl_lock();
+ mutex_lock(&rpriv->unready_flows_lock);
list_for_each_entry_safe(flow, tmp, &rpriv->unready_flows, unready) {
if (!mlx5e_tc_add_fdb_flow(flow->priv, flow, NULL))
- remove_unready_flow(flow);
+ unready_flow_del(flow);
}
- rtnl_unlock();
+ mutex_unlock(&rpriv->unready_flows_lock);
}
--
2.21.0
^ permalink raw reply related
* [net-next 04/13] net/mlx5e: Fix unnecessary flow_block_cb_is_busy call
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev@vger.kernel.org, wenxu, Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: wenxu <wenxu@ucloud.cn>
When call flow_block_cb_is_busy. The indr_priv is guaranteed to
NULL ptr. So there is no need to call flow_bock_cb_is_busy.
Fixes: 0d4fd02e7199 ("net: flow_offload: add flow_block_cb_is_busy() and use it")
Signed-off-by: wenxu <wenxu@ucloud.cn>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 7f747cb1a4f4..496d3034e278 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -722,10 +722,6 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
if (indr_priv)
return -EEXIST;
- if (flow_block_cb_is_busy(mlx5e_rep_indr_setup_block_cb,
- indr_priv, &mlx5e_block_cb_list))
- return -EBUSY;
-
indr_priv = kmalloc(sizeof(*indr_priv), GFP_KERNEL);
if (!indr_priv)
return -ENOMEM;
--
2.21.0
^ permalink raw reply related
* [net-next 08/13] net/mlx5e: Protect tc flows hashtable with rcu
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
In order to remove dependency on rtnl lock, access to tc flows hashtable
must be explicitly protected from concurrent flows removal.
Extend tc flow structure with rcu to allow concurrent parallel access. Use
rcu read lock to safely lookup flow in tc flows hash table, and take
reference to it. Use rcu free for flow deletion to accommodate concurrent
stats requests.
Add new DELETED flow flag. Imlement new flow_flag_test_and_set() helper
that is used to set a flag and return its previous value. Use it to
atomically set the flag in mlx5e_delete_flower() to guarantee that flow can
only be deleted once, even when same flow is deleted concurrently by
multiple tasks.
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 47 ++++++++++++++++---
1 file changed, 40 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 241157b699df..a39f8a07de0a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -79,6 +79,7 @@ enum {
MLX5E_TC_FLOW_FLAG_SLOW = MLX5E_TC_FLOW_BASE + 3,
MLX5E_TC_FLOW_FLAG_DUP = MLX5E_TC_FLOW_BASE + 4,
MLX5E_TC_FLOW_FLAG_NOT_READY = MLX5E_TC_FLOW_BASE + 5,
+ MLX5E_TC_FLOW_FLAG_DELETED = MLX5E_TC_FLOW_BASE + 6,
};
#define MLX5E_TC_MAX_SPLITS 1
@@ -122,6 +123,7 @@ struct mlx5e_tc_flow {
struct list_head peer; /* flows with peer flow */
struct list_head unready; /* flows not ready to be offloaded (e.g due to missing route) */
refcount_t refcnt;
+ struct rcu_head rcu_head;
union {
struct mlx5_esw_flow_attr esw_attr[0];
struct mlx5_nic_flow_attr nic_attr[0];
@@ -201,7 +203,7 @@ static void mlx5e_flow_put(struct mlx5e_priv *priv,
{
if (refcount_dec_and_test(&flow->refcnt)) {
mlx5e_tc_del_flow(priv, flow);
- kfree(flow);
+ kfree_rcu(flow, rcu_head);
}
}
@@ -214,6 +216,17 @@ static void __flow_flag_set(struct mlx5e_tc_flow *flow, unsigned long flag)
#define flow_flag_set(flow, flag) __flow_flag_set(flow, MLX5E_TC_FLOW_FLAG_##flag)
+static bool __flow_flag_test_and_set(struct mlx5e_tc_flow *flow,
+ unsigned long flag)
+{
+ /* test_and_set_bit() provides all necessary barriers */
+ return test_and_set_bit(flag, &flow->flags);
+}
+
+#define flow_flag_test_and_set(flow, flag) \
+ __flow_flag_test_and_set(flow, \
+ MLX5E_TC_FLOW_FLAG_##flag)
+
static void __flow_flag_clear(struct mlx5e_tc_flow *flow, unsigned long flag)
{
/* Complete all memory stores before clearing bit. */
@@ -3451,7 +3464,9 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow;
int err = 0;
- flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params);
+ rcu_read_lock();
+ flow = rhashtable_lookup(tc_ht, &f->cookie, tc_ht_params);
+ rcu_read_unlock();
if (flow) {
NL_SET_ERR_MSG_MOD(extack,
"flow cookie already exists, ignoring");
@@ -3466,7 +3481,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
if (err)
goto out;
- err = rhashtable_insert_fast(tc_ht, &flow->node, tc_ht_params);
+ err = rhashtable_lookup_insert_fast(tc_ht, &flow->node, tc_ht_params);
if (err)
goto err_free;
@@ -3492,16 +3507,32 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
{
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
struct mlx5e_tc_flow *flow;
+ int err;
+ rcu_read_lock();
flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params);
- if (!flow || !same_flow_direction(flow, flags))
- return -EINVAL;
+ if (!flow || !same_flow_direction(flow, flags)) {
+ err = -EINVAL;
+ goto errout;
+ }
+ /* Only delete the flow if it doesn't have MLX5E_TC_FLOW_DELETED flag
+ * set.
+ */
+ if (flow_flag_test_and_set(flow, DELETED)) {
+ err = -EINVAL;
+ goto errout;
+ }
rhashtable_remove_fast(tc_ht, &flow->node, tc_ht_params);
+ rcu_read_unlock();
mlx5e_flow_put(priv, flow);
return 0;
+
+errout:
+ rcu_read_unlock();
+ return err;
}
int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
@@ -3517,8 +3548,10 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
u64 bytes = 0;
int err = 0;
- flow = mlx5e_flow_get(rhashtable_lookup_fast(tc_ht, &f->cookie,
- tc_ht_params));
+ rcu_read_lock();
+ flow = mlx5e_flow_get(rhashtable_lookup(tc_ht, &f->cookie,
+ tc_ht_params));
+ rcu_read_unlock();
if (IS_ERR(flow))
return PTR_ERR(flow);
--
2.21.0
^ permalink raw reply related
* [net-next 06/13] net/mlx5e: Extend tc flow struct with reference counter
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Vlad Buslov, Jianbo Liu, Roi Dayan,
Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Vlad Buslov <vladbu@mellanox.com>
With new classifier type that doesn't require rtnl lock, following
invariant holds:
- Filter with specified cookie created only once.
- Filter with specified cookie deleted only once.
- Stats updates can be performed in parallel to each other.
Extend tc flow with rcu and reference counter. To protect from concurrent
delete, get reference to tc flow when:
- Reading flow stats.
- Accessing flow in neigh update handler.
- Accessing flow in neigh update used value handler.
Only free flow when reference counter reached zero. Modify flow cleanup to
account for flows that could be not fully initialized by checking if flow
is actually in the list of corresponding mod_hdr, hairpin and encap
entries. Don't cleanup flow directly in case of error to allow concurrent
neigh update (neigh update will be modified to always take reference to
flow when using it).
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 193 ++++++++++--------
1 file changed, 105 insertions(+), 88 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index cc096f6011d9..e2b87f723819 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -38,6 +38,7 @@
#include <linux/mlx5/fs.h>
#include <linux/mlx5/device.h>
#include <linux/rhashtable.h>
+#include <linux/refcount.h>
#include <net/tc_act/tc_mirred.h>
#include <net/tc_act/tc_vlan.h>
#include <net/tc_act/tc_tunnel_key.h>
@@ -120,6 +121,7 @@ struct mlx5e_tc_flow {
struct list_head hairpin; /* flows sharing the same hairpin */
struct list_head peer; /* flows with peer flow */
struct list_head unready; /* flows not ready to be offloaded (e.g due to missing route) */
+ refcount_t refcnt;
union {
struct mlx5_esw_flow_attr esw_attr[0];
struct mlx5_nic_flow_attr nic_attr[0];
@@ -184,6 +186,25 @@ struct mlx5e_mod_hdr_entry {
#define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)
+static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
+ struct mlx5e_tc_flow *flow);
+
+static struct mlx5e_tc_flow *mlx5e_flow_get(struct mlx5e_tc_flow *flow)
+{
+ if (!flow || !refcount_inc_not_zero(&flow->refcnt))
+ return ERR_PTR(-EINVAL);
+ return flow;
+}
+
+static void mlx5e_flow_put(struct mlx5e_priv *priv,
+ struct mlx5e_tc_flow *flow)
+{
+ if (refcount_dec_and_test(&flow->refcnt)) {
+ mlx5e_tc_del_flow(priv, flow);
+ kfree(flow);
+ }
+}
+
static inline u32 hash_mod_hdr_info(struct mod_hdr_key *key)
{
return jhash(key->actions,
@@ -281,6 +302,10 @@ static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv,
{
struct list_head *next = flow->mod_hdr.next;
+ /* flow wasn't fully initialized */
+ if (list_empty(&flow->mod_hdr))
+ return;
+
list_del(&flow->mod_hdr);
if (list_empty(next)) {
@@ -694,6 +719,10 @@ static void mlx5e_hairpin_flow_del(struct mlx5e_priv *priv,
{
struct list_head *next = flow->hairpin.next;
+ /* flow wasn't fully initialized */
+ if (list_empty(&flow->hairpin))
+ return;
+
list_del(&flow->hairpin);
/* no more hairpin flows for us, release the hairpin pair */
@@ -727,7 +756,6 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
.flags = FLOW_ACT_NO_APPEND,
};
struct mlx5_fc *counter = NULL;
- bool table_created = false;
int err, dest_ix = 0;
flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
@@ -735,9 +763,9 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) {
err = mlx5e_hairpin_flow_add(priv, flow, parse_attr, extack);
- if (err) {
- goto err_add_hairpin_flow;
- }
+ if (err)
+ return err;
+
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN_RSS) {
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[dest_ix].ft = attr->hairpin_ft;
@@ -754,10 +782,9 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
counter = mlx5_fc_create(dev, true);
- if (IS_ERR(counter)) {
- err = PTR_ERR(counter);
- goto err_fc_create;
- }
+ if (IS_ERR(counter))
+ return PTR_ERR(counter);
+
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
dest[dest_ix].counter_id = mlx5_fc_id(counter);
dest_ix++;
@@ -769,7 +796,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
flow_act.modify_id = attr->mod_hdr_id;
kfree(parse_attr->mod_hdr_actions);
if (err)
- goto err_create_mod_hdr_id;
+ return err;
}
if (IS_ERR_OR_NULL(priv->fs.tc.t)) {
@@ -795,11 +822,8 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
"Failed to create tc offload table\n");
netdev_err(priv->netdev,
"Failed to create tc offload table\n");
- err = PTR_ERR(priv->fs.tc.t);
- goto err_create_ft;
+ return PTR_ERR(priv->fs.tc.t);
}
-
- table_created = true;
}
if (attr->match_level != MLX5_MATCH_NONE)
@@ -808,28 +832,10 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
flow->rule[0] = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
&flow_act, dest, dest_ix);
- if (IS_ERR(flow->rule[0])) {
- err = PTR_ERR(flow->rule[0]);
- goto err_add_rule;
- }
+ if (IS_ERR(flow->rule[0]))
+ return PTR_ERR(flow->rule[0]);
return 0;
-
-err_add_rule:
- if (table_created) {
- mlx5_destroy_flow_table(priv->fs.tc.t);
- priv->fs.tc.t = NULL;
- }
-err_create_ft:
- if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
- mlx5e_detach_mod_hdr(priv, flow);
-err_create_mod_hdr_id:
- mlx5_fc_destroy(dev, counter);
-err_fc_create:
- if (flow->flags & MLX5E_TC_FLOW_HAIRPIN)
- mlx5e_hairpin_flow_del(priv, flow);
-err_add_hairpin_flow:
- return err;
}
static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
@@ -839,7 +845,8 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
struct mlx5_fc *counter = NULL;
counter = attr->counter;
- mlx5_del_flow_rules(flow->rule[0]);
+ if (!IS_ERR_OR_NULL(flow->rule[0]))
+ mlx5_del_flow_rules(flow->rule[0]);
mlx5_fc_destroy(priv->mdev, counter);
if (!mlx5e_tc_num_filters(priv, MLX5E_TC_NIC_OFFLOAD) && priv->fs.tc.t) {
@@ -980,14 +987,12 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
if (attr->chain > max_chain) {
NL_SET_ERR_MSG(extack, "Requested chain is out of supported range");
- err = -EOPNOTSUPP;
- goto err_max_prio_chain;
+ return -EOPNOTSUPP;
}
if (attr->prio > max_prio) {
NL_SET_ERR_MSG(extack, "Requested priority is out of supported range");
- err = -EOPNOTSUPP;
- goto err_max_prio_chain;
+ return -EOPNOTSUPP;
}
for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
@@ -1002,7 +1007,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
err = mlx5e_attach_encap(priv, flow, out_dev, out_index,
extack, &encap_dev, &encap_valid);
if (err)
- goto err_attach_encap;
+ return err;
out_priv = netdev_priv(encap_dev);
rpriv = out_priv->ppriv;
@@ -1012,21 +1017,19 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
err = mlx5_eswitch_add_vlan_action(esw, attr);
if (err)
- goto err_add_vlan;
+ return err;
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
err = mlx5e_attach_mod_hdr(priv, flow, parse_attr);
kfree(parse_attr->mod_hdr_actions);
if (err)
- goto err_mod_hdr;
+ return err;
}
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
counter = mlx5_fc_create(attr->counter_dev, true);
- if (IS_ERR(counter)) {
- err = PTR_ERR(counter);
- goto err_create_counter;
- }
+ if (IS_ERR(counter))
+ return PTR_ERR(counter);
attr->counter = counter;
}
@@ -1044,27 +1047,10 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
flow->rule[0] = mlx5e_tc_offload_fdb_rules(esw, flow, &parse_attr->spec, attr);
}
- if (IS_ERR(flow->rule[0])) {
- err = PTR_ERR(flow->rule[0]);
- goto err_add_rule;
- }
+ if (IS_ERR(flow->rule[0]))
+ return PTR_ERR(flow->rule[0]);
return 0;
-
-err_add_rule:
- mlx5_fc_destroy(attr->counter_dev, counter);
-err_create_counter:
- if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
- mlx5e_detach_mod_hdr(priv, flow);
-err_mod_hdr:
- mlx5_eswitch_del_vlan_action(esw, attr);
-err_add_vlan:
- for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++)
- if (attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)
- mlx5e_detach_encap(priv, flow, out_index);
-err_attach_encap:
-err_max_prio_chain:
- return err;
}
static bool mlx5_flow_has_geneve_opt(struct mlx5e_tc_flow *flow)
@@ -1123,9 +1109,9 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr slow_attr, *esw_attr;
+ struct encap_flow_item *efi, *tmp;
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
- struct encap_flow_item *efi;
struct mlx5e_tc_flow *flow;
int err;
@@ -1142,11 +1128,14 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
e->flags |= MLX5_ENCAP_ENTRY_VALID;
mlx5e_rep_queue_neigh_stats_work(priv);
- list_for_each_entry(efi, &e->flows, list) {
+ list_for_each_entry_safe(efi, tmp, &e->flows, list) {
bool all_flow_encaps_valid = true;
int i;
flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
+ if (IS_ERR(mlx5e_flow_get(flow)))
+ continue;
+
esw_attr = flow->esw_attr;
spec = &esw_attr->parse_attr->spec;
@@ -1166,19 +1155,22 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
}
/* Do not offload flows with unresolved neighbors */
if (!all_flow_encaps_valid)
- continue;
+ goto loop_cont;
/* update from slow path rule to encap rule */
rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
err);
- continue;
+ goto loop_cont;
}
mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr);
flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when slow path rule removed */
flow->rule[0] = rule;
+
+loop_cont:
+ mlx5e_flow_put(priv, flow);
}
}
@@ -1187,14 +1179,17 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr slow_attr;
+ struct encap_flow_item *efi, *tmp;
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
- struct encap_flow_item *efi;
struct mlx5e_tc_flow *flow;
int err;
- list_for_each_entry(efi, &e->flows, list) {
+ list_for_each_entry_safe(efi, tmp, &e->flows, list) {
flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
+ if (IS_ERR(mlx5e_flow_get(flow)))
+ continue;
+
spec = &flow->esw_attr->parse_attr->spec;
/* update from encap rule to slow path rule */
@@ -1206,12 +1201,15 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
err = PTR_ERR(rule);
mlx5_core_warn(priv->mdev, "Failed to update slow path (encap) flow, %d\n",
err);
- continue;
+ goto loop_cont;
}
mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr);
flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when fast path rule removed */
flow->rule[0] = rule;
+
+loop_cont:
+ mlx5e_flow_put(priv, flow);
}
/* we know that the encap is valid */
@@ -1248,20 +1246,26 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
return;
list_for_each_entry(e, &nhe->encap_list, encap_list) {
- struct encap_flow_item *efi;
+ struct encap_flow_item *efi, *tmp;
if (!(e->flags & MLX5_ENCAP_ENTRY_VALID))
continue;
- list_for_each_entry(efi, &e->flows, list) {
+ list_for_each_entry_safe(efi, tmp, &e->flows, list) {
flow = container_of(efi, struct mlx5e_tc_flow,
encaps[efi->index]);
+ if (IS_ERR(mlx5e_flow_get(flow)))
+ continue;
+
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
counter = mlx5e_tc_get_counter(flow);
mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
+ mlx5e_flow_put(netdev_priv(e->out_dev), flow);
neigh_used = true;
break;
}
}
+
+ mlx5e_flow_put(netdev_priv(e->out_dev), flow);
}
if (neigh_used)
break;
@@ -1287,6 +1291,10 @@ static void mlx5e_detach_encap(struct mlx5e_priv *priv,
{
struct list_head *next = flow->encaps[out_index].list.next;
+ /* flow wasn't fully initialized */
+ if (list_empty(&flow->encaps[out_index].list))
+ return;
+
list_del(&flow->encaps[out_index].list);
if (list_empty(next)) {
struct mlx5e_encap_entry *e;
@@ -3122,7 +3130,7 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
{
struct mlx5e_tc_flow_parse_attr *parse_attr;
struct mlx5e_tc_flow *flow;
- int err;
+ int out_index, err;
flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL);
parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL);
@@ -3134,6 +3142,11 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
flow->cookie = f->cookie;
flow->flags = flow_flags;
flow->priv = priv;
+ for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++)
+ INIT_LIST_HEAD(&flow->encaps[out_index].list);
+ INIT_LIST_HEAD(&flow->mod_hdr);
+ INIT_LIST_HEAD(&flow->hairpin);
+ refcount_set(&flow->refcnt, 1);
*__flow = flow;
*__parse_attr = parse_attr;
@@ -3216,8 +3229,7 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
return flow;
err_free:
- kfree(flow);
- kvfree(parse_attr);
+ mlx5e_flow_put(priv, flow);
out:
return ERR_PTR(err);
}
@@ -3351,7 +3363,7 @@ mlx5e_add_nic_flow(struct mlx5e_priv *priv,
return 0;
err_free:
- kfree(flow);
+ mlx5e_flow_put(priv, flow);
kvfree(parse_attr);
out:
return err;
@@ -3413,8 +3425,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
return 0;
err_free:
- mlx5e_tc_del_flow(priv, flow);
- kfree(flow);
+ mlx5e_flow_put(priv, flow);
out:
return err;
}
@@ -3442,9 +3453,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
rhashtable_remove_fast(tc_ht, &flow->node, tc_ht_params);
- mlx5e_tc_del_flow(priv, flow);
-
- kfree(flow);
+ mlx5e_flow_put(priv, flow);
return 0;
}
@@ -3460,15 +3469,22 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
u64 lastuse = 0;
u64 packets = 0;
u64 bytes = 0;
+ int err = 0;
- flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params);
- if (!flow || !same_flow_direction(flow, flags))
- return -EINVAL;
+ flow = mlx5e_flow_get(rhashtable_lookup_fast(tc_ht, &f->cookie,
+ tc_ht_params));
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+
+ if (!same_flow_direction(flow, flags)) {
+ err = -EINVAL;
+ goto errout;
+ }
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
counter = mlx5e_tc_get_counter(flow);
if (!counter)
- return 0;
+ goto errout;
mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
}
@@ -3500,8 +3516,9 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
out:
flow_stats_update(&f->stats, bytes, packets, lastuse);
-
- return 0;
+errout:
+ mlx5e_flow_put(priv, flow);
+ return err;
}
static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv,
--
2.21.0
^ permalink raw reply related
* [net-next 05/13] net/mlx5e: Simplify get_route_and_out_devs helper function
From: Saeed Mahameed @ 2019-07-29 23:50 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Eli Britstein, Roi Dayan, Saeed Mahameed
In-Reply-To: <20190729234934.23595-1-saeedm@mellanox.com>
From: Eli Britstein <elibr@mellanox.com>
The helper function has "if" branches that do the same. Merge them to
simplify the code.
Signed-off-by: Eli Britstein <elibr@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../ethernet/mellanox/mlx5/core/en/tc_tun.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
index a6a52806be45..ae439d95f5a3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
@@ -40,20 +40,15 @@ static int get_route_and_out_devs(struct mlx5e_priv *priv,
/* if the egress device isn't on the same HW e-switch or
* it's a LAG device, use the uplink
*/
+ *route_dev = dev;
if (!netdev_port_same_parent_id(priv->netdev, real_dev) ||
- dst_is_lag_dev) {
- *route_dev = dev;
+ dst_is_lag_dev || is_vlan_dev(*route_dev))
*out_dev = uplink_dev;
- } else {
- *route_dev = dev;
- if (is_vlan_dev(*route_dev))
- *out_dev = uplink_dev;
- else if (mlx5e_eswitch_rep(dev) &&
- mlx5e_is_valid_eswitch_fwd_dev(priv, dev))
- *out_dev = *route_dev;
- else
- return -EOPNOTSUPP;
- }
+ else if (mlx5e_eswitch_rep(dev) &&
+ mlx5e_is_valid_eswitch_fwd_dev(priv, dev))
+ *out_dev = *route_dev;
+ else
+ return -EOPNOTSUPP;
if (!(mlx5e_eswitch_rep(*out_dev) &&
mlx5e_is_uplink_rep(netdev_priv(*out_dev))))
--
2.21.0
^ 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