* [PATCH 2/6] [v4] phylib: introduce PHY_INTERFACE_MODE_XGMII for 10G PHY
From: shh.xie @ 2014-01-07 2:13 UTC (permalink / raw)
To: davem, jg1.han, mugunthanvnm, f.fainelli, netdev, linux-kernel
Cc: Shaohui.Xie, Andy Fleming
From: Andy Fleming <afleming@gmail.com>
Signed-off-by: Andy Fleming <afleming@gmail.com>
Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
resend for v4.
drivers/of/of_net.c | 1 +
include/linux/phy.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
index 8f9be2e..a208a45 100644
--- a/drivers/of/of_net.c
+++ b/drivers/of/of_net.c
@@ -30,6 +30,7 @@ static const char *phy_modes[] = {
[PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
[PHY_INTERFACE_MODE_RTBI] = "rtbi",
[PHY_INTERFACE_MODE_SMII] = "smii",
+ [PHY_INTERFACE_MODE_XGMII] = "xgmii",
};
/**
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 0ff2476..1d6d1b9 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -66,6 +66,7 @@ typedef enum {
PHY_INTERFACE_MODE_RGMII_TXID,
PHY_INTERFACE_MODE_RTBI,
PHY_INTERFACE_MODE_SMII,
+ PHY_INTERFACE_MODE_XGMII,
} phy_interface_t;
--
1.8.4.1
^ permalink raw reply related
* [PATCH 3/6] [v4] phylib: turn genphy_driver to an array
From: shh.xie @ 2014-01-07 2:13 UTC (permalink / raw)
To: davem, jg1.han, mugunthanvnm, f.fainelli, netdev, linux-kernel
Cc: Shaohui.Xie
From: Shaohui Xie <Shaohui.Xie@freescale.com>
Then other generic phy driver such as generic 10g phy driver can join it.
Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
---
resend for v4.
drivers/net/phy/phy_device.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index d6447b3..748bf07 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -53,7 +53,12 @@ static void phy_device_release(struct device *dev)
kfree(to_phy_device(dev));
}
-static struct phy_driver genphy_driver;
+enum genphy_driver {
+ GENPHY_DRV_1G,
+ GENPHY_DRV_MAX
+};
+
+static struct phy_driver genphy_driver[GENPHY_DRV_MAX];
extern int mdio_bus_init(void);
extern void mdio_bus_exit(void);
@@ -539,7 +544,7 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
return -ENODEV;
}
- d->driver = &genphy_driver.driver;
+ d->driver = &genphy_driver[GENPHY_DRV_1G].driver;
err = d->driver->probe(d);
if (err >= 0)
@@ -613,6 +618,7 @@ EXPORT_SYMBOL(phy_attach);
*/
void phy_detach(struct phy_device *phydev)
{
+ int i;
phydev->attached_dev->phydev = NULL;
phydev->attached_dev = NULL;
@@ -620,8 +626,12 @@ void phy_detach(struct phy_device *phydev)
* was using the generic driver), we unbind the device
* from the generic driver so that there's a chance a
* real driver could be loaded */
- if (phydev->dev.driver == &genphy_driver.driver)
- device_release_driver(&phydev->dev);
+ for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) {
+ if (phydev->dev.driver == &genphy_driver[i].driver) {
+ device_release_driver(&phydev->dev);
+ break;
+ }
+ }
}
EXPORT_SYMBOL(phy_detach);
@@ -1116,7 +1126,8 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
}
EXPORT_SYMBOL(phy_drivers_unregister);
-static struct phy_driver genphy_driver = {
+static struct phy_driver genphy_driver[] = {
+{
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic PHY",
@@ -1127,7 +1138,7 @@ static struct phy_driver genphy_driver = {
.suspend = genphy_suspend,
.resume = genphy_resume,
.driver = {.owner= THIS_MODULE, },
-};
+} };
static int __init phy_init(void)
{
@@ -1137,7 +1148,8 @@ static int __init phy_init(void)
if (rc)
return rc;
- rc = phy_driver_register(&genphy_driver);
+ rc = phy_drivers_register(genphy_driver,
+ ARRAY_SIZE(genphy_driver));
if (rc)
mdio_bus_exit();
@@ -1146,7 +1158,8 @@ static int __init phy_init(void)
static void __exit phy_exit(void)
{
- phy_driver_unregister(&genphy_driver);
+ phy_drivers_unregister(genphy_driver,
+ ARRAY_SIZE(genphy_driver));
mdio_bus_exit();
}
--
1.8.4.1
^ permalink raw reply related
* [PATCH 4/6] [v4] phylib: Add generic 10G driver
From: shh.xie @ 2014-01-07 2:14 UTC (permalink / raw)
To: davem, jg1.han, mugunthanvnm, f.fainelli, netdev, linux-kernel
Cc: Shaohui.Xie, Andy Fleming
From: Andy Fleming <afleming@gmail.com>
Very incomplete, but will allow for binding an ethernet controller
to it.
Signed-off-by: Andy Fleming <afleming@gmail.com>
Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
---
resend for v4.
drivers/net/phy/phy_device.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 748bf07..439b0d4 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -33,6 +33,7 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
+#include <linux/mdio.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -55,6 +56,7 @@ static void phy_device_release(struct device *dev)
enum genphy_driver {
GENPHY_DRV_1G,
+ GENPHY_DRV_10G,
GENPHY_DRV_MAX
};
@@ -699,6 +701,12 @@ static int genphy_config_advert(struct phy_device *phydev)
return changed;
}
+int gen10g_config_advert(struct phy_device *dev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(gen10g_config_advert);
+
/**
* genphy_setup_forced - configures/forces speed/duplex from @phydev
* @phydev: target phy_device struct
@@ -752,6 +760,11 @@ int genphy_restart_aneg(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_restart_aneg);
+int gen10g_restart_aneg(struct phy_device *phydev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(gen10g_restart_aneg);
/**
* genphy_config_aneg - restart auto-negotiation or write BMCR
@@ -794,6 +807,12 @@ int genphy_config_aneg(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_config_aneg);
+int gen10g_config_aneg(struct phy_device *phydev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(gen10g_config_aneg);
+
/**
* genphy_update_link - update link status in @phydev
* @phydev: target phy_device struct
@@ -923,6 +942,34 @@ int genphy_read_status(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_read_status);
+int gen10g_read_status(struct phy_device *phydev)
+{
+ int devad, reg;
+ u32 mmd_mask = phydev->c45_ids.devices_in_package;
+
+ phydev->link = 1;
+
+ /* For now just lie and say it's 10G all the time */
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+
+ for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) {
+ if (!(mmd_mask & 1))
+ continue;
+
+ /* Read twice because link state is latched and a
+ * read moves the current state into the register
+ */
+ phy_read_mmd(phydev, devad, MDIO_STAT1);
+ reg = phy_read_mmd(phydev, devad, MDIO_STAT1);
+ if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
+ phydev->link = 0;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(gen10g_read_status);
+
static int genphy_config_init(struct phy_device *phydev)
{
int val;
@@ -969,6 +1016,16 @@ static int genphy_config_init(struct phy_device *phydev)
return 0;
}
+
+static int gen10g_config_init(struct phy_device *phydev)
+{
+ /* Temporarily just say we support everything */
+ phydev->supported = SUPPORTED_10000baseT_Full;
+ phydev->advertising = SUPPORTED_10000baseT_Full;
+
+ return 0;
+}
+
int genphy_suspend(struct phy_device *phydev)
{
int value;
@@ -984,6 +1041,12 @@ int genphy_suspend(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_suspend);
+int gen10g_suspend(struct phy_device *phydev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(gen10g_suspend);
+
int genphy_resume(struct phy_device *phydev)
{
int value;
@@ -999,6 +1062,12 @@ int genphy_resume(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_resume);
+int gen10g_resume(struct phy_device *phydev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(gen10g_resume);
+
/**
* phy_probe - probe and init a PHY device
* @dev: device to probe and init
@@ -1138,6 +1207,17 @@ static struct phy_driver genphy_driver[] = {
.suspend = genphy_suspend,
.resume = genphy_resume,
.driver = {.owner= THIS_MODULE, },
+}, {
+ .phy_id = 0xffffffff,
+ .phy_id_mask = 0xffffffff,
+ .name = "Generic 10G PHY",
+ .config_init = gen10g_config_init,
+ .features = 0,
+ .config_aneg = gen10g_config_aneg,
+ .read_status = gen10g_read_status,
+ .suspend = gen10g_suspend,
+ .resume = gen10g_resume,
+ .driver = {.owner = THIS_MODULE, },
} };
static int __init phy_init(void)
--
1.8.4.1
^ permalink raw reply related
* [PATCH 5/6] [v4] phylib: Support attaching to generic 10g driver
From: shh.xie @ 2014-01-07 2:14 UTC (permalink / raw)
To: davem, jg1.han, mugunthanvnm, f.fainelli, netdev, linux-kernel
Cc: Shaohui.Xie, Andy Fleming
From: Andy Fleming <afleming@gmail.com>
phy_attach_direct() may now attach to a generic 10G driver. It can
also be used exactly as phy_connect_direct(), which will be useful
when using of_mdio, as phy_connect (and therefore of_phy_connect)
start the PHY state machine, which is currently irrelevant for 10G
PHYs.
Signed-off-by: Andy Fleming <afleming@gmail.com>
Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
resend for v4.
drivers/net/phy/phy_device.c | 20 ++++++++------------
include/linux/phy.h | 2 ++
2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 439b0d4..6eab488 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -67,9 +67,6 @@ extern void mdio_bus_exit(void);
static LIST_HEAD(phy_fixup_list);
static DEFINE_MUTEX(phy_fixup_lock);
-static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
- u32 flags, phy_interface_t interface);
-
/*
* Creates a new phy_fixup and adds it to the list
* @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)
@@ -527,12 +524,12 @@ int phy_init_hw(struct phy_device *phydev)
*
* Description: Called by drivers to attach to a particular PHY
* device. The phy_device is found, and properly hooked up
- * to the phy_driver. If no driver is attached, then the
- * genphy_driver is used. The phy_device is given a ptr to
+ * to the phy_driver. If no driver is attached, then a
+ * generic driver is used. The phy_device is given a ptr to
* the attaching device, and given a callback for link status
* change. The phy_device is returned to the attaching driver.
*/
-static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
struct device *d = &phydev->dev;
@@ -541,12 +538,10 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
/* Assume that if there is no driver, that it doesn't
* exist, and we should use the genphy driver. */
if (NULL == d->driver) {
- if (phydev->is_c45) {
- pr_err("No driver for phy %x\n", phydev->phy_id);
- return -ENODEV;
- }
-
- d->driver = &genphy_driver[GENPHY_DRV_1G].driver;
+ if (phydev->is_c45)
+ d->driver = &genphy_driver[GENPHY_DRV_10G].driver;
+ else
+ d->driver = &genphy_driver[GENPHY_DRV_1G].driver;
err = d->driver->probe(d);
if (err >= 0)
@@ -579,6 +574,7 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
return err;
}
+EXPORT_SYMBOL(phy_attach_direct);
/**
* phy_attach - attach a network device to a particular PHY device
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 1d6d1b9..5ccbac1 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -581,6 +581,8 @@ int phy_init_hw(struct phy_device *phydev);
struct phy_device * phy_attach(struct net_device *dev,
const char *bus_id, phy_interface_t interface);
struct phy_device *phy_find_first(struct mii_bus *bus);
+int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+ u32 flags, phy_interface_t interface);
int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
void (*handler)(struct net_device *),
phy_interface_t interface);
--
1.8.4.1
^ permalink raw reply related
* [PATCH 6/6] [v4] phylib: Add of_phy_attach
From: shh.xie @ 2014-01-07 2:14 UTC (permalink / raw)
To: davem, jg1.han, mugunthanvnm, f.fainelli, netdev, linux-kernel
Cc: Shaohui.Xie, Andy Fleming
From: Andy Fleming <afleming@gmail.com>
10G PHYs don't currently support running the state machine, which
is implicitly setup via of_phy_connect(). Therefore, it is necessary
to implement an OF version of phy_attach(), which does everything
except start the state machine.
Signed-off-by: Andy Fleming <afleming@gmail.com>
Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
resend for v4.
drivers/of/of_mdio.c | 19 +++++++++++++++++++
include/linux/of_mdio.h | 9 +++++++++
2 files changed, 28 insertions(+)
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index d5a57a9..21076ac 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -247,3 +247,22 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
return IS_ERR(phy) ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_connect_fixed_link);
+
+/**
+ * of_phy_attach - Attach to a PHY without starting the state machine
+ * @dev: pointer to net_device claiming the phy
+ * @phy_np: Node pointer for the PHY
+ * @flags: flags to pass to the PHY
+ * @iface: PHY data interface type
+ */
+struct phy_device *of_phy_attach(struct net_device *dev,
+ struct device_node *phy_np, u32 flags, phy_interface_t iface)
+{
+ struct phy_device *phy = of_phy_find_device(phy_np);
+
+ if (!phy)
+ return NULL;
+
+ return phy_attach_direct(dev, phy, flags, iface) ? NULL : phy;
+}
+EXPORT_SYMBOL(of_phy_attach);
diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h
index 8163107..108583a 100644
--- a/include/linux/of_mdio.h
+++ b/include/linux/of_mdio.h
@@ -19,6 +19,9 @@ extern struct phy_device *of_phy_connect(struct net_device *dev,
struct device_node *phy_np,
void (*hndlr)(struct net_device *),
u32 flags, phy_interface_t iface);
+struct phy_device *of_phy_attach(struct net_device *dev,
+ struct device_node *phy_np, u32 flags,
+ phy_interface_t iface);
extern struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
void (*hndlr)(struct net_device *),
phy_interface_t iface);
@@ -44,6 +47,12 @@ static inline struct phy_device *of_phy_connect(struct net_device *dev,
return NULL;
}
+static inline struct phy_device *of_phy_attach(struct net_device *dev,
+ struct device_node *phy_np, u32 flags, phy_interface_t iface)
+{
+ return NULL;
+}
+
static inline struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
void (*hndlr)(struct net_device *),
phy_interface_t iface)
--
1.8.4.1
^ permalink raw reply related
* [PATCH v3 0/3] Add ethernet support for r7s72100
From: Simon Horman @ 2014-01-07 2:27 UTC (permalink / raw)
To: netdev, linux-sh
Cc: linux-arm-kernel, Magnus Damm, Sergei Shtylyov, Simon Horman
Hi,
this is a third pass at adding ethernet support to sh-pfc for
the r7s72100 SoC.
This series is based on a merge of:
* The topic/r7s72100-v3.13-rc7-20140107 tag in my renesas tree
* net-next
- Head revision: 56a4342dfe3145cd
("Merge branch 'master' of
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net")
The first patch, targeted at net-next, also applies cleanly there.
Changes since v2
* Trivial rebase
* Dropped "RFC" from subject
Changes since v1 are noted in the changelog of each patch.
Simon Horman (3):
sh_eth: Add support for r7s72100
ARM: shmobile: r7s72100: Add clock for r7s72100-ether
ARM: shmobile: genmai: Enable r7s72100-ether
arch/arm/mach-shmobile/board-genmai.c | 21 ++++++
arch/arm/mach-shmobile/clock-r7s72100.c | 4 ++
drivers/net/ethernet/renesas/sh_eth.c | 119 ++++++++++++++++++++++++++++++--
drivers/net/ethernet/renesas/sh_eth.h | 4 +-
4 files changed, 141 insertions(+), 7 deletions(-)
--
1.8.4
^ permalink raw reply
* [PATCH v3 net-next 1/3] sh_eth: Add support for r7s72100
From: Simon Horman @ 2014-01-07 2:27 UTC (permalink / raw)
To: netdev, linux-sh
Cc: linux-arm-kernel, Magnus Damm, Sergei Shtylyov, Simon Horman
In-Reply-To: <1389061635-4083-1-git-send-email-horms+renesas@verge.net.au>
This is a fast ethernet controller.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
v2
* As suggested by Magnus Damm and Sergei Shtylyov
- r7s72100 ethernet is not gigabit so do not refer to it as such
* As suggested by Magnus Damm
- As RZ specific register layout rather than using the gigabit layout
which includes registers that do not exist on this chip.
As suggested by Sergei Shtylyov
- Do not use sh_eth_chip_reset_r8a7740 as it accesses non-existent
RMII registers. Instead use sh_eth_chip_reset.
- Do not use sh_eth_set_rate_gether as it accesses non-existent registers.
- Do not use reserved LCHNG bit of ECSR
- Do not use reserved LCHNGIP bit of ECSIPR
- Document that R8A779x also needs a 16 bit shift of the RFS bits
- Do not document that the R7S72100 has GECMR, it does not
---
drivers/net/ethernet/renesas/sh_eth.c | 119 ++++++++++++++++++++++++++++++++--
drivers/net/ethernet/renesas/sh_eth.h | 4 +-
2 files changed, 116 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 8884107..de1a437 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -190,6 +190,59 @@ static const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
[TRIMD] = 0x027c,
};
+static const u16 sh_eth_offset_fast_rz[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [EDSR] = 0x0000,
+ [EDMR] = 0x0400,
+ [EDTRR] = 0x0408,
+ [EDRRR] = 0x0410,
+ [EESR] = 0x0428,
+ [EESIPR] = 0x0430,
+ [TDLAR] = 0x0010,
+ [TDFAR] = 0x0014,
+ [TDFXR] = 0x0018,
+ [TDFFR] = 0x001c,
+ [RDLAR] = 0x0030,
+ [RDFAR] = 0x0034,
+ [RDFXR] = 0x0038,
+ [RDFFR] = 0x003c,
+ [TRSCER] = 0x0438,
+ [RMFCR] = 0x0440,
+ [TFTR] = 0x0448,
+ [FDR] = 0x0450,
+ [RMCR] = 0x0458,
+ [RPADIR] = 0x0460,
+ [FCFTR] = 0x0468,
+ [CSMR] = 0x04E4,
+
+ [ECMR] = 0x0500,
+ [ECSR] = 0x0510,
+ [ECSIPR] = 0x0518,
+ [PIR] = 0x0520,
+ [APR] = 0x0554,
+ [MPR] = 0x0558,
+ [PFTCR] = 0x055c,
+ [PFRCR] = 0x0560,
+ [TPAUSER] = 0x0564,
+ [MAHR] = 0x05c0,
+ [MALR] = 0x05c8,
+ [CEFCR] = 0x0740,
+ [FRECR] = 0x0748,
+ [TSFRCR] = 0x0750,
+ [TLFRCR] = 0x0758,
+ [RFCR] = 0x0760,
+ [MAFCR] = 0x0778,
+
+ [ARSTR] = 0x0000,
+ [TSU_CTRST] = 0x0004,
+ [TSU_VTAG0] = 0x0058,
+ [TSU_ADSBSY] = 0x0060,
+ [TSU_TEN] = 0x0064,
+ [TSU_ADRH0] = 0x0100,
+ [TSU_ADRL0] = 0x0104,
+ [TSU_ADRH31] = 0x01f8,
+ [TSU_ADRL31] = 0x01fc,
+};
+
static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
[ECMR] = 0x0100,
[RFLR] = 0x0108,
@@ -318,6 +371,14 @@ static int sh_eth_is_gether(struct sh_eth_private *mdp)
return 0;
}
+static int sh_eth_is_rz_fast_ether(struct sh_eth_private *mdp)
+{
+ if (mdp->reg_offset == sh_eth_offset_fast_rz)
+ return 1;
+ else
+ return 0;
+}
+
static void sh_eth_select_mii(struct net_device *ndev)
{
u32 value = 0x0;
@@ -701,6 +762,35 @@ static struct sh_eth_cpu_data r8a7740_data = {
.shift_rd0 = 1,
};
+/* R7S72100 */
+static struct sh_eth_cpu_data r7s72100_data = {
+ .chip_reset = sh_eth_chip_reset,
+ .set_duplex = sh_eth_set_duplex,
+
+ .register_type = SH_ETH_REG_FAST_RZ,
+
+ .ecsr_value = ECSR_ICD,
+ .ecsipr_value = ECSIPR_ICDIP,
+ .eesipr_value = 0xff7f009f,
+
+ .tx_check = EESR_TC1 | EESR_FTC,
+ .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
+ EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
+ EESR_TDE | EESR_ECI,
+ .fdr_value = 0x0000070f,
+ .rmcr_value = RMCR_RNC,
+
+ .apr = 1,
+ .mpr = 1,
+ .tpauser = 1,
+ .hw_swap = 1,
+ .rpadir = 1,
+ .rpadir_value = 2 << 16,
+ .no_trimd = 1,
+ .tsu = 1,
+ .shift_rd0 = 1,
+};
+
static struct sh_eth_cpu_data sh7619_data = {
.register_type = SH_ETH_REG_FAST_SH3_SH2,
@@ -767,7 +857,7 @@ static int sh_eth_reset(struct net_device *ndev)
struct sh_eth_private *mdp = netdev_priv(ndev);
int ret = 0;
- if (sh_eth_is_gether(mdp)) {
+ if (sh_eth_is_gether(mdp) || sh_eth_is_rz_fast_ether(mdp)) {
sh_eth_write(ndev, EDSR_ENALL, EDSR);
sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER,
EDMR);
@@ -880,6 +970,8 @@ static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
{
if (sh_eth_is_gether(mdp))
return EDTRR_TRNS_GETHER;
+ else if (sh_eth_is_rz_fast_ether(mdp))
+ return EDTRR_TRNS_RZ_ETHER;
else
return EDTRR_TRNS_ETHER;
}
@@ -1041,7 +1133,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
/* Rx descriptor address set */
if (i == 0) {
sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
- if (sh_eth_is_gether(mdp))
+ if (sh_eth_is_gether(mdp) ||
+ sh_eth_is_rz_fast_ether(mdp))
sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR);
}
}
@@ -1062,7 +1155,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
if (i == 0) {
/* Tx descriptor address set */
sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
- if (sh_eth_is_gether(mdp))
+ if (sh_eth_is_gether(mdp) ||
+ sh_eth_is_rz_fast_ether(mdp))
sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR);
}
}
@@ -1309,9 +1403,9 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
/* In case of almost all GETHER/ETHERs, the Receive Frame State
* (RFS) bits in the Receive Descriptor 0 are from bit 9 to
- * bit 0. However, in case of the R8A7740's GETHER, the RFS
- * bits are from bit 25 to bit 16. So, the driver needs right
- * shifting by 16.
+ * bit 0. However, in case of the R8A7740, R8A779x and
+ * R7S72100 the RFS bits are from bit 25 to bit 16. So, the
+ * driver needs right shifting by 16.
*/
if (mdp->cd->shift_rd0)
desc_status >>= 16;
@@ -2061,6 +2155,10 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
+ if (sh_eth_is_rz_fast_ether(mdp)) {
+ return &ndev->stats;
+ }
+
pm_runtime_get_sync(&mdp->pdev->dev);
ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR);
@@ -2442,6 +2540,11 @@ static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev,
/* SuperH's TSU register init function */
static void sh_eth_tsu_init(struct sh_eth_private *mdp)
{
+ if (sh_eth_is_rz_fast_ether(mdp)) {
+ sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */
+ return;
+ }
+
sh_eth_tsu_write(mdp, 0, TSU_FWEN0); /* Disable forward(0->1) */
sh_eth_tsu_write(mdp, 0, TSU_FWEN1); /* Disable forward(1->0) */
sh_eth_tsu_write(mdp, 0, TSU_FCM); /* forward fifo 3k-3k */
@@ -2564,6 +2667,9 @@ static const u16 *sh_eth_get_register_offset(int register_type)
case SH_ETH_REG_FAST_RCAR:
reg_offset = sh_eth_offset_fast_rcar;
break;
+ case SH_ETH_REG_FAST_RZ:
+ reg_offset = sh_eth_offset_fast_rz;
+ break;
case SH_ETH_REG_FAST_SH4:
reg_offset = sh_eth_offset_fast_sh4;
break;
@@ -2799,6 +2905,7 @@ static struct platform_device_id sh_eth_id_table[] = {
{ "sh7757-ether", (kernel_ulong_t)&sh7757_data },
{ "sh7757-gether", (kernel_ulong_t)&sh7757_data_giga },
{ "sh7763-gether", (kernel_ulong_t)&sh7763_data },
+ { "r7s72100-ether", (kernel_ulong_t)&r7s72100_data },
{ "r8a7740-gether", (kernel_ulong_t)&r8a7740_data },
{ "r8a777x-ether", (kernel_ulong_t)&r8a777x_data },
{ "r8a7790-ether", (kernel_ulong_t)&r8a779x_data },
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 0fe35b7..0bcde90 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -156,6 +156,7 @@ enum {
enum {
SH_ETH_REG_GIGABIT,
SH_ETH_REG_FAST_RCAR,
+ SH_ETH_REG_FAST_RZ,
SH_ETH_REG_FAST_SH4,
SH_ETH_REG_FAST_SH3_SH2
};
@@ -169,7 +170,7 @@ enum {
/* Register's bits
*/
-/* EDSR : sh7734, sh7757, sh7763, and r8a7740 only */
+/* EDSR : sh7734, sh7757, sh7763, r8a7740 and r7s72100 only */
enum EDSR_BIT {
EDSR_ENT = 0x01, EDSR_ENR = 0x02,
};
@@ -191,6 +192,7 @@ enum DMAC_M_BIT {
/* EDTRR */
enum DMAC_T_BIT {
EDTRR_TRNS_GETHER = 0x03,
+ EDTRR_TRNS_RZ_ETHER = 0x03,
EDTRR_TRNS_ETHER = 0x01,
};
--
1.8.4
^ permalink raw reply related
* [PATCH v3 2/3] ARM: shmobile: r7s72100: Add clock for r7s72100-ether
From: Simon Horman @ 2014-01-07 2:27 UTC (permalink / raw)
To: netdev, linux-sh
Cc: linux-arm-kernel, Magnus Damm, Sergei Shtylyov, Simon Horman
In-Reply-To: <1389061635-4083-1-git-send-email-horms+renesas@verge.net.au>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
v2
* As suggested by Sergei Shtylyov
- Add MSTP74 to beginning of enum on a line by itself
* As suggested by Magnus Damm
- r7s72100 ethernet is not gigabit so do not refer to it as such
---
arch/arm/mach-shmobile/clock-r7s72100.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-shmobile/clock-r7s72100.c b/arch/arm/mach-shmobile/clock-r7s72100.c
index e6ab0cd..c4ba651 100644
--- a/arch/arm/mach-shmobile/clock-r7s72100.c
+++ b/arch/arm/mach-shmobile/clock-r7s72100.c
@@ -27,6 +27,7 @@
#define FRQCR2 0xfcfe0014
#define STBCR3 0xfcfe0420
#define STBCR4 0xfcfe0424
+#define STBCR7 0xfcfe0430
#define STBCR9 0xfcfe0438
#define PLL_RATE 30
@@ -146,6 +147,7 @@ struct clk div4_clks[DIV4_NR] = {
};
enum { MSTP97, MSTP96, MSTP95, MSTP94,
+ MSTP74,
MSTP47, MSTP46, MSTP45, MSTP44, MSTP43, MSTP42, MSTP41, MSTP40,
MSTP33, MSTP_NR };
@@ -154,6 +156,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP96] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 6, 0), /* RIIC1 */
[MSTP95] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 5, 0), /* RIIC2 */
[MSTP94] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 4, 0), /* RIIC3 */
+ [MSTP74] = SH_CLK_MSTP8(&peripheral1_clk, STBCR7, 4, 0), /* Ether */
[MSTP47] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 7, 0), /* SCIF0 */
[MSTP46] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 6, 0), /* SCIF1 */
[MSTP45] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 5, 0), /* SCIF2 */
@@ -176,6 +179,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP clocks */
+ CLKDEV_DEV_ID("r7s72100-ether", &mstp_clks[MSTP74]),
CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP33]),
/* ICK */
--
1.8.4
^ permalink raw reply related
* [PATCH v3 3/3] ARM: shmobile: genmai: Enable r7s72100-ether
From: Simon Horman @ 2014-01-07 2:27 UTC (permalink / raw)
To: netdev, linux-sh
Cc: linux-arm-kernel, Magnus Damm, Sergei Shtylyov, Simon Horman
In-Reply-To: <1389061635-4083-1-git-send-email-horms+renesas@verge.net.au>
---
v2
* As suggested by Magnus Damm and Sergei Shtylyov
- r7s72100 ethernet is not gigabit so do not refer to it as such
* As suggested by Sergei Shtylyov
- set no_ether_link as there is no LINK signal documented
in the manual
---
arch/arm/mach-shmobile/board-genmai.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm/mach-shmobile/board-genmai.c b/arch/arm/mach-shmobile/board-genmai.c
index 3e92e3c..a1f6fe1 100644
--- a/arch/arm/mach-shmobile/board-genmai.c
+++ b/arch/arm/mach-shmobile/board-genmai.c
@@ -20,15 +20,36 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/sh_eth.h>
#include <mach/common.h>
+#include <mach/irqs.h>
#include <mach/r7s72100.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+/* Ether */
+static const struct sh_eth_plat_data ether_pdata __initconst = {
+ .phy = 0x00, /* PD60610 */
+ .edmac_endian = EDMAC_LITTLE_ENDIAN,
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .no_ether_link = 1
+};
+
+static const struct resource ether_resources[] __initconst = {
+ DEFINE_RES_MEM(0xe8203000, 0x800),
+ DEFINE_RES_MEM(0xe8204800, 0x200),
+ DEFINE_RES_IRQ(gic_iid(359)),
+};
+
static void __init genmai_add_standard_devices(void)
{
r7s72100_clock_init();
r7s72100_add_dt_devices();
+
+ platform_device_register_resndata(&platform_bus, "r7s72100-ether", -1,
+ ether_resources,
+ ARRAY_SIZE(ether_resources),
+ ðer_pdata, sizeof(ether_pdata));
}
static const char * const genmai_boards_compat_dt[] __initconst = {
--
1.8.4
^ permalink raw reply related
* Re: [PATCHv4 net-next] xfrm: Namespacify xfrm_policy_sk_bundles
From: Fan Du @ 2014-01-07 2:43 UTC (permalink / raw)
To: Steffen Klassert; +Cc: Timo Teras, Eric Dumazet, davem, netdev
In-Reply-To: <20140106103512.GR31491@secunet.com>
On 2014年01月06日 18:35, Steffen Klassert wrote:
> On Wed, Dec 25, 2013 at 04:44:26PM +0800, Fan Du wrote:
>>
>>
>> On 2013年12月25日 16:11, Timo Teras wrote:
>>> On Wed, 25 Dec 2013 14:40:36 +0800
>>> Fan Du<fan.du@windriver.com> wrote:
>>>
>>>>> ccing Timo
>>>>>
>>>>> On 2013年12月24日 18:35, Steffen Klassert wrote:
>>>>>> > On Fri, Dec 20, 2013 at 11:34:41AM +0800, Fan Du wrote:
>>>>>>> >>
>>>>>>> >> Subject: [PATCHv4 net-next] xfrm: Namespacify
>>>>>>> >> xfrm_policy_sk_bundles
>>>>>>> >>
>>>>>>> >> xfrm_policy_sk_bundles, protected by
>>>>>>> >> net->xfrm.xfrm_policy_sk_bundle_lock should be put into netns xfrm
>>>>>>> >> structure, otherwise xfrm_policy_sk_bundles can be corrupted from
>>>>>>> >> different net namespace.
>>>>>> >
>>>>>> > I'm ok with this patch, but I wonder where we use these cached
>>>>>> > socket bundles. After a quick look I see where we add and where we
>>>>>> > delete them, but I can't see how we use these cached bundles.
>>>>>
>>>>> Interesting
>>>>>
>>>>> The per socket bundles is introduced by Timo in commit 80c802f3
>>>>> ("xfrm: cache bundles instead of policies for outgoing flows")
>>> Those existed even before. I just did systematic transformation of the
>>> caching code to work on bundle level instead of policy level.
>>
>> Apologizes and thanks for your quick reply :)
>>
>>>>> But one fundamental question is why not use existing flow cache
>>>>> for per socket bundles as well? then no need to create such per
>>>>> sock xdst for every packet, and also share the same flow cache
>>>>> flush mechanism.
>>> It was needed when the flow cache cached policies. They explicitly
>>> needed to check the socket for per-socket policy. So it made no sense
>>> to have anything socket related in the cache.
>>
>> I understand your concern.
>>
>> per sk bundles could be distinguished by putting per sk policy pointer into
>> struct flow_cache_entry, and then compare sk policy between cached policy
>> against with sk policy.
Yes, I tested sk policy with udp, when transmit, dst will be cached into sk
by sk_dst_set. Let's leave current implementation as it is.
Please kindly review if there is any concern about v4.
> Most protocols cache the used routes at the sockets, so I'm not sure if
> we really need to cache them in xfrm too.
>
> Given the fact that we don't use these cached socket policy bundles,
> it would be already an improvement if we would simply remove this caching.
> All we are doing here is wasting memory.
>>
>> And I also notice flow cache is global across different namespaces, but flow
>> cache flush is doing a per-cpu(also global) operation, that's not fair for
>> slim netns as compared with fat netns which floods flow cache. Maybe it's
>> time to make flow cache also name space aware.
>
> Yes, making the flow cache namespace aware would be a good thing.
>
I will give it a try :)
--
浮沉随浪只记今朝笑
--fan
^ permalink raw reply
* Re: [PATCH net 1/2] macvlan: forbid L2 fowarding offload for macvtap
From: Jason Wang @ 2014-01-07 3:10 UTC (permalink / raw)
To: Neil Horman
Cc: John Fastabend, davem, netdev, linux-kernel, mst, John Fastabend,
Vlad Yasevich
In-Reply-To: <20140106122628.GA24280@hmsreliant.think-freely.org>
On 01/06/2014 08:26 PM, Neil Horman wrote:
> On Mon, Jan 06, 2014 at 03:54:21PM +0800, Jason Wang wrote:
>> On 01/06/2014 03:35 PM, John Fastabend wrote:
>>> On 01/05/2014 07:21 PM, Jason Wang wrote:
>>>> L2 fowarding offload will bypass the rx handler of real device. This
>>>> will make
>>>> the packet could not be forwarded to macvtap device. Another problem
>>>> is the
>>>> dev_hard_start_xmit() called for macvtap does not have any
>>>> synchronization.
>>>>
>>>> Fix this by forbidding L2 forwarding for macvtap.
>>>>
>>>> Cc: John Fastabend <john.r.fastabend@intel.com>
>>>> Cc: Neil Horman <nhorman@tuxdriver.com>
>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>>> ---
>>>> drivers/net/macvlan.c | 5 ++++-
>>>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>>>
>>> I must be missing something.
>>>
>>> The lower layer device should set skb->dev to the correct macvtap
>>> device on receive so that in netif_receive_skb_core() the macvtap
>>> handler is hit. Skipping the macvlan receive handler should be OK
>>> because the switching was done by the hardware. If I read macvtap.c
>>> correctly macvlan_common_newlink() is called with 'dev' where 'dev'
>>> is the macvtap device. Any idea what I'm missing? I guess I'll need
>>> to setup a macvtap test case.
>> Unlike macvlan, macvtap depends on rx handler on the lower device to
>> work. In this case macvlan_handle_frame() will call macvtap_receive().
>> So doing netif_receive_skb_core() for macvtap device directly won't work
>> since we need to forward the packet to userspace instead of kernel.
>>
>> For net-next.git, it may work since commit
>> 6acf54f1cf0a6747bac9fea26f34cfc5a9029523 let macvtap device register an
>> rx handler for itself.
> I agree, this seems like it should already be fixed with the above commit. With
> this the macvlan rx handler should effectively be a no-op as far as the
> reception of frames is concerned. As long as the driver sets the dev correctly
> to the macvtap device (and it appears to), macvtap will get frames to user
> space, regardless of weather the software or hardware did the switching. If
> thats the case though, I think the solution is moving that fix to -stable
> (pending testing of course), rather than comming up with a new fix.
>
>>> And what synchronization are you worried about on dev_hard_start_xmit()?
>>> In the L2 forwarding offload case macvlan_open() clears the NETIF_F_LLTX
>>> flag so HARD_TX_LOCK protects the driver txq. We might hit this warning
>>> in dev_queue_xmit() though,
>>>
>>> net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
>>>
>>> Perhaps we can remove it.
>> The problem is macvtap does not call dev_queue_xmit() for macvlan
>> device. It calls macvlan_start_xmit() directly from macvtap_get_user().
>> So HARD_TX_LOCK was not done for the txq.
> This seems to also be fixed by 6acf54f1cf0a6747bac9fea26f34cfc5a9029523.
> Macvtap does, as of that commit use dev_queue_xmit for the transmission of
> frames to the lowerdevice.
Unfortunately not. This commit has a side effect that it in fact
disables the multiqueue macvtap transmission. Since all macvtap queues
will contend on a single qdisc lock.
For L2 forwarding offload itself, more issues need to be addressed for
multiqueue macvtap:
- ndo_dfwd_add_station() can only create queues per device at ndo_open,
but multiqueue macvtap allows user to create and destroy queues at their
will and at any time.
- it looks that ixgbe has a upper limit of 4 queues per station, but
macvtap currently allows up to 16 queues per device.
So more works need to be done and unless those above 3 issues were
addressed, this patch is really needed to make sure macvtap works.
>
> Regards
> Neil
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH net 1/2] macvlan: forbid L2 fowarding offload for macvtap
From: Jason Wang @ 2014-01-07 3:17 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-kernel, mst, john.r.fastabend, nhorman
In-Reply-To: <20140106.154740.590358835696689785.davem@davemloft.net>
On 01/07/2014 04:47 AM, David Miller wrote:
> From: Jason Wang <jasowang@redhat.com>
> Date: Mon, 6 Jan 2014 11:21:06 +0800
>
>> L2 fowarding offload will bypass the rx handler of real device. This will make
>> the packet could not be forwarded to macvtap device. Another problem is the
>> dev_hard_start_xmit() called for macvtap does not have any synchronization.
>>
>> Fix this by forbidding L2 forwarding for macvtap.
>>
>> Cc: John Fastabend <john.r.fastabend@intel.com>
>> Cc: Neil Horman <nhorman@tuxdriver.com>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
> I think I agree with Neil that the rx_handler change might be the best
> way to fix this. That change seems to have a lot of nice unintended
> side effects, no?
Not all sides effects are nice.
One obvious issue is it disables the multiqueue macvtap transmission,
since all queues will contend on a single qdisc lock of macvlan. And
even more, multiqueue macvtap support creating and destroying a queue on
demand which is not supported by L2 forwarding offload.
So L2 forwarding offload needs more fixes to let the multiqueue macvtap
works. Currently, we really need this patch to make sure macvtap works
as expected.
^ permalink raw reply
* [PATCH net] r8152: correct some messages
From: Hayes Wang @ 2014-01-07 3:18 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, linux-usb, Hayes Wang
In-Reply-To: <1388999999-9218-1-git-send-email-hayeswang@realtek.com>
- Replace pr_warn_ratelimited() with net_ratelimit() and netdev_warn().
- Adjust the algnment of some messages.
- Remove the peroid.
- Fix some messages don't have terminating newline.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 5107372..49632ff 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -814,10 +814,12 @@ static void read_bulk_callback(struct urb *urb)
case -ENOENT:
return; /* the urb is in unlink state */
case -ETIME:
- pr_warn_ratelimited("may be reset is needed?..\n");
+ if (net_ratelimit())
+ netdev_warn(netdev, "maybe reset is needed?\n");
break;
default:
- pr_warn_ratelimited("Rx status %d\n", status);
+ if (net_ratelimit())
+ netdev_warn(netdev, "Rx status %d\n", status);
break;
}
@@ -850,7 +852,8 @@ static void write_bulk_callback(struct urb *urb)
stats = rtl8152_get_stats(tp->netdev);
if (status) {
- pr_warn_ratelimited("Tx status %d\n", status);
+ if (net_ratelimit())
+ netdev_warn(tp->netdev, "Tx status %d\n", status);
stats->tx_errors += agg->skb_num;
} else {
stats->tx_packets += agg->skb_num;
@@ -927,7 +930,7 @@ resubmit:
netif_device_detach(tp->netdev);
else if (res)
netif_err(tp, intr, tp->netdev,
- "can't resubmit intr, status %d\n", res);
+ "can't resubmit intr, status %d\n", res);
}
static inline void *rx_agg_align(void *data)
@@ -1336,7 +1339,7 @@ static void rtl8152_tx_timeout(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev);
int i;
- netif_warn(tp, tx_err, netdev, "Tx timeout.\n");
+ netif_warn(tp, tx_err, netdev, "Tx timeout\n");
for (i = 0; i < RTL8152_MAX_TX; i++)
usb_unlink_urb(tp->tx_info[i].urb);
}
@@ -1806,8 +1809,8 @@ static int rtl8152_open(struct net_device *netdev)
if (res) {
if (res == -ENODEV)
netif_device_detach(tp->netdev);
- netif_warn(tp, ifup, netdev,
- "intr_urb submit failed: %d\n", res);
+ netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
+ res);
return res;
}
@@ -2094,7 +2097,7 @@ static int rtl8152_probe(struct usb_interface *intf,
netdev = alloc_etherdev(sizeof(struct r8152));
if (!netdev) {
- dev_err(&intf->dev, "Out of memory");
+ dev_err(&intf->dev, "Out of memory\n");
return -ENOMEM;
}
@@ -2135,11 +2138,11 @@ static int rtl8152_probe(struct usb_interface *intf,
ret = register_netdev(netdev);
if (ret != 0) {
- netif_err(tp, probe, netdev, "couldn't register the device");
+ netif_err(tp, probe, netdev, "couldn't register the device\n");
goto out1;
}
- netif_info(tp, probe, netdev, "%s", DRIVER_VERSION);
+ netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
return 0;
--
1.8.4.2
^ permalink raw reply related
* Re: [PATCH v3.5 10/19] mac8011: slight optimization of addr compare
From: Ding Tianhong @ 2014-01-07 3:40 UTC (permalink / raw)
To: Johannes Berg
Cc: John W. Linville, David S. Miller, linux-wireless, Netdev,
linux-kernel@vger.kernel.org
In-Reply-To: <1389021111.5891.21.camel@jlt4.sipsolutions.net>
On 2014/1/6 23:11, Johannes Berg wrote:
> On Thu, 2013-12-26 at 19:40 +0800, Ding Tianhong wrote:
>> Use the possibly more efficient ether_addr_equal
>> to instead of memcmp.
>
> This is a slow-path, I don't think that's really worth it. It kinda
> makes sense, but relies on the struct mac_address allocation for
> alignment and the fact that there are no other members in that struct,
> so it seems to me that this ought to also add some alignment attributes?
>
> johannes
>
>
Yes, I had to say that it is really a slight optimization.And I am sure the address in the struct
is alignment, otherwise I have to use the ether_addr_equal_unaligned().
Regards
Ding
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
^ permalink raw reply
* Re: [PATCH net 2/2] net: core: explicitly select a txq before doing l2 forwarding
From: Jason Wang @ 2014-01-07 3:42 UTC (permalink / raw)
To: Neil Horman; +Cc: mst, e1000-devel, netdev, linux-kernel, John Fastabend, davem
In-Reply-To: <20140106124248.GB24280@hmsreliant.think-freely.org>
On 01/06/2014 08:42 PM, Neil Horman wrote:
> On Mon, Jan 06, 2014 at 11:21:07AM +0800, Jason Wang wrote:
>> Currently, the tx queue were selected implicitly in ndo_dfwd_start_xmit(). The
>> will cause several issues:
>>
>> - NETIF_F_LLTX was forced for macvlan device in this case which lead extra lock
>> contention.
>> - dev_hard_start_xmit() was called with NULL txq which bypasses the net device
>> watchdog
>> - dev_hard_start_xmit() does not check txq everywhere which will lead a crash
>> when tso is disabled for lower device.
>>
>> Fix this by explicitly introducing a select queue method just for l2 forwarding
>> offload (ndo_dfwd_select_queue), and introducing dfwd_direct_xmit() to do the
>> queue selecting and transmitting for l2 forwarding.
>>
>> With this fixes, NETIF_F_LLTX could be preserved for macvlan and there's no need
>> to check txq against NULL in dev_hard_start_xmit().
>>
>> In the future, it was also required for macvtap l2 forwarding support since it
>> provides a necessary synchronization method.
>>
>> Cc: John Fastabend <john.r.fastabend@intel.com>
>> Cc: Neil Horman <nhorman@tuxdriver.com>
>> Cc: e1000-devel@lists.sourceforge.net
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
> Instead of creating another operation here to do special queue selection, why
> not just have ndo_dfwd_start_xmit include a pointer to a pointer in its argument
> list, so it can pass the txq it used back to the caller (dev_hard_start_xmit)?
> ndo_dfwd_start_xmit already knows which queue set to pick from (since their
> reserved for the device doing the transmitting). It seems more clear to me than
> creating a new netdevice operation.
See commit 8ffab51b3dfc54876f145f15b351c41f3f703195 ("macvlan: lockless
tx path"). The point is keep the tx path lockless to be efficient and
simplicity for management. And macvtap multiqueue was also implemented
with this assumption. The real contention should be done in the txq of
lower device instead of macvlan itself. This is also needed for
multiqueue macvtap.
>
> As for the crash issue, I'm not sure what you mean. Where in
> dev_hard_start_xmit would we need to check txq that we're not currently, and
> what crash results?
Well, see current dev_hard_start_xmit(), if lower device does not
support tso or tso is disabled, in gso path:
gso:
...
txq_trans_update(txq);
if (unlikely(netif_xmit_stopped(txq) && skb->next))
There's an obvious NULL pointer dereference.
>
> Also, can you elaborate on what you mean by additional lock contention?
If the lower device has NETIF_F_LLTX, then both macvlan txq lock and the
lock of device itself must be held before doing transmission. In the
case, the macvlan txq lock contention is obvious unnecessary.
> What
> contention do you see that goes above and beyond the normal locking required by
> txq access?
As I said above, the point is keeping the lockess tx path and make the
contention of txq for real device instead of macvlan itself.
> I suppose its extra locking above and beyond in the macvtap case,
> where you would otherwise never hit hardware, but that not the only use case,
> and I think the solution there is likely to add some code in the macvlan feature
> set handler so that NETIF_F_LLTX is cleared if you disable the hardware
> forwarding acceleration via ethtool.
>
> Regards
> Neil
>
------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT
organizations don't have a clear picture of how application performance
affects their revenue. With AppDynamics, you get 100% visibility into your
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply
* Re: [PATCH net] vti: get rid of nf mark rule in prerouting
From: Stephen Hemminger @ 2014-01-07 4:59 UTC (permalink / raw)
To: David Miller; +Cc: christophe.gouault, netdev, amwang, saurabh
In-Reply-To: <20131011.145304.305063991853045981.davem@davemloft.net>
On Fri, 11 Oct 2013 14:53:04 -0400 (EDT)
David Miller <davem@davemloft.net> wrote:
> From: Christophe Gouault <christophe.gouault@6wind.com>
> Date: Tue, 8 Oct 2013 17:21:22 +0200
>
> > This patch fixes and improves the use of vti interfaces (while
> > lightly changing the way of configuring them).
> ...
> > Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
> > ---
> > This is is both a fix and enhancement patch. However, there are 2 ways
> > of fixing the inbound processing bug:
> > - either keep the current configuration model (ikey + netfilter rule)
> > and change the tunnel lookup method. This patch would then be reverted
> > by the enhancement (this sounds counterproductive).
> > - or directly change the configuration model (okey, no netfilter rule) and keep
> > the current tunnel lookup method.
>
> Ok, applied and queued up for -stable, thanks.
I hate to reply to old threads, but this keeps context.
We have discovered a problem with this patch, it breaks the earlier use of VTI
because it loses the mark applied through iptables. It was not a "light change"
to the way to configure them and should have gotten more review and was not
appropriate for -stable.
^ permalink raw reply
* Re: inconsistency of ethtool feature names for get vs. set
From: Bill Fink @ 2014-01-07 4:58 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Or Gerlitz, netdev
In-Reply-To: <1388688114.9947.30.camel@bwh-desktop.uk.level5networks.com>
On Thu, 2 Jan 2014, Ben Hutchings wrote:
> On Thu, 2014-01-02 at 15:03 +0000, Ben Hutchings wrote:
> > On Thu, 2014-01-02 at 11:47 +0200, Or Gerlitz wrote:
> [...]
> > > $ ethtool -k eth1 | grep generic-receive-offload
> > > generic-receive-offload: on
> > >
> > > $ ethtool -K eth1 generic-receive-offload off
> > > ethtool: bad command line argument(s)
> > > For more information run ethtool -h
> > >
> > > --> looking in the sources and realizing I need to use "rx-gro"
> >
> > Or 'gro'. All the old feature names that can be used with the -K option
> > are listed in the manual page. All the new feature names are consistent
> > between -k/-K.
>
> By 'new feature names' I mean names for features that weren't previously
> exposed through ethtool.
>
> [...]
> > > Basically, this can be resolved by fairly simple patch, but I wasn't
> > > sure if you want it in user space, in the kernel or both...
> >
> > How do you intend to resolve this, given the compatibility requirement
> > that the old names must still be reported by -k and accepted by -K?
>
> Just to be clear, I do see that there's a problem here but the fix may
> have to be mostly or entirely in documentation rather than code.
Wouldn't one simple option be to allow the long form like
generic-receive-offload for setting in addition to the existing
shortcuts rx-gro and gro? That way a user doing "ethtool -k"
could use the name provided to do a set via "ethtool -K" without
needing to consult a man page (or "ethtool -h"), while still
allowing more knowledgeable users to use the shortcut names.
-Bill
^ permalink raw reply
* Re: [PATCH net 1/2] macvlan: forbid L2 fowarding offload for macvtap
From: John Fastabend @ 2014-01-07 5:15 UTC (permalink / raw)
To: Jason Wang
Cc: Neil Horman, davem, netdev, linux-kernel, mst, John Fastabend,
Vlad Yasevich
In-Reply-To: <52CB7009.2030903@redhat.com>
On 01/06/2014 07:10 PM, Jason Wang wrote:
> On 01/06/2014 08:26 PM, Neil Horman wrote:
>> On Mon, Jan 06, 2014 at 03:54:21PM +0800, Jason Wang wrote:
>>> On 01/06/2014 03:35 PM, John Fastabend wrote:
>>>> On 01/05/2014 07:21 PM, Jason Wang wrote:
>>>>> L2 fowarding offload will bypass the rx handler of real device. This
>>>>> will make
>>>>> the packet could not be forwarded to macvtap device. Another problem
>>>>> is the
>>>>> dev_hard_start_xmit() called for macvtap does not have any
>>>>> synchronization.
>>>>>
>>>>> Fix this by forbidding L2 forwarding for macvtap.
>>>>>
>>>>> Cc: John Fastabend <john.r.fastabend@intel.com>
>>>>> Cc: Neil Horman <nhorman@tuxdriver.com>
>>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>>>> ---
>>>>> drivers/net/macvlan.c | 5 ++++-
>>>>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>>>>
>>>> I must be missing something.
>>>>
>>>> The lower layer device should set skb->dev to the correct macvtap
>>>> device on receive so that in netif_receive_skb_core() the macvtap
>>>> handler is hit. Skipping the macvlan receive handler should be OK
>>>> because the switching was done by the hardware. If I read macvtap.c
>>>> correctly macvlan_common_newlink() is called with 'dev' where 'dev'
>>>> is the macvtap device. Any idea what I'm missing? I guess I'll need
>>>> to setup a macvtap test case.
>>> Unlike macvlan, macvtap depends on rx handler on the lower device to
>>> work. In this case macvlan_handle_frame() will call macvtap_receive().
>>> So doing netif_receive_skb_core() for macvtap device directly won't work
>>> since we need to forward the packet to userspace instead of kernel.
>>>
>>> For net-next.git, it may work since commit
>>> 6acf54f1cf0a6747bac9fea26f34cfc5a9029523 let macvtap device register an
>>> rx handler for itself.
>> I agree, this seems like it should already be fixed with the above commit. With
>> this the macvlan rx handler should effectively be a no-op as far as the
>> reception of frames is concerned. As long as the driver sets the dev correctly
>> to the macvtap device (and it appears to), macvtap will get frames to user
>> space, regardless of weather the software or hardware did the switching. If
>> thats the case though, I think the solution is moving that fix to -stable
>> (pending testing of course), rather than comming up with a new fix.
>>
>>>> And what synchronization are you worried about on dev_hard_start_xmit()?
>>>> In the L2 forwarding offload case macvlan_open() clears the NETIF_F_LLTX
>>>> flag so HARD_TX_LOCK protects the driver txq. We might hit this warning
>>>> in dev_queue_xmit() though,
>>>>
>>>> net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
>>>>
>>>> Perhaps we can remove it.
>>> The problem is macvtap does not call dev_queue_xmit() for macvlan
>>> device. It calls macvlan_start_xmit() directly from macvtap_get_user().
>>> So HARD_TX_LOCK was not done for the txq.
>> This seems to also be fixed by 6acf54f1cf0a6747bac9fea26f34cfc5a9029523.
>> Macvtap does, as of that commit use dev_queue_xmit for the transmission of
>> frames to the lowerdevice.
>
> Unfortunately not. This commit has a side effect that it in fact
> disables the multiqueue macvtap transmission. Since all macvtap queues
> will contend on a single qdisc lock.
>
They will only contend on a single qdisc lock if the lower device has
1 queue. Perhaps defaulting the L2 forwarding devices to 1queue was a
mistake. But the same issue arises when running macvtap over a
non-multiqueue nic. Or even if you have a multiqueue device and create
many more macvtap queues than the lower device has queues.
Shouldn't the macvtap configuration take into account the lowest level
devices queues? How does using the L2 forwarding device change the
contention issues? Without the L2 forwarding LLTX is enabled but the
qdisc lock, etc is still acquired on the device below the macvlan.
The ixgbe driver as it is currently written can be configured for up to
4 queues by setting numtxqueues when the device is created. I assume
when creating macvtap queues the user needs to account for the number
of queues supported by the lower device.
> For L2 forwarding offload itself, more issues need to be addressed for
> multiqueue macvtap:
>
> - ndo_dfwd_add_station() can only create queues per device at ndo_open,
> but multiqueue macvtap allows user to create and destroy queues at their
> will and at any time.
same argument as above, isn't this the same when running macvtap without
the l2 offloads over a real device? I expect you hit the same contention
points when running over a real device.
> - it looks that ixgbe has a upper limit of 4 queues per station, but
> macvtap currently allows up to 16 queues per device.
>
The 4 limit was to simplify the code because the queue mapping in the
driver gets complicated if it is greater than 4. We can probably
increase this latter. But sorry reiterating how is this different than
a macvtap on a real device that supports a max of 4 queues?
> So more works need to be done and unless those above 3 issues were
> addressed, this patch is really needed to make sure macvtap works.
>
Agreed there is a lot more work here to improve things I'm just not
sure we need to disable this now. Also note its the l2 forwarding
should be disabled by default so a user would have to enable the
feature flag.
Thanks,
John
--
John Fastabend Intel Corporation
^ permalink raw reply
* Re: [PATCH net 1/2] macvlan: forbid L2 fowarding offload for macvtap
From: John Fastabend @ 2014-01-07 5:16 UTC (permalink / raw)
To: Jason Wang
Cc: Neil Horman, davem, netdev, linux-kernel, mst, John Fastabend,
Vlad Yasevich
In-Reply-To: <52CB7009.2030903@redhat.com>
On 01/06/2014 07:10 PM, Jason Wang wrote:
> On 01/06/2014 08:26 PM, Neil Horman wrote:
>> On Mon, Jan 06, 2014 at 03:54:21PM +0800, Jason Wang wrote:
>>> On 01/06/2014 03:35 PM, John Fastabend wrote:
>>>> On 01/05/2014 07:21 PM, Jason Wang wrote:
>>>>> L2 fowarding offload will bypass the rx handler of real device. This
>>>>> will make
>>>>> the packet could not be forwarded to macvtap device. Another problem
>>>>> is the
>>>>> dev_hard_start_xmit() called for macvtap does not have any
>>>>> synchronization.
>>>>>
>>>>> Fix this by forbidding L2 forwarding for macvtap.
>>>>>
>>>>> Cc: John Fastabend <john.r.fastabend@intel.com>
>>>>> Cc: Neil Horman <nhorman@tuxdriver.com>
>>>>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>>>> ---
>>>>> drivers/net/macvlan.c | 5 ++++-
>>>>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>>>>
>>>> I must be missing something.
>>>>
>>>> The lower layer device should set skb->dev to the correct macvtap
>>>> device on receive so that in netif_receive_skb_core() the macvtap
>>>> handler is hit. Skipping the macvlan receive handler should be OK
>>>> because the switching was done by the hardware. If I read macvtap.c
>>>> correctly macvlan_common_newlink() is called with 'dev' where 'dev'
>>>> is the macvtap device. Any idea what I'm missing? I guess I'll need
>>>> to setup a macvtap test case.
>>> Unlike macvlan, macvtap depends on rx handler on the lower device to
>>> work. In this case macvlan_handle_frame() will call macvtap_receive().
>>> So doing netif_receive_skb_core() for macvtap device directly won't work
>>> since we need to forward the packet to userspace instead of kernel.
>>>
>>> For net-next.git, it may work since commit
>>> 6acf54f1cf0a6747bac9fea26f34cfc5a9029523 let macvtap device register an
>>> rx handler for itself.
>> I agree, this seems like it should already be fixed with the above commit. With
>> this the macvlan rx handler should effectively be a no-op as far as the
>> reception of frames is concerned. As long as the driver sets the dev correctly
>> to the macvtap device (and it appears to), macvtap will get frames to user
>> space, regardless of weather the software or hardware did the switching. If
>> thats the case though, I think the solution is moving that fix to -stable
>> (pending testing of course), rather than comming up with a new fix.
>>
>>>> And what synchronization are you worried about on dev_hard_start_xmit()?
>>>> In the L2 forwarding offload case macvlan_open() clears the NETIF_F_LLTX
>>>> flag so HARD_TX_LOCK protects the driver txq. We might hit this warning
>>>> in dev_queue_xmit() though,
>>>>
>>>> net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
>>>>
>>>> Perhaps we can remove it.
>>> The problem is macvtap does not call dev_queue_xmit() for macvlan
>>> device. It calls macvlan_start_xmit() directly from macvtap_get_user().
>>> So HARD_TX_LOCK was not done for the txq.
>> This seems to also be fixed by 6acf54f1cf0a6747bac9fea26f34cfc5a9029523.
>> Macvtap does, as of that commit use dev_queue_xmit for the transmission of
>> frames to the lowerdevice.
>
> Unfortunately not. This commit has a side effect that it in fact
> disables the multiqueue macvtap transmission. Since all macvtap queues
> will contend on a single qdisc lock.
>
They will only contend on a single qdisc lock if the lower device has
1 queue. Perhaps defaulting the L2 forwarding devices to 1queue was a
mistake. But the same issue arises when running macvtap over a
non-multiqueue nic. Or even if you have a multiqueue device and create
many more macvtap queues than the lower device has queues.
Shouldn't the macvtap configuration take into account the lowest level
devices queues? How does using the L2 forwarding device change the
contention issues? Without the L2 forwarding LLTX is enabled but the
qdisc lock, etc is still acquired on the device below the macvlan.
The ixgbe driver as it is currently written can be configured for up to
4 queues by setting numtxqueues when the device is created. I assume
when creating macvtap queues the user needs to account for the number
of queues supported by the lower device.
> For L2 forwarding offload itself, more issues need to be addressed for
> multiqueue macvtap:
>
> - ndo_dfwd_add_station() can only create queues per device at ndo_open,
> but multiqueue macvtap allows user to create and destroy queues at their
> will and at any time.
same argument as above, isn't this the same when running macvtap without
the l2 offloads over a real device? I expect you hit the same contention
points when running over a real device.
> - it looks that ixgbe has a upper limit of 4 queues per station, but
> macvtap currently allows up to 16 queues per device.
>
The 4 limit was to simplify the code because the queue mapping in the
driver gets complicated if it is greater than 4. We can probably
increase this latter. But sorry reiterating how is this different than
a macvtap on a real device that supports a max of 4 queues?
> So more works need to be done and unless those above 3 issues were
> addressed, this patch is really needed to make sure macvtap works.
>
Agreed there is a lot more work here to improve things I'm just not
sure we need to disable this now. Also note its the l2 forwarding
should be disabled by default so a user would have to enable the
feature flag.
Thanks,
John
--
John Fastabend Intel Corporation
^ permalink raw reply
* [PATCH net-next v2 1/4] net: allow > 0 order atomic page alloc in skb_page_frag_refill
From: Michael Dalton @ 2014-01-07 5:25 UTC (permalink / raw)
To: David S. Miller
Cc: Michael Dalton, Michael S. Tsirkin, netdev, virtualization,
Eric Dumazet
skb_page_frag_refill currently permits only order-0 page allocs
unless GFP_WAIT is used. Change skb_page_frag_refill to attempt
higher-order page allocations whether or not GFP_WAIT is used. If
memory cannot be allocated, the allocator will fall back to
successively smaller page allocs (down to order-0 page allocs).
This change brings skb_page_frag_refill in line with the existing
page allocation strategy employed by netdev_alloc_frag, which attempts
higher-order page allocations whether or not GFP_WAIT is set, falling
back to successively lower-order page allocations on failure. Part
of migration of virtio-net to per-receive queue page frag allocators.
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Michael Dalton <mwdalton@google.com>
---
net/core/sock.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/net/core/sock.c b/net/core/sock.c
index 5393b4b..a0d522a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1865,9 +1865,7 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio)
put_page(pfrag->page);
}
- /* We restrict high order allocations to users that can afford to wait */
- order = (prio & __GFP_WAIT) ? SKB_FRAG_PAGE_ORDER : 0;
-
+ order = SKB_FRAG_PAGE_ORDER;
do {
gfp_t gfp = prio;
--
1.8.5.1
^ permalink raw reply related
* [PATCH net-next v2 2/4] virtio-net: use per-receive queue page frag alloc for mergeable bufs
From: Michael Dalton @ 2014-01-07 5:25 UTC (permalink / raw)
To: David S. Miller
Cc: Michael Dalton, Michael S. Tsirkin, netdev, virtualization,
Eric Dumazet
In-Reply-To: <1389072355-20666-1-git-send-email-mwdalton@google.com>
The virtio-net driver currently uses netdev_alloc_frag() for GFP_ATOMIC
mergeable rx buffer allocations. This commit migrates virtio-net to use
per-receive queue page frags for GFP_ATOMIC allocation. This change unifies
mergeable rx buffer memory allocation, which now will use skb_refill_frag()
for both atomic and GFP-WAIT buffer allocations.
To address fragmentation concerns, if after buffer allocation there
is too little space left in the page frag to allocate a subsequent
buffer, the remaining space is added to the current allocated buffer
so that the remaining space can be used to store packet data.
Signed-off-by: Michael Dalton <mwdalton@google.com>
---
v2: Use GFP_COLD for RX buffer allocations (as in netdev_alloc_frag()).
Remove per-netdev GFP_KERNEL page_frag allocator.
drivers/net/virtio_net.c | 69 ++++++++++++++++++++++++------------------------
1 file changed, 35 insertions(+), 34 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index c51a988..526dfd8 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -78,6 +78,9 @@ struct receive_queue {
/* Chain pages by the private ptr. */
struct page *pages;
+ /* Page frag for packet buffer allocation. */
+ struct page_frag alloc_frag;
+
/* RX: fragments + linear part + virtio header */
struct scatterlist sg[MAX_SKB_FRAGS + 2];
@@ -126,11 +129,6 @@ struct virtnet_info {
/* Lock for config space updates */
struct mutex config_lock;
- /* Page_frag for GFP_KERNEL packet buffer allocation when we run
- * low on memory.
- */
- struct page_frag alloc_frag;
-
/* Does the affinity hint is set for virtqueues? */
bool affinity_hint_set;
@@ -336,8 +334,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
int num_buf = hdr->mhdr.num_buffers;
struct page *page = virt_to_head_page(buf);
int offset = buf - page_address(page);
- struct sk_buff *head_skb = page_to_skb(rq, page, offset, len,
- MERGE_BUFFER_LEN);
+ unsigned int truesize = max_t(unsigned int, len, MERGE_BUFFER_LEN);
+ struct sk_buff *head_skb = page_to_skb(rq, page, offset, len, truesize);
struct sk_buff *curr_skb = head_skb;
if (unlikely(!curr_skb))
@@ -353,11 +351,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
dev->stats.rx_length_errors++;
goto err_buf;
}
- if (unlikely(len > MERGE_BUFFER_LEN)) {
- pr_debug("%s: rx error: merge buffer too long\n",
- dev->name);
- len = MERGE_BUFFER_LEN;
- }
page = virt_to_head_page(buf);
--rq->num;
@@ -376,19 +369,20 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
head_skb->truesize += nskb->truesize;
num_skb_frags = 0;
}
+ truesize = max_t(unsigned int, len, MERGE_BUFFER_LEN);
if (curr_skb != head_skb) {
head_skb->data_len += len;
head_skb->len += len;
- head_skb->truesize += MERGE_BUFFER_LEN;
+ head_skb->truesize += truesize;
}
offset = buf - page_address(page);
if (skb_can_coalesce(curr_skb, num_skb_frags, page, offset)) {
put_page(page);
skb_coalesce_rx_frag(curr_skb, num_skb_frags - 1,
- len, MERGE_BUFFER_LEN);
+ len, truesize);
} else {
skb_add_rx_frag(curr_skb, num_skb_frags, page,
- offset, len, MERGE_BUFFER_LEN);
+ offset, len, truesize);
}
}
@@ -578,25 +572,24 @@ static int add_recvbuf_big(struct receive_queue *rq, gfp_t gfp)
static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
{
- struct virtnet_info *vi = rq->vq->vdev->priv;
- char *buf = NULL;
+ struct page_frag *alloc_frag = &rq->alloc_frag;
+ char *buf;
int err;
+ unsigned int len, hole;
- if (gfp & __GFP_WAIT) {
- if (skb_page_frag_refill(MERGE_BUFFER_LEN, &vi->alloc_frag,
- gfp)) {
- buf = (char *)page_address(vi->alloc_frag.page) +
- vi->alloc_frag.offset;
- get_page(vi->alloc_frag.page);
- vi->alloc_frag.offset += MERGE_BUFFER_LEN;
- }
- } else {
- buf = netdev_alloc_frag(MERGE_BUFFER_LEN);
- }
- if (!buf)
+ if (unlikely(!skb_page_frag_refill(MERGE_BUFFER_LEN, alloc_frag, gfp)))
return -ENOMEM;
+ buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
+ get_page(alloc_frag->page);
+ len = MERGE_BUFFER_LEN;
+ alloc_frag->offset += len;
+ hole = alloc_frag->size - alloc_frag->offset;
+ if (hole < MERGE_BUFFER_LEN) {
+ len += hole;
+ alloc_frag->offset += hole;
+ }
- sg_init_one(rq->sg, buf, MERGE_BUFFER_LEN);
+ sg_init_one(rq->sg, buf, len);
err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, buf, gfp);
if (err < 0)
put_page(virt_to_head_page(buf));
@@ -617,6 +610,7 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
int err;
bool oom;
+ gfp |= __GFP_COLD;
do {
if (vi->mergeable_rx_bufs)
err = add_recvbuf_mergeable(rq, gfp);
@@ -1377,6 +1371,14 @@ static void free_receive_bufs(struct virtnet_info *vi)
}
}
+static void free_receive_page_frags(struct virtnet_info *vi)
+{
+ int i;
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ if (vi->rq[i].alloc_frag.page)
+ put_page(vi->rq[i].alloc_frag.page);
+}
+
static void free_unused_bufs(struct virtnet_info *vi)
{
void *buf;
@@ -1705,9 +1707,8 @@ free_recv_bufs:
unregister_netdev(dev);
free_vqs:
cancel_delayed_work_sync(&vi->refill);
+ free_receive_page_frags(vi);
virtnet_del_vqs(vi);
- if (vi->alloc_frag.page)
- put_page(vi->alloc_frag.page);
free_stats:
free_percpu(vi->stats);
free:
@@ -1724,6 +1725,8 @@ static void remove_vq_common(struct virtnet_info *vi)
free_receive_bufs(vi);
+ free_receive_page_frags(vi);
+
virtnet_del_vqs(vi);
}
@@ -1741,8 +1744,6 @@ static void virtnet_remove(struct virtio_device *vdev)
unregister_netdev(vi->dev);
remove_vq_common(vi);
- if (vi->alloc_frag.page)
- put_page(vi->alloc_frag.page);
flush_work(&vi->config_work);
--
1.8.5.1
^ permalink raw reply related
* [PATCH net-next v2 3/4] virtio-net: auto-tune mergeable rx buffer size for improved performance
From: Michael Dalton @ 2014-01-07 5:25 UTC (permalink / raw)
To: David S. Miller
Cc: Michael Dalton, Michael S. Tsirkin, netdev, virtualization,
Eric Dumazet
In-Reply-To: <1389072355-20666-1-git-send-email-mwdalton@google.com>
Commit 2613af0ed18a ("virtio_net: migrate mergeable rx buffers to page frag
allocators") changed the mergeable receive buffer size from PAGE_SIZE to
MTU-size, introducing a single-stream regression for benchmarks with large
average packet size. There is no single optimal buffer size for all
workloads. For workloads with packet size <= MTU bytes, MTU + virtio-net
header-sized buffers are preferred as larger buffers reduce the TCP window
due to SKB truesize. However, single-stream workloads with large average
packet sizes have higher throughput if larger (e.g., PAGE_SIZE) buffers
are used.
This commit auto-tunes the mergeable receiver buffer packet size by
choosing the packet buffer size based on an EWMA of the recent packet
sizes for the receive queue. Packet buffer sizes range from MTU_SIZE +
virtio-net header len to PAGE_SIZE. This improves throughput for
large packet workloads, as any workload with average packet size >=
PAGE_SIZE will use PAGE_SIZE buffers.
These optimizations interact positively with recent commit
ba275241030c ("virtio-net: coalesce rx frags when possible during rx"),
which coalesces adjacent RX SKB fragments in virtio_net. The coalescing
optimizations benefit buffers of any size.
Benchmarks taken from an average of 5 netperf 30-second TCP_STREAM runs
between two QEMU VMs on a single physical machine. Each VM has two VCPUs
with all offloads & vhost enabled. All VMs and vhost threads run in a
single 4 CPU cgroup cpuset, using cgroups to ensure that other processes
in the system will not be scheduled on the benchmark CPUs. Trunk includes
SKB rx frag coalescing.
net-next w/ virtio_net before 2613af0ed18a (PAGE_SIZE bufs): 14642.85Gb/s
net-next (MTU-size bufs): 13170.01Gb/s
net-next + auto-tune: 14555.94Gb/s
Jason Wang also reported a throughput increase on mlx4 from 22Gb/s
using MTU-sized buffers to about 26Gb/s using auto-tuning.
Signed-off-by: Michael Dalton <mwdalton@google.com>
---
v2: Add per-receive queue metadata ring to track precise truesize for
mergeable receive buffers. Remove all truesize approximation. Never
try to fill a full RX ring (required for metadata ring in v2).
drivers/net/virtio_net.c | 145 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 107 insertions(+), 38 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 526dfd8..f6e1ee0 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -26,6 +26,7 @@
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/cpu.h>
+#include <linux/average.h>
static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
@@ -36,11 +37,15 @@ module_param(gso, bool, 0444);
/* FIXME: MTU in config. */
#define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
-#define MERGE_BUFFER_LEN (ALIGN(GOOD_PACKET_LEN + \
- sizeof(struct virtio_net_hdr_mrg_rxbuf), \
- L1_CACHE_BYTES))
#define GOOD_COPY_LEN 128
+/* Weight used for the RX packet size EWMA. The average packet size is used to
+ * determine the packet buffer size when refilling RX rings. As the entire RX
+ * ring may be refilled at once, the weight is chosen so that the EWMA will be
+ * insensitive to short-term, transient changes in packet size.
+ */
+#define RECEIVE_AVG_WEIGHT 64
+
#define VIRTNET_DRIVER_VERSION "1.0.0"
struct virtnet_stats {
@@ -65,11 +70,30 @@ struct send_queue {
char name[40];
};
+/* Per-packet buffer context for mergeable receive buffers. */
+struct mergeable_receive_buf_ctx {
+ /* Packet buffer base address. */
+ void *buf;
+
+ /* Original size of the packet buffer for use in SKB truesize. Does not
+ * include any padding space used to avoid internal fragmentation.
+ */
+ unsigned int truesize;
+};
+
/* Internal representation of a receive virtqueue */
struct receive_queue {
/* Virtqueue associated with this receive_queue */
struct virtqueue *vq;
+ /* Circular buffer of mergeable rxbuf contexts. */
+ struct mergeable_receive_buf_ctx *mrg_buf_ctx;
+
+ /* Number of elements & head index of mrg_buf_ctx. Size must be
+ * equal to the associated virtqueue's vring size.
+ */
+ unsigned int mrg_buf_ctx_size, mrg_buf_ctx_head;
+
struct napi_struct napi;
/* Number of input buffers, and max we've ever had. */
@@ -78,6 +102,9 @@ struct receive_queue {
/* Chain pages by the private ptr. */
struct page *pages;
+ /* Average packet length for mergeable receive buffers. */
+ struct ewma mrg_avg_pkt_len;
+
/* Page frag for packet buffer allocation. */
struct page_frag alloc_frag;
@@ -327,32 +354,32 @@ err:
static struct sk_buff *receive_mergeable(struct net_device *dev,
struct receive_queue *rq,
- void *buf,
+ struct mergeable_receive_buf_ctx *ctx,
unsigned int len)
{
- struct skb_vnet_hdr *hdr = buf;
+ struct skb_vnet_hdr *hdr = ctx->buf;
int num_buf = hdr->mhdr.num_buffers;
- struct page *page = virt_to_head_page(buf);
- int offset = buf - page_address(page);
- unsigned int truesize = max_t(unsigned int, len, MERGE_BUFFER_LEN);
+ struct page *page = virt_to_head_page(ctx->buf);
+ int offset = ctx->buf - page_address(page);
+ unsigned int truesize = max(len, ctx->truesize);
+
struct sk_buff *head_skb = page_to_skb(rq, page, offset, len, truesize);
struct sk_buff *curr_skb = head_skb;
if (unlikely(!curr_skb))
goto err_skb;
-
while (--num_buf) {
int num_skb_frags;
- buf = virtqueue_get_buf(rq->vq, &len);
- if (unlikely(!buf)) {
+ ctx = virtqueue_get_buf(rq->vq, &len);
+ if (unlikely(!ctx)) {
pr_debug("%s: rx error: %d buffers out of %d missing\n",
dev->name, num_buf, hdr->mhdr.num_buffers);
dev->stats.rx_length_errors++;
goto err_buf;
}
- page = virt_to_head_page(buf);
+ page = virt_to_head_page(ctx->buf);
--rq->num;
num_skb_frags = skb_shinfo(curr_skb)->nr_frags;
@@ -369,13 +396,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
head_skb->truesize += nskb->truesize;
num_skb_frags = 0;
}
- truesize = max_t(unsigned int, len, MERGE_BUFFER_LEN);
+ truesize = max(len, ctx->truesize);
if (curr_skb != head_skb) {
head_skb->data_len += len;
head_skb->len += len;
head_skb->truesize += truesize;
}
- offset = buf - page_address(page);
+ offset = ctx->buf - page_address(page);
if (skb_can_coalesce(curr_skb, num_skb_frags, page, offset)) {
put_page(page);
skb_coalesce_rx_frag(curr_skb, num_skb_frags - 1,
@@ -386,19 +413,20 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
}
}
+ ewma_add(&rq->mrg_avg_pkt_len, head_skb->len);
return head_skb;
err_skb:
put_page(page);
while (--num_buf) {
- buf = virtqueue_get_buf(rq->vq, &len);
- if (unlikely(!buf)) {
+ ctx = virtqueue_get_buf(rq->vq, &len);
+ if (unlikely(!ctx)) {
pr_debug("%s: rx error: %d buffers missing\n",
dev->name, num_buf);
dev->stats.rx_length_errors++;
break;
}
- page = virt_to_head_page(buf);
+ page = virt_to_head_page(ctx->buf);
put_page(page);
--rq->num;
}
@@ -419,12 +447,14 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
pr_debug("%s: short packet %i\n", dev->name, len);
dev->stats.rx_length_errors++;
- if (vi->mergeable_rx_bufs)
- put_page(virt_to_head_page(buf));
- else if (vi->big_packets)
+ if (vi->mergeable_rx_bufs) {
+ struct mergeable_receive_buf_ctx *ctx = buf;
+ put_page(virt_to_head_page(ctx->buf));
+ } else if (vi->big_packets) {
give_pages(rq, buf);
- else
+ } else {
dev_kfree_skb(buf);
+ }
return;
}
@@ -572,29 +602,43 @@ static int add_recvbuf_big(struct receive_queue *rq, gfp_t gfp)
static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
{
+ const unsigned int ring_size = rq->mrg_buf_ctx_size;
+ const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
struct page_frag *alloc_frag = &rq->alloc_frag;
- char *buf;
+ struct mergeable_receive_buf_ctx *ctx;
int err;
unsigned int len, hole;
- if (unlikely(!skb_page_frag_refill(MERGE_BUFFER_LEN, alloc_frag, gfp)))
+ len = hdr_len + clamp_t(unsigned int, ewma_read(&rq->mrg_avg_pkt_len),
+ GOOD_PACKET_LEN, PAGE_SIZE - hdr_len);
+ len = ALIGN(len, L1_CACHE_BYTES);
+ if (unlikely(!skb_page_frag_refill(len, alloc_frag, gfp)))
return -ENOMEM;
- buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
+
+ ctx = &rq->mrg_buf_ctx[rq->mrg_buf_ctx_head];
+ ctx->buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
+ ctx->truesize = len;
get_page(alloc_frag->page);
- len = MERGE_BUFFER_LEN;
alloc_frag->offset += len;
hole = alloc_frag->size - alloc_frag->offset;
- if (hole < MERGE_BUFFER_LEN) {
+ if (hole < len) {
+ /* To avoid internal fragmentation, if there is very likely not
+ * enough space for another buffer, add the remaining space to
+ * the current buffer. This extra space is not included in
+ * ctx->truesize.
+ */
len += hole;
alloc_frag->offset += hole;
}
- sg_init_one(rq->sg, buf, len);
- err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, buf, gfp);
- if (err < 0)
- put_page(virt_to_head_page(buf));
-
- return err;
+ sg_init_one(rq->sg, ctx->buf, len);
+ err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, ctx, gfp);
+ if (err < 0) {
+ put_page(virt_to_head_page(ctx->buf));
+ return err;
+ }
+ rq->mrg_buf_ctx_head = (rq->mrg_buf_ctx_head + 1) & (ring_size - 1);
+ return 0;
}
/*
@@ -610,6 +654,9 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
int err;
bool oom;
+ /* Do not attempt to add a buffer if the RX ring is full. */
+ if (unlikely(!rq->vq->num_free))
+ return true;
gfp |= __GFP_COLD;
do {
if (vi->mergeable_rx_bufs)
@@ -1354,8 +1401,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
{
int i;
- for (i = 0; i < vi->max_queue_pairs; i++)
+ for (i = 0; i < vi->max_queue_pairs; i++) {
netif_napi_del(&vi->rq[i].napi);
+ kfree(vi->rq[i].mrg_buf_ctx);
+ }
kfree(vi->rq);
kfree(vi->sq);
@@ -1394,12 +1443,14 @@ static void free_unused_bufs(struct virtnet_info *vi)
struct virtqueue *vq = vi->rq[i].vq;
while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
- if (vi->mergeable_rx_bufs)
- put_page(virt_to_head_page(buf));
- else if (vi->big_packets)
+ if (vi->mergeable_rx_bufs) {
+ struct mergeable_receive_buf_ctx *ctx = buf;
+ put_page(virt_to_head_page(ctx->buf));
+ } else if (vi->big_packets) {
give_pages(&vi->rq[i], buf);
- else
+ } else {
dev_kfree_skb(buf);
+ }
--vi->rq[i].num;
}
BUG_ON(vi->rq[i].num != 0);
@@ -1509,6 +1560,7 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
napi_weight);
sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg));
+ ewma_init(&vi->rq[i].mrg_avg_pkt_len, 1, RECEIVE_AVG_WEIGHT);
sg_init_table(vi->sq[i].sg, ARRAY_SIZE(vi->sq[i].sg));
}
@@ -1522,7 +1574,8 @@ err_sq:
static int init_vqs(struct virtnet_info *vi)
{
- int ret;
+ struct virtio_device *vdev = vi->vdev;
+ int i, ret;
/* Allocate send & receive queues */
ret = virtnet_alloc_queues(vi);
@@ -1533,12 +1586,28 @@ static int init_vqs(struct virtnet_info *vi)
if (ret)
goto err_free;
+ if (vi->mergeable_rx_bufs) {
+ for (i = 0; i < vi->max_queue_pairs; i++) {
+ struct receive_queue *rq = &vi->rq[i];
+ rq->mrg_buf_ctx_size = virtqueue_get_vring_size(rq->vq);
+ rq->mrg_buf_ctx = kmalloc(sizeof(*rq->mrg_buf_ctx) *
+ rq->mrg_buf_ctx_size,
+ GFP_KERNEL);
+ if (!rq->mrg_buf_ctx) {
+ ret = -ENOMEM;
+ goto err_del_vqs;
+ }
+ }
+ }
+
get_online_cpus();
virtnet_set_affinity(vi);
put_online_cpus();
return 0;
+err_del_vqs:
+ vdev->config->del_vqs(vdev);
err_free:
virtnet_free_queues(vi);
err:
--
1.8.5.1
^ permalink raw reply related
* [PATCH net-next v2 4/4] virtio-net: initial debugfs support, export mergeable rx buffer size
From: Michael Dalton @ 2014-01-07 5:25 UTC (permalink / raw)
To: David S. Miller
Cc: Michael Dalton, Michael S. Tsirkin, netdev, virtualization,
Eric Dumazet
In-Reply-To: <1389072355-20666-1-git-send-email-mwdalton@google.com>
Add initial support for debugfs to virtio-net. Each virtio-net network
device will have a directory under /virtio-net in debugfs. The
per-network device directory will contain one sub-directory per active,
enabled receive queue. If mergeable receive buffers are enabled, each
receive queue directory will contain a read-only file that returns the
current packet buffer size for the receive queue.
Signed-off-by: Michael Dalton <mwdalton@google.com>
---
drivers/net/virtio_net.c | 314 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 296 insertions(+), 18 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index f6e1ee0..5da18d6 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -27,6 +27,9 @@
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/average.h>
+#include <linux/seqlock.h>
+#include <linux/kref.h>
+#include <linux/debugfs.h>
static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
@@ -35,6 +38,9 @@ static bool csum = true, gso = true;
module_param(csum, bool, 0444);
module_param(gso, bool, 0444);
+/* Debugfs root directory for all virtio-net devices. */
+static struct dentry *virtnet_debugfs_root;
+
/* FIXME: MTU in config. */
#define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
#define GOOD_COPY_LEN 128
@@ -102,9 +108,6 @@ struct receive_queue {
/* Chain pages by the private ptr. */
struct page *pages;
- /* Average packet length for mergeable receive buffers. */
- struct ewma mrg_avg_pkt_len;
-
/* Page frag for packet buffer allocation. */
struct page_frag alloc_frag;
@@ -115,6 +118,28 @@ struct receive_queue {
char name[40];
};
+/* Per-receive queue statistics exported via debugfs. */
+struct receive_queue_stats {
+ /* Average packet length of receive queue (for mergeable rx buffers). */
+ struct ewma avg_pkt_len;
+
+ /* Per-receive queue stats debugfs directory. */
+ struct dentry *dbg;
+
+ /* Reference count for the receive queue statistics, needed because
+ * an open debugfs file may outlive the receive queue and netdevice.
+ * Open files will remain in-use until all outstanding file descriptors
+ * are closed, even after the underlying file is unlinked.
+ */
+ struct kref refcount;
+
+ /* Sequence counter to allow debugfs readers to safely access stats.
+ * Assumes a single virtio-net writer, which is enforced by virtio-net
+ * and NAPI.
+ */
+ seqcount_t dbg_seq;
+};
+
struct virtnet_info {
struct virtio_device *vdev;
struct virtqueue *cvq;
@@ -147,6 +172,15 @@ struct virtnet_info {
/* Active statistics */
struct virtnet_stats __percpu *stats;
+ /* Per-receive queue statstics exported via debugfs. Stored in
+ * virtnet_info to survive freeze/restore -- a task may have a per-rq
+ * debugfs file open at the time of freeze.
+ */
+ struct receive_queue_stats **rq_stats;
+
+ /* Per-netdevice debugfs directory. */
+ struct dentry *dbg_dev_root;
+
/* Work struct for refilling if we run low on memory. */
struct delayed_work refill;
@@ -358,6 +392,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
unsigned int len)
{
struct skb_vnet_hdr *hdr = ctx->buf;
+ struct virtnet_info *vi = netdev_priv(dev);
+ struct receive_queue_stats *rq_stats = vi->rq_stats[vq2rxq(rq->vq)];
int num_buf = hdr->mhdr.num_buffers;
struct page *page = virt_to_head_page(ctx->buf);
int offset = ctx->buf - page_address(page);
@@ -413,7 +449,9 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
}
}
- ewma_add(&rq->mrg_avg_pkt_len, head_skb->len);
+ write_seqcount_begin(&rq_stats->dbg_seq);
+ ewma_add(&rq_stats->avg_pkt_len, head_skb->len);
+ write_seqcount_end(&rq_stats->dbg_seq);
return head_skb;
err_skb:
@@ -600,18 +638,30 @@ static int add_recvbuf_big(struct receive_queue *rq, gfp_t gfp)
return err;
}
+static unsigned int get_mergeable_buf_len(struct ewma *avg_pkt_len)
+{
+ const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ unsigned int len;
+
+ len = hdr_len + clamp_t(unsigned int, ewma_read(avg_pkt_len),
+ GOOD_PACKET_LEN, PAGE_SIZE - hdr_len);
+ return ALIGN(len, L1_CACHE_BYTES);
+}
+
static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
{
const unsigned int ring_size = rq->mrg_buf_ctx_size;
- const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
struct page_frag *alloc_frag = &rq->alloc_frag;
+ struct virtnet_info *vi = rq->vq->vdev->priv;
struct mergeable_receive_buf_ctx *ctx;
int err;
unsigned int len, hole;
- len = hdr_len + clamp_t(unsigned int, ewma_read(&rq->mrg_avg_pkt_len),
- GOOD_PACKET_LEN, PAGE_SIZE - hdr_len);
- len = ALIGN(len, L1_CACHE_BYTES);
+ /* avg_pkt_len is written only in NAPI rx softirq context. We may
+ * read avg_pkt_len without using the dbg_seq seqcount, as this code
+ * is called only in NAPI rx softirq context or when NAPI is disabled.
+ */
+ len = get_mergeable_buf_len(&vi->rq_stats[vq2rxq(rq->vq)]->avg_pkt_len);
if (unlikely(!skb_page_frag_refill(len, alloc_frag, gfp)))
return -ENOMEM;
@@ -1274,13 +1324,101 @@ static void virtnet_get_drvinfo(struct net_device *dev,
}
+static ssize_t mergeable_rx_buffer_size_read(struct file *file,
+ char __user *userbuf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct receive_queue_stats *rq_stats = file->private_data;
+ char buf[32];
+ struct ewma avg;
+ unsigned int start, len;
+
+ /* Don't allow partial reads. */
+ if (*ppos)
+ return 0;
+ do {
+ start = read_seqcount_begin(&rq_stats->dbg_seq);
+ avg = rq_stats->avg_pkt_len;
+ } while (read_seqcount_retry(&rq_stats->dbg_seq, start));
+ len = scnprintf(buf, sizeof(buf), "%u\n", get_mergeable_buf_len(&avg));
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+void receive_queue_stats_free(struct kref *ref)
+{
+ struct receive_queue_stats *rq_stats;
+
+ rq_stats = container_of(ref, struct receive_queue_stats, refcount);
+ kfree(rq_stats);
+}
+
+static int receive_queue_stats_debugfs_open(struct inode *inode,
+ struct file *file)
+{
+ struct receive_queue_stats *rq_stats = inode->i_private;
+ kref_get(&rq_stats->refcount);
+ file->private_data = rq_stats;
+ return 0;
+}
+
+static int receive_queue_stats_debugfs_release(struct inode *inode,
+ struct file *file)
+{
+ struct receive_queue_stats *rq_stats = inode->i_private;
+ kref_put(&rq_stats->refcount, receive_queue_stats_free);
+ file->private_data = NULL;
+ return 0;
+}
+
+static const struct file_operations mergeable_rx_buffer_size_fops = {
+ .owner = THIS_MODULE,
+ .open = receive_queue_stats_debugfs_open,
+ .read = mergeable_rx_buffer_size_read,
+ .llseek = default_llseek,
+ .release = receive_queue_stats_debugfs_release,
+};
+
+static void receive_queue_debugfs_add(struct receive_queue *rq)
+{
+ struct virtnet_info *vi = rq->vq->vdev->priv;
+ unsigned int rq_index = vq2rxq(rq->vq);
+ struct receive_queue_stats *rq_stats = vi->rq_stats[rq_index];
+ struct dentry *dentry;
+ char name[32];
+
+ if (IS_ERR_OR_NULL(vi->dbg_dev_root))
+ return;
+ scnprintf(name, sizeof(name), "rx-%u", rq_index);
+ dentry = debugfs_create_dir(name, vi->dbg_dev_root);
+ if (IS_ERR_OR_NULL(dentry)) {
+ pr_warn("%s: could not create %s rx queue debugfs dir\n",
+ vi->dev->name, name);
+ return;
+ }
+ rq_stats->dbg = dentry;
+ if (vi->mergeable_rx_bufs)
+ debugfs_create_file("mergeable_rx_buffer_size", S_IRUSR,
+ rq_stats->dbg, rq_stats,
+ &mergeable_rx_buffer_size_fops);
+}
+
+static void receive_queue_debugfs_del(struct receive_queue *rq)
+{
+ struct virtnet_info *vi = rq->vq->vdev->priv;
+ struct receive_queue_stats *rq_stats = vi->rq_stats[vq2rxq(rq->vq)];
+ debugfs_remove_recursive(rq_stats->dbg);
+ rq_stats->dbg = NULL;
+}
+
/* TODO: Eliminate OOO packets during switching */
static int virtnet_set_channels(struct net_device *dev,
struct ethtool_channels *channels)
{
struct virtnet_info *vi = netdev_priv(dev);
- u16 queue_pairs = channels->combined_count;
- int err;
+ u16 new_queue_pairs = channels->combined_count;
+ u16 old_queue_pairs = vi->curr_queue_pairs;
+ int err, i;
/* We don't support separate rx/tx channels.
* We don't allow setting 'other' channels.
@@ -1288,14 +1426,21 @@ static int virtnet_set_channels(struct net_device *dev,
if (channels->rx_count || channels->tx_count || channels->other_count)
return -EINVAL;
- if (queue_pairs > vi->max_queue_pairs)
+ if (new_queue_pairs > vi->max_queue_pairs)
return -EINVAL;
get_online_cpus();
- err = virtnet_set_queues(vi, queue_pairs);
+ err = virtnet_set_queues(vi, new_queue_pairs);
if (!err) {
- netif_set_real_num_tx_queues(dev, queue_pairs);
- netif_set_real_num_rx_queues(dev, queue_pairs);
+ if (new_queue_pairs < old_queue_pairs) {
+ for (i = new_queue_pairs; i < old_queue_pairs; i++)
+ receive_queue_debugfs_del(&vi->rq[i]);
+ } else {
+ for (i = old_queue_pairs; i < new_queue_pairs; i++)
+ receive_queue_debugfs_add(&vi->rq[i]);
+ }
+ netif_set_real_num_tx_queues(dev, new_queue_pairs);
+ netif_set_real_num_rx_queues(dev, new_queue_pairs);
virtnet_set_affinity(vi);
}
@@ -1336,7 +1481,44 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+/* Must be called only after the net_device name has been expanded. */
+static void virtnet_debugfs_init(struct virtnet_info *vi)
+{
+ int i;
+
+ if (IS_ERR_OR_NULL(virtnet_debugfs_root))
+ return;
+ vi->dbg_dev_root = debugfs_create_dir(vi->dev->name,
+ virtnet_debugfs_root);
+ if (IS_ERR_OR_NULL(vi->dbg_dev_root)) {
+ pr_warn("%s: could not create netdevice debugfs dir\n",
+ vi->dev->name);
+ return;
+ }
+ for (i = 0; i < vi->curr_queue_pairs; i++)
+ receive_queue_debugfs_add(&vi->rq[i]);
+}
+
+static void virtnet_debugfs_cleanup(struct virtnet_info *vi)
+{
+ int i;
+
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ receive_queue_debugfs_del(&vi->rq[i]);
+ debugfs_remove_recursive(vi->dbg_dev_root);
+ vi->dbg_dev_root = NULL;
+}
+
+static int virtnet_init(struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+
+ virtnet_debugfs_init(vi);
+ return 0;
+}
+
static const struct net_device_ops virtnet_netdev = {
+ .ndo_init = virtnet_init,
.ndo_open = virtnet_open,
.ndo_stop = virtnet_close,
.ndo_start_xmit = start_xmit,
@@ -1560,7 +1742,6 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
napi_weight);
sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg));
- ewma_init(&vi->rq[i].mrg_avg_pkt_len, 1, RECEIVE_AVG_WEIGHT);
sg_init_table(vi->sq[i].sg, ARRAY_SIZE(vi->sq[i].sg));
}
@@ -1614,6 +1795,39 @@ err:
return ret;
}
+static int virtnet_rename(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct virtnet_info *vi;
+
+ if (event != NETDEV_CHANGENAME || dev->netdev_ops != &virtnet_netdev)
+ return NOTIFY_DONE;
+ vi = netdev_priv(dev);
+ if (IS_ERR_OR_NULL(vi->dbg_dev_root))
+ return NOTIFY_DONE;
+ if (IS_ERR_OR_NULL(debugfs_rename(virtnet_debugfs_root,
+ vi->dbg_dev_root,
+ virtnet_debugfs_root, dev->name))) {
+ pr_warn("%s: failed debugfs rename, removing old debugfs dir\n",
+ dev->name);
+ virtnet_debugfs_cleanup(vi);
+ }
+ return NOTIFY_DONE;
+}
+
+static void virtnet_release_receive_queue_stats(struct virtnet_info *vi)
+{
+ int i;
+
+ for (i = 0; i < vi->max_queue_pairs; i++) {
+ struct receive_queue_stats *rq_stats = vi->rq_stats[i];
+ if (rq_stats)
+ kref_put(&rq_stats->refcount, receive_queue_stats_free);
+ }
+ kfree(vi->rq_stats);
+}
+
static int virtnet_probe(struct virtio_device *vdev)
{
int i, err;
@@ -1723,10 +1937,24 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->curr_queue_pairs = 1;
vi->max_queue_pairs = max_queue_pairs;
+ vi->rq_stats = kzalloc(sizeof(vi->rq_stats[0]) *
+ vi->max_queue_pairs, GFP_KERNEL);
+ if (!vi->rq_stats)
+ goto free_dev_stats;
+ for (i = 0; i < vi->max_queue_pairs; i++) {
+ vi->rq_stats[i] = kzalloc(sizeof(*vi->rq_stats[0]), GFP_KERNEL);
+ if (!vi->rq_stats[i])
+ goto free_rq_stats;
+ seqcount_init(&vi->rq_stats[i]->dbg_seq);
+ kref_init(&vi->rq_stats[i]->refcount);
+ ewma_init(&vi->rq_stats[i]->avg_pkt_len, 1,
+ RECEIVE_AVG_WEIGHT);
+ }
+
/* Allocate/initialize the rx/tx queues, and invoke find_vqs */
err = init_vqs(vi);
if (err)
- goto free_stats;
+ goto free_rq_stats;
netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
@@ -1777,8 +2005,11 @@ free_recv_bufs:
free_vqs:
cancel_delayed_work_sync(&vi->refill);
free_receive_page_frags(vi);
+ virtnet_debugfs_cleanup(vi);
virtnet_del_vqs(vi);
-free_stats:
+free_rq_stats:
+ virtnet_release_receive_queue_stats(vi);
+free_dev_stats:
free_percpu(vi->stats);
free:
free_netdev(dev);
@@ -1812,10 +2043,12 @@ static void virtnet_remove(struct virtio_device *vdev)
unregister_netdev(vi->dev);
+ virtnet_debugfs_cleanup(vi);
remove_vq_common(vi);
flush_work(&vi->config_work);
+ virtnet_release_receive_queue_stats(vi);
free_percpu(vi->stats);
free_netdev(vi->dev);
}
@@ -1884,6 +2117,19 @@ static int virtnet_restore(struct virtio_device *vdev)
}
#endif
+static void virtnet_register_debugfs(void)
+{
+ virtnet_debugfs_root = debugfs_create_dir("virtio-net", NULL);
+ if (IS_ERR_OR_NULL(virtnet_debugfs_root))
+ pr_warn("Could not create virtio-net debugfs dir\n");
+}
+
+static void virtnet_unregister_debugfs(void)
+{
+ debugfs_remove_recursive(virtnet_debugfs_root);
+ virtnet_debugfs_root = NULL;
+}
+
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
{ 0 },
@@ -1917,7 +2163,39 @@ static struct virtio_driver virtio_net_driver = {
#endif
};
-module_virtio_driver(virtio_net_driver);
+static struct notifier_block virtnet_rename_notifier = {
+ .notifier_call = virtnet_rename,
+};
+
+static int __init init(void)
+{
+ int err;
+
+ virtnet_register_debugfs();
+ err = register_netdevice_notifier(&virtnet_rename_notifier);
+ if (err)
+ goto free_debugfs;
+ err = register_virtio_driver(&virtio_net_driver);
+ if (err)
+ goto free_notifier;
+ return 0;
+
+free_notifier:
+ unregister_netdevice_notifier(&virtnet_rename_notifier);
+free_debugfs:
+ virtnet_unregister_debugfs();
+ return err;
+}
+
+static void __exit cleanup(void)
+{
+ unregister_virtio_driver(&virtio_net_driver);
+ unregister_netdevice_notifier(&virtnet_rename_notifier);
+ virtnet_unregister_debugfs();
+}
+
+module_init(init);
+module_exit(cleanup);
MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_DESCRIPTION("Virtio network driver");
--
1.8.5.1
^ permalink raw reply related
* Re: [PATCH net] r8152: correct some messages
From: David Miller @ 2014-01-07 5:45 UTC (permalink / raw)
To: hayeswang; +Cc: netdev, nic_swsd, linux-kernel, linux-usb
In-Reply-To: <1389064702-1173-1-git-send-email-hayeswang@realtek.com>
From: Hayes Wang <hayeswang@realtek.com>
Date: Tue, 7 Jan 2014 11:18:22 +0800
> - Replace pr_warn_ratelimited() with net_ratelimit() and netdev_warn().
> - Adjust the algnment of some messages.
> - Remove the peroid.
> - Fix some messages don't have terminating newline.
>
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
I only want major bug fixes in 'net' at this time so I've applied
this to 'net-next'.
Thanks.
^ permalink raw reply
* Re: [PATCH 5/6] [v4] phylib: Support attaching to generic 10g driver
From: David Miller @ 2014-01-07 5:56 UTC (permalink / raw)
To: shh.xie
Cc: jg1.han, mugunthanvnm, f.fainelli, netdev, linux-kernel,
Shaohui.Xie, afleming
In-Reply-To: <1389060865-7143-1-git-send-email-shh.xie@gmail.com>
From: <shh.xie@gmail.com>
Date: Tue, 7 Jan 2014 10:14:25 +0800
> -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
> +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
> u32 flags, phy_interface_t interface)
Since you are changing where the open parenthesis is, you must reindent
the arguments on the second line so that they start exactly at the
first column after that openning parenthesis.
^ permalink raw reply
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