* Re: [PATCH] e1000e: MSI interrupt test failed, using legacy interrupt
From: Ben Hutchings @ 2012-04-27 1:40 UTC (permalink / raw)
To: prasanna.panchamukhi
Cc: netdev, bruce.w.allan, jesse.brandeburg, e1000-devel, gospo,
sassmann
In-Reply-To: <1335485150-2765-1-git-send-email-prasanna.panchamukhi@riverbed.com>
On Thu, 2012-04-26 at 17:05 -0700, prasanna.panchamukhi@riverbed.com
wrote:
> From: Prasanna S. Panchamukhi <ppanchamukhi@riverbed.com>
>
> Following logs where seen on Systems with multiple NICs & ports,
> while using MSI interrupts as shown below:
[...]
> This patch changes the IRQ tests to use polling loops starting with a
> delay of 1 tick and doubling that if necessary up to a maximum total
> delay of approximately 1 second.
[...]
I don't think you entirely understood my point. This exponential
back-off was the best I could come up with for a self-test
(ethtool -t) where we have to answer the question 'are interrupts
working' in a reasonable time, and the user can decide for themselves
whether this was a false negative.
If you want a definite answer in order to make an automatic decision
about interrupt modes, there really is no valid time limit. I think the
proper way to do interrupt mode selection in an in-tree driver is to
rely on no-MSI quirks for chipsets and devices in the PCI core.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
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
* [PATCH v2 4/5] staging: octeon_ethernet: Convert to use device tree.
From: David Daney @ 2012-04-27 1:20 UTC (permalink / raw)
To: linux-mips, ralf, devicetree-discuss, Grant Likely, Rob Herring
Cc: linux-kernel, David Daney, netdev, Greg Kroah-Hartman,
David S. Miller
In-Reply-To: <1335489630-27017-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
Get MAC address and PHY connection from the device tree. The driver
is converted to a platform driver.
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: David Daney <david.daney@cavium.com>
Cc: netdev@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: David S. Miller <davem@davemloft.net>
---
drivers/staging/octeon/ethernet-mdio.c | 28 +++---
drivers/staging/octeon/ethernet.c | 153 +++++++++++++++++++-----------
drivers/staging/octeon/octeon-ethernet.h | 3 +
3 files changed, 117 insertions(+), 67 deletions(-)
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index e31949c..f15b31b 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -28,6 +28,7 @@
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/ratelimit.h>
+#include <linux/of_mdio.h>
#include <net/dst.h>
@@ -161,22 +162,23 @@ static void cvm_oct_adjust_link(struct net_device *dev)
int cvm_oct_phy_setup_device(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
+ struct device_node *phy_node;
- int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
- if (phy_addr != -1) {
- char phy_id[MII_BUS_ID_SIZE + 3];
+ if (!priv->of_node)
+ return 0;
- snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", phy_addr);
+ phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
+ if (!phy_node)
+ return 0;
- priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
- PHY_INTERFACE_MODE_GMII);
+ priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
+ PHY_INTERFACE_MODE_GMII);
+
+ if (priv->phydev == NULL)
+ return -ENODEV;
+
+ priv->last_link = 0;
+ phy_start_aneg(priv->phydev);
- if (IS_ERR(priv->phydev)) {
- priv->phydev = NULL;
- return -1;
- }
- priv->last_link = 0;
- phy_start_aneg(priv->phydev);
- }
return 0;
}
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 9112cd8..7df97fc 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -24,6 +24,7 @@
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
**********************************************************************/
+#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -31,6 +32,7 @@
#include <linux/etherdevice.h>
#include <linux/phy.h>
#include <linux/slab.h>
+#include <linux/of_net.h>
#include <net/dst.h>
@@ -112,15 +114,6 @@ int rx_napi_weight = 32;
module_param(rx_napi_weight, int, 0444);
MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");
-/*
- * The offset from mac_addr_base that should be used for the next port
- * that is configured. By convention, if any mgmt ports exist on the
- * chip, they get the first mac addresses, The ports controlled by
- * this driver are numbered sequencially following any mgmt addresses
- * that may exist.
- */
-static unsigned int cvm_oct_mac_addr_offset;
-
/**
* cvm_oct_poll_queue - Workqueue for polling operations.
*/
@@ -175,7 +168,7 @@ static void cvm_oct_periodic_worker(struct work_struct *work)
queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ);
}
-static __init void cvm_oct_configure_common_hw(void)
+static __devinit void cvm_oct_configure_common_hw(void)
{
/* Setup the FPA */
cvmx_fpa_enable();
@@ -395,23 +388,21 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
* Returns Zero on success
*/
-static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
+static int cvm_oct_set_mac_filter(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
union cvmx_gmxx_prtx_cfg gmx_cfg;
int interface = INTERFACE(priv->port);
int index = INDEX(priv->port);
- memcpy(dev->dev_addr, addr + 2, 6);
-
if ((interface < 2)
&& (cvmx_helper_interface_get_mode(interface) !=
CVMX_HELPER_INTERFACE_MODE_SPI)) {
int i;
- uint8_t *ptr = addr;
+ uint8_t *ptr = dev->dev_addr;
uint64_t mac = 0;
for (i = 0; i < 6; i++)
- mac = (mac << 8) | (uint64_t) (ptr[i + 2]);
+ mac = (mac << 8) | (uint64_t)ptr[i];
gmx_cfg.u64 =
cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
@@ -420,17 +411,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
- ptr[2]);
+ ptr[0]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
- ptr[3]);
+ ptr[1]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
- ptr[4]);
+ ptr[2]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
- ptr[5]);
+ ptr[3]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
- ptr[6]);
+ ptr[4]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
- ptr[7]);
+ ptr[5]);
cvm_oct_common_set_multicast_list(dev);
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
gmx_cfg.u64);
@@ -438,6 +429,15 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
return 0;
}
+static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
+{
+ int r = eth_mac_addr(dev, addr);
+
+ if (r)
+ return r;
+ return cvm_oct_set_mac_filter(dev);
+}
+
/**
* cvm_oct_common_init - per network device initialization
* @dev: Device to initialize
@@ -447,26 +447,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
int cvm_oct_common_init(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
- struct sockaddr sa;
- u64 mac = ((u64)(octeon_bootinfo->mac_addr_base[0] & 0xff) << 40) |
- ((u64)(octeon_bootinfo->mac_addr_base[1] & 0xff) << 32) |
- ((u64)(octeon_bootinfo->mac_addr_base[2] & 0xff) << 24) |
- ((u64)(octeon_bootinfo->mac_addr_base[3] & 0xff) << 16) |
- ((u64)(octeon_bootinfo->mac_addr_base[4] & 0xff) << 8) |
- (u64)(octeon_bootinfo->mac_addr_base[5] & 0xff);
-
- mac += cvm_oct_mac_addr_offset;
- sa.sa_data[0] = (mac >> 40) & 0xff;
- sa.sa_data[1] = (mac >> 32) & 0xff;
- sa.sa_data[2] = (mac >> 24) & 0xff;
- sa.sa_data[3] = (mac >> 16) & 0xff;
- sa.sa_data[4] = (mac >> 8) & 0xff;
- sa.sa_data[5] = mac & 0xff;
-
- if (cvm_oct_mac_addr_offset >= octeon_bootinfo->mac_addr_count)
- printk(KERN_DEBUG "%s: Using MAC outside of the assigned range:"
- " %pM\n", dev->name, sa.sa_data);
- cvm_oct_mac_addr_offset++;
+ const u8 *mac = NULL;
+
+ if (priv->of_node)
+ mac = of_get_mac_address(priv->of_node);
+
+ if (mac && is_valid_ether_addr(mac)) {
+ memcpy(dev->dev_addr, mac, ETH_ALEN);
+ dev->addr_assign_type &= ~NET_ADDR_RANDOM;
+ } else {
+ eth_hw_addr_random(dev);
+ }
/*
* Force the interface to use the POW send if always_use_pow
@@ -487,7 +478,7 @@ int cvm_oct_common_init(struct net_device *dev)
SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
cvm_oct_phy_setup_device(dev);
- dev->netdev_ops->ndo_set_mac_address(dev, &sa);
+ cvm_oct_set_mac_filter(dev);
dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
/*
@@ -594,22 +585,55 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {
extern void octeon_mdiobus_force_mod_depencency(void);
-static int __init cvm_oct_init_module(void)
+static struct device_node * __devinit cvm_oct_of_get_child(const struct device_node *parent,
+ int reg_val)
+{
+ struct device_node *node = NULL;
+ int size;
+ const __be32 *addr;
+
+ for (;;) {
+ node = of_get_next_child(parent, node);
+ if (!node)
+ break;
+ addr = of_get_property(node, "reg", &size);
+ if (addr && (be32_to_cpu(*addr) == reg_val))
+ break;
+ }
+ return node;
+}
+
+static struct device_node * __devinit cvm_oct_node_for_port(struct device_node *pip,
+ int interface, int port)
+{
+ struct device_node *ni, *np;
+
+ ni = cvm_oct_of_get_child(pip, interface);
+ if (!ni)
+ return NULL;
+
+ np = cvm_oct_of_get_child(ni, port);
+ of_node_put(ni);
+
+ return np;
+}
+
+static int __devinit cvm_oct_probe(struct platform_device *pdev)
{
int num_interfaces;
int interface;
int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
int qos;
+ struct device_node *pip;
octeon_mdiobus_force_mod_depencency();
pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);
- if (OCTEON_IS_MODEL(OCTEON_CN52XX))
- cvm_oct_mac_addr_offset = 2; /* First two are the mgmt ports. */
- else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
- cvm_oct_mac_addr_offset = 1; /* First one is the mgmt port. */
- else
- cvm_oct_mac_addr_offset = 0;
+ pip = pdev->dev.of_node;
+ if (!pip) {
+ pr_err("Error: No 'pip' in /aliases\n");
+ return -EINVAL;
+ }
cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet");
if (cvm_oct_poll_queue == NULL) {
@@ -688,10 +712,11 @@ static int __init cvm_oct_init_module(void)
cvmx_helper_interface_get_mode(interface);
int num_ports = cvmx_helper_ports_on_interface(interface);
int port;
+ int port_index;
- for (port = cvmx_helper_get_ipd_port(interface, 0);
+ for (port_index = 0, port = cvmx_helper_get_ipd_port(interface, 0);
port < cvmx_helper_get_ipd_port(interface, num_ports);
- port++) {
+ port_index++, port++) {
struct octeon_ethernet *priv;
struct net_device *dev =
alloc_etherdev(sizeof(struct octeon_ethernet));
@@ -702,6 +727,7 @@ static int __init cvm_oct_init_module(void)
/* Initialize the device private structure. */
priv = netdev_priv(dev);
+ priv->of_node = cvm_oct_node_for_port(pip, interface, port_index);
INIT_DELAYED_WORK(&priv->port_periodic_work,
cvm_oct_periodic_worker);
@@ -786,7 +812,7 @@ static int __init cvm_oct_init_module(void)
return 0;
}
-static void __exit cvm_oct_cleanup_module(void)
+static int __devexit cvm_oct_remove(struct platform_device *pdev)
{
int port;
@@ -834,10 +860,29 @@ static void __exit cvm_oct_cleanup_module(void)
if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
+ return 0;
}
+static struct of_device_id cvm_oct_match[] = {
+ {
+ .compatible = "cavium,octeon-3860-pip",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cvm_oct_match);
+
+static struct platform_driver cvm_oct_driver = {
+ .probe = cvm_oct_probe,
+ .remove = __devexit_p(cvm_oct_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .of_match_table = cvm_oct_match,
+ },
+};
+
+module_platform_driver(cvm_oct_driver);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver.");
-module_init(cvm_oct_init_module);
-module_exit(cvm_oct_cleanup_module);
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
index d581925..9360e22 100644
--- a/drivers/staging/octeon/octeon-ethernet.h
+++ b/drivers/staging/octeon/octeon-ethernet.h
@@ -31,6 +31,8 @@
#ifndef OCTEON_ETHERNET_H
#define OCTEON_ETHERNET_H
+#include <linux/of.h>
+
/**
* This is the definition of the Ethernet driver's private
* driver state stored in netdev_priv(dev).
@@ -59,6 +61,7 @@ struct octeon_ethernet {
void (*poll) (struct net_device *dev);
struct delayed_work port_periodic_work;
struct work_struct port_work; /* may be unused. */
+ struct device_node *of_node;
};
int cvm_oct_free_work(void *work_queue_entry);
--
1.7.2.3
^ permalink raw reply related
* [PATCH v2 3/5] netdev: octeon_mgmt: Convert to use device tree.
From: David Daney @ 2012-04-27 1:20 UTC (permalink / raw)
To: linux-mips, ralf, devicetree-discuss, Grant Likely, Rob Herring
Cc: linux-kernel, David Daney, netdev, David S. Miller
In-Reply-To: <1335489630-27017-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
The device tree will supply the register bank base addresses, make
register addressing relative to those. PHY connection is now
described by the device tree.
The OCTEON_IRQ_MII{0,1} symbols are also removed as they are now
unused and interfere with the irq_domain used for device tree irq
mapping.
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: David Daney <david.daney@cavium.com>
Cc: netdev@vger.kernel.org
Cc: David S. Miller <davem@davemloft.net>
---
arch/mips/cavium-octeon/octeon-irq.c | 2 -
arch/mips/cavium-octeon/octeon-platform.c | 62 ------
drivers/net/ethernet/octeon/octeon_mgmt.c | 312 +++++++++++++++++++----------
3 files changed, 207 insertions(+), 169 deletions(-)
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index c6b0b41..a729728 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -1188,7 +1188,6 @@ static void __init octeon_irq_init_ciu(void)
octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq);
octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq);
- octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII0, 0, 62, chip, handle_level_irq);
octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq);
/* CIU_1 */
@@ -1197,7 +1196,6 @@ static void __init octeon_irq_init_ciu(void)
octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART2, 1, 16, chip, handle_level_irq);
octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq);
- octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq);
gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio");
if (gpio_node) {
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index 66cabc2..0938df1 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -168,68 +168,6 @@ out:
}
device_initcall(octeon_rng_device_init);
-/* Octeon mgmt port Ethernet interface. */
-static int __init octeon_mgmt_device_init(void)
-{
- struct platform_device *pd;
- int ret = 0;
- int port, num_ports;
-
- struct resource mgmt_port_resource = {
- .flags = IORESOURCE_IRQ,
- .start = -1,
- .end = -1
- };
-
- if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
- return 0;
-
- if (OCTEON_IS_MODEL(OCTEON_CN56XX))
- num_ports = 1;
- else
- num_ports = 2;
-
- for (port = 0; port < num_ports; port++) {
- pd = platform_device_alloc("octeon_mgmt", port);
- if (!pd) {
- ret = -ENOMEM;
- goto out;
- }
- /* No DMA restrictions */
- pd->dev.coherent_dma_mask = DMA_BIT_MASK(64);
- pd->dev.dma_mask = &pd->dev.coherent_dma_mask;
-
- switch (port) {
- case 0:
- mgmt_port_resource.start = OCTEON_IRQ_MII0;
- break;
- case 1:
- mgmt_port_resource.start = OCTEON_IRQ_MII1;
- break;
- default:
- BUG();
- }
- mgmt_port_resource.end = mgmt_port_resource.start;
-
- ret = platform_device_add_resources(pd, &mgmt_port_resource, 1);
-
- if (ret)
- goto fail;
-
- ret = platform_device_add(pd);
- if (ret)
- goto fail;
- }
- return ret;
-fail:
- platform_device_put(pd);
-
-out:
- return ret;
-
-}
-device_initcall(octeon_mgmt_device_init);
-
#ifdef CONFIG_USB
static int __init octeon_ehci_device_init(void)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index cd827ff..c42bbb1 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -6,19 +6,21 @@
* Copyright (C) 2009 Cavium Networks
*/
-#include <linux/capability.h>
+#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/capability.h>
#include <linux/interrupt.h>
-#include <linux/platform_device.h>
#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if.h>
+#include <linux/spinlock.h>
#include <linux/if_vlan.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/init.h>
#include <linux/slab.h>
#include <linux/phy.h>
-#include <linux/spinlock.h>
+#include <linux/io.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-mixx-defs.h>
@@ -58,8 +60,56 @@ union mgmt_port_ring_entry {
} s;
};
+#define MIX_ORING1 0x0
+#define MIX_ORING2 0x8
+#define MIX_IRING1 0x10
+#define MIX_IRING2 0x18
+#define MIX_CTL 0x20
+#define MIX_IRHWM 0x28
+#define MIX_IRCNT 0x30
+#define MIX_ORHWM 0x38
+#define MIX_ORCNT 0x40
+#define MIX_ISR 0x48
+#define MIX_INTENA 0x50
+#define MIX_REMCNT 0x58
+#define MIX_BIST 0x78
+
+#define AGL_GMX_PRT_CFG 0x10
+#define AGL_GMX_RX_FRM_CTL 0x18
+#define AGL_GMX_RX_FRM_MAX 0x30
+#define AGL_GMX_RX_JABBER 0x38
+#define AGL_GMX_RX_STATS_CTL 0x50
+
+#define AGL_GMX_RX_STATS_PKTS_DRP 0xb0
+#define AGL_GMX_RX_STATS_OCTS_DRP 0xb8
+#define AGL_GMX_RX_STATS_PKTS_BAD 0xc0
+
+#define AGL_GMX_RX_ADR_CTL 0x100
+#define AGL_GMX_RX_ADR_CAM_EN 0x108
+#define AGL_GMX_RX_ADR_CAM0 0x180
+#define AGL_GMX_RX_ADR_CAM1 0x188
+#define AGL_GMX_RX_ADR_CAM2 0x190
+#define AGL_GMX_RX_ADR_CAM3 0x198
+#define AGL_GMX_RX_ADR_CAM4 0x1a0
+#define AGL_GMX_RX_ADR_CAM5 0x1a8
+
+#define AGL_GMX_TX_STATS_CTL 0x268
+#define AGL_GMX_TX_CTL 0x270
+#define AGL_GMX_TX_STAT0 0x280
+#define AGL_GMX_TX_STAT1 0x288
+#define AGL_GMX_TX_STAT2 0x290
+#define AGL_GMX_TX_STAT3 0x298
+#define AGL_GMX_TX_STAT4 0x2a0
+#define AGL_GMX_TX_STAT5 0x2a8
+#define AGL_GMX_TX_STAT6 0x2b0
+#define AGL_GMX_TX_STAT7 0x2b8
+#define AGL_GMX_TX_STAT8 0x2c0
+#define AGL_GMX_TX_STAT9 0x2c8
+
struct octeon_mgmt {
struct net_device *netdev;
+ u64 mix;
+ u64 agl;
int port;
int irq;
u64 *tx_ring;
@@ -85,31 +135,34 @@ struct octeon_mgmt {
struct napi_struct napi;
struct tasklet_struct tx_clean_tasklet;
struct phy_device *phydev;
+ struct device_node *phy_np;
+ resource_size_t mix_phys;
+ resource_size_t mix_size;
+ resource_size_t agl_phys;
+ resource_size_t agl_size;
};
static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable)
{
- int port = p->port;
union cvmx_mixx_intena mix_intena;
unsigned long flags;
spin_lock_irqsave(&p->lock, flags);
- mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+ mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA);
mix_intena.s.ithena = enable ? 1 : 0;
- cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+ cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64);
spin_unlock_irqrestore(&p->lock, flags);
}
static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable)
{
- int port = p->port;
union cvmx_mixx_intena mix_intena;
unsigned long flags;
spin_lock_irqsave(&p->lock, flags);
- mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+ mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA);
mix_intena.s.othena = enable ? 1 : 0;
- cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+ cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64);
spin_unlock_irqrestore(&p->lock, flags);
}
@@ -146,7 +199,6 @@ static unsigned int ring_size_to_bytes(unsigned int ring_size)
static void octeon_mgmt_rx_fill_ring(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
while (p->rx_current_fill < ring_max_fill(OCTEON_MGMT_RX_RING_SIZE)) {
unsigned int size;
@@ -177,24 +229,23 @@ static void octeon_mgmt_rx_fill_ring(struct net_device *netdev)
(p->rx_next_fill + 1) % OCTEON_MGMT_RX_RING_SIZE;
p->rx_current_fill++;
/* Ring the bell. */
- cvmx_write_csr(CVMX_MIXX_IRING2(port), 1);
+ cvmx_write_csr(p->mix + MIX_IRING2, 1);
}
}
static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
{
- int port = p->port;
union cvmx_mixx_orcnt mix_orcnt;
union mgmt_port_ring_entry re;
struct sk_buff *skb;
int cleaned = 0;
unsigned long flags;
- mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+ mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT);
while (mix_orcnt.s.orcnt) {
spin_lock_irqsave(&p->tx_list.lock, flags);
- mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+ mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT);
if (mix_orcnt.s.orcnt == 0) {
spin_unlock_irqrestore(&p->tx_list.lock, flags);
@@ -214,7 +265,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
mix_orcnt.s.orcnt = 1;
/* Acknowledge to hardware that we have the buffer. */
- cvmx_write_csr(CVMX_MIXX_ORCNT(port), mix_orcnt.u64);
+ cvmx_write_csr(p->mix + MIX_ORCNT, mix_orcnt.u64);
p->tx_current_fill--;
spin_unlock_irqrestore(&p->tx_list.lock, flags);
@@ -224,7 +275,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
dev_kfree_skb_any(skb);
cleaned++;
- mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+ mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT);
}
if (cleaned && netif_queue_stopped(p->netdev))
@@ -241,13 +292,12 @@ static void octeon_mgmt_clean_tx_tasklet(unsigned long arg)
static void octeon_mgmt_update_rx_stats(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
unsigned long flags;
u64 drop, bad;
/* These reads also clear the count registers. */
- drop = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port));
- bad = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port));
+ drop = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP);
+ bad = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD);
if (drop || bad) {
/* Do an atomic update. */
@@ -261,15 +311,14 @@ static void octeon_mgmt_update_rx_stats(struct net_device *netdev)
static void octeon_mgmt_update_tx_stats(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
unsigned long flags;
union cvmx_agl_gmx_txx_stat0 s0;
union cvmx_agl_gmx_txx_stat1 s1;
/* These reads also clear the count registers. */
- s0.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT0(port));
- s1.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT1(port));
+ s0.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT0);
+ s1.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT1);
if (s0.s.xsdef || s0.s.xscol || s1.s.scol || s1.s.mcol) {
/* Do an atomic update. */
@@ -308,7 +357,6 @@ static u64 octeon_mgmt_dequeue_rx_buffer(struct octeon_mgmt *p,
static int octeon_mgmt_receive_one(struct octeon_mgmt *p)
{
- int port = p->port;
struct net_device *netdev = p->netdev;
union cvmx_mixx_ircnt mix_ircnt;
union mgmt_port_ring_entry re;
@@ -381,18 +429,17 @@ done:
/* Tell the hardware we processed a packet. */
mix_ircnt.u64 = 0;
mix_ircnt.s.ircnt = 1;
- cvmx_write_csr(CVMX_MIXX_IRCNT(port), mix_ircnt.u64);
+ cvmx_write_csr(p->mix + MIX_IRCNT, mix_ircnt.u64);
return rc;
}
static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
{
- int port = p->port;
unsigned int work_done = 0;
union cvmx_mixx_ircnt mix_ircnt;
int rc;
- mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+ mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT);
while (work_done < budget && mix_ircnt.s.ircnt) {
rc = octeon_mgmt_receive_one(p);
@@ -400,7 +447,7 @@ static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
work_done++;
/* Check for more packets. */
- mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+ mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT);
}
octeon_mgmt_rx_fill_ring(p->netdev);
@@ -434,16 +481,16 @@ static void octeon_mgmt_reset_hw(struct octeon_mgmt *p)
union cvmx_agl_gmx_bist agl_gmx_bist;
mix_ctl.u64 = 0;
- cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
+ cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
do {
- mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+ mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL);
} while (mix_ctl.s.busy);
mix_ctl.s.reset = 1;
- cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
- cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+ cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
+ cvmx_read_csr(p->mix + MIX_CTL);
cvmx_wait(64);
- mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(p->port));
+ mix_bist.u64 = cvmx_read_csr(p->mix + MIX_BIST);
if (mix_bist.u64)
dev_warn(p->dev, "MIX failed BIST (0x%016llx)\n",
(unsigned long long)mix_bist.u64);
@@ -474,7 +521,6 @@ static void octeon_mgmt_cam_state_add(struct octeon_mgmt_cam_state *cs,
static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
union cvmx_agl_gmx_rxx_adr_ctl adr_ctl;
union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
unsigned long flags;
@@ -520,29 +566,29 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
spin_lock_irqsave(&p->lock, flags);
/* Disable packet I/O. */
- agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ agl_gmx_prtx.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
prev_packet_enable = agl_gmx_prtx.s.en;
agl_gmx_prtx.s.en = 0;
- cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64);
adr_ctl.u64 = 0;
adr_ctl.s.cam_mode = cam_mode;
adr_ctl.s.mcst = multicast_mode;
adr_ctl.s.bcst = 1; /* Allow broadcast */
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), adr_ctl.u64);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CTL, adr_ctl.u64);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), cam_state.cam[0]);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), cam_state.cam[1]);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), cam_state.cam[2]);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), cam_state.cam[3]);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), cam_state.cam[4]);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), cam_state.cam[5]);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), cam_state.cam_mask);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM0, cam_state.cam[0]);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM1, cam_state.cam[1]);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM2, cam_state.cam[2]);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM3, cam_state.cam[3]);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM4, cam_state.cam[4]);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM5, cam_state.cam[5]);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM_EN, cam_state.cam_mask);
/* Restore packet I/O. */
agl_gmx_prtx.s.en = prev_packet_enable;
- cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64);
spin_unlock_irqrestore(&p->lock, flags);
}
@@ -564,7 +610,6 @@ static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr)
static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM;
/*
@@ -580,8 +625,8 @@ static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
- cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port),
+ cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_MAX, size_without_fcs);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_JABBER,
(size_without_fcs + 7) & 0xfff8);
return 0;
@@ -591,14 +636,13 @@ static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id)
{
struct net_device *netdev = dev_id;
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
union cvmx_mixx_isr mixx_isr;
- mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(port));
+ mixx_isr.u64 = cvmx_read_csr(p->mix + MIX_ISR);
/* Clear any pending interrupts */
- cvmx_write_csr(CVMX_MIXX_ISR(port), mixx_isr.u64);
- cvmx_read_csr(CVMX_MIXX_ISR(port));
+ cvmx_write_csr(p->mix + MIX_ISR, mixx_isr.u64);
+ cvmx_read_csr(p->mix + MIX_ISR);
if (mixx_isr.s.irthresh) {
octeon_mgmt_disable_rx_irq(p);
@@ -629,7 +673,6 @@ static int octeon_mgmt_ioctl(struct net_device *netdev,
static void octeon_mgmt_adjust_link(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
union cvmx_agl_gmx_prtx_cfg prtx_cfg;
unsigned long flags;
int link_changed = 0;
@@ -640,11 +683,9 @@ static void octeon_mgmt_adjust_link(struct net_device *netdev)
link_changed = 1;
if (p->last_duplex != p->phydev->duplex) {
p->last_duplex = p->phydev->duplex;
- prtx_cfg.u64 =
- cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
prtx_cfg.s.duplex = p->phydev->duplex;
- cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port),
- prtx_cfg.u64);
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
}
} else {
if (p->last_link)
@@ -670,18 +711,16 @@ static void octeon_mgmt_adjust_link(struct net_device *netdev)
static int octeon_mgmt_init_phy(struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- char phy_id[MII_BUS_ID_SIZE + 3];
- if (octeon_is_simulation()) {
+ if (octeon_is_simulation() || p->phy_np == NULL) {
/* No PHYs in the simulator. */
netif_carrier_on(netdev);
return 0;
}
- snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", p->port);
-
- p->phydev = phy_connect(netdev, phy_id, octeon_mgmt_adjust_link, 0,
- PHY_INTERFACE_MODE_MII);
+ p->phydev = of_phy_connect(netdev, p->phy_np,
+ octeon_mgmt_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
if (IS_ERR(p->phydev)) {
p->phydev = NULL;
@@ -737,14 +776,14 @@ static int octeon_mgmt_open(struct net_device *netdev)
octeon_mgmt_reset_hw(p);
- mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+ mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL);
/* Bring it out of reset if needed. */
if (mix_ctl.s.reset) {
mix_ctl.s.reset = 0;
- cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+ cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
do {
- mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+ mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL);
} while (mix_ctl.s.reset);
}
@@ -755,17 +794,17 @@ static int octeon_mgmt_open(struct net_device *netdev)
oring1.u64 = 0;
oring1.s.obase = p->tx_ring_handle >> 3;
oring1.s.osize = OCTEON_MGMT_TX_RING_SIZE;
- cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64);
+ cvmx_write_csr(p->mix + MIX_ORING1, oring1.u64);
iring1.u64 = 0;
iring1.s.ibase = p->rx_ring_handle >> 3;
iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE;
- cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64);
+ cvmx_write_csr(p->mix + MIX_IRING1, iring1.u64);
/* Disable packet I/O. */
- prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
prtx_cfg.s.en = 0;
- cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN);
octeon_mgmt_set_mac_address(netdev, &sa);
@@ -782,7 +821,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
mix_ctl.s.nbtarb = 0; /* Arbitration mode */
/* MII CB-request FIFO programmable high watermark */
mix_ctl.s.mrq_hwm = 1;
- cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+ cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
|| OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
@@ -809,16 +848,16 @@ static int octeon_mgmt_open(struct net_device *netdev)
/* Clear statistics. */
/* Clear on read. */
- cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_CTL(port), 1);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port), 0);
- cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port), 0);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_CTL, 1);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP, 0);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD, 0);
- cvmx_write_csr(CVMX_AGL_GMX_TXX_STATS_CTL(port), 1);
- cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT0(port), 0);
- cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT1(port), 0);
+ cvmx_write_csr(p->agl + AGL_GMX_TX_STATS_CTL, 1);
+ cvmx_write_csr(p->agl + AGL_GMX_TX_STAT0, 0);
+ cvmx_write_csr(p->agl + AGL_GMX_TX_STAT1, 0);
/* Clear any pending interrupts */
- cvmx_write_csr(CVMX_MIXX_ISR(port), cvmx_read_csr(CVMX_MIXX_ISR(port)));
+ cvmx_write_csr(p->mix + MIX_ISR, cvmx_read_csr(p->mix + MIX_ISR));
if (request_irq(p->irq, octeon_mgmt_interrupt, 0, netdev->name,
netdev)) {
@@ -829,18 +868,18 @@ static int octeon_mgmt_open(struct net_device *netdev)
/* Interrupt every single RX packet */
mix_irhwm.u64 = 0;
mix_irhwm.s.irhwm = 0;
- cvmx_write_csr(CVMX_MIXX_IRHWM(port), mix_irhwm.u64);
+ cvmx_write_csr(p->mix + MIX_IRHWM, mix_irhwm.u64);
/* Interrupt when we have 1 or more packets to clean. */
mix_orhwm.u64 = 0;
mix_orhwm.s.orhwm = 1;
- cvmx_write_csr(CVMX_MIXX_ORHWM(port), mix_orhwm.u64);
+ cvmx_write_csr(p->mix + MIX_ORHWM, mix_orhwm.u64);
/* Enable receive and transmit interrupts */
mix_intena.u64 = 0;
mix_intena.s.ithena = 1;
mix_intena.s.othena = 1;
- cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+ cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64);
/* Enable packet I/O. */
@@ -871,7 +910,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
* frame. GMX checks that the PREAMBLE is sent correctly.
*/
rxx_frm_ctl.s.pre_chk = 1;
- cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64);
+ cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64);
/* Enable the AGL block */
agl_gmx_inf_mode.u64 = 0;
@@ -879,13 +918,13 @@ static int octeon_mgmt_open(struct net_device *netdev)
cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
/* Configure the port duplex and enables */
- prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+ prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
prtx_cfg.s.tx_en = 1;
prtx_cfg.s.rx_en = 1;
prtx_cfg.s.en = 1;
p->last_duplex = 1;
prtx_cfg.s.duplex = p->last_duplex;
- cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+ cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
p->last_link = 0;
netif_carrier_off(netdev);
@@ -949,7 +988,6 @@ static int octeon_mgmt_stop(struct net_device *netdev)
static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
- int port = p->port;
union mgmt_port_ring_entry re;
unsigned long flags;
int rv = NETDEV_TX_BUSY;
@@ -993,7 +1031,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
netdev->stats.tx_bytes += skb->len;
/* Ring the bell. */
- cvmx_write_csr(CVMX_MIXX_ORING2(port), 1);
+ cvmx_write_csr(p->mix + MIX_ORING2, 1);
rv = NETDEV_TX_OK;
out:
@@ -1071,10 +1109,14 @@ static const struct net_device_ops octeon_mgmt_ops = {
static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
{
- struct resource *res_irq;
struct net_device *netdev;
struct octeon_mgmt *p;
- int i;
+ const __be32 *data;
+ const u8 *mac;
+ struct resource *res_mix;
+ struct resource *res_agl;
+ int len;
+ int result;
netdev = alloc_etherdev(sizeof(struct octeon_mgmt));
if (netdev == NULL)
@@ -1088,14 +1130,63 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
p->netdev = netdev;
p->dev = &pdev->dev;
- p->port = pdev->id;
+ data = of_get_property(pdev->dev.of_node, "cell-index", &len);
+ if (data && len == sizeof(*data)) {
+ p->port = be32_to_cpup(data);
+ } else {
+ dev_err(&pdev->dev, "no 'cell-index' property\n");
+ result = -ENXIO;
+ goto err;
+ }
+
snprintf(netdev->name, IFNAMSIZ, "mgmt%d", p->port);
- res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res_irq)
+ result = platform_get_irq(pdev, 0);
+ if (result < 0)
+ goto err;
+
+ p->irq = result;
+
+ res_mix = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res_mix == NULL) {
+ dev_err(&pdev->dev, "no 'reg' resource\n");
+ result = -ENXIO;
+ goto err;
+ }
+
+ res_agl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res_agl == NULL) {
+ dev_err(&pdev->dev, "no 'reg' resource\n");
+ result = -ENXIO;
+ goto err;
+ }
+
+ p->mix_phys = res_mix->start;
+ p->mix_size = resource_size(res_mix);
+ p->agl_phys = res_agl->start;
+ p->agl_size = resource_size(res_agl);
+
+
+ if (!devm_request_mem_region(&pdev->dev, p->mix_phys, p->mix_size,
+ res_mix->name)) {
+ dev_err(&pdev->dev, "request_mem_region (%s) failed\n",
+ res_mix->name);
+ result = -ENXIO;
+ goto err;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, p->agl_phys, p->agl_size,
+ res_agl->name)) {
+ result = -ENXIO;
+ dev_err(&pdev->dev, "request_mem_region (%s) failed\n",
+ res_agl->name);
goto err;
+ }
+
+
+ p->mix = (u64)devm_ioremap(&pdev->dev, p->mix_phys, p->mix_size);
+ p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size);
- p->irq = res_irq->start;
spin_lock_init(&p->lock);
skb_queue_head_init(&p->tx_list);
@@ -1108,24 +1199,26 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
netdev->netdev_ops = &octeon_mgmt_ops;
netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
- /* The mgmt ports get the first N MACs. */
- for (i = 0; i < 6; i++)
- netdev->dev_addr[i] = octeon_bootinfo->mac_addr_base[i];
- netdev->dev_addr[5] += p->port;
+ mac = of_get_mac_address(pdev->dev.of_node);
+
+ if (mac)
+ memcpy(netdev->dev_addr, mac, 6);
- if (p->port >= octeon_bootinfo->mac_addr_count)
- dev_err(&pdev->dev,
- "Error %s: Using MAC outside of the assigned range: %pM\n",
- netdev->name, netdev->dev_addr);
+ p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
- if (register_netdev(netdev))
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+ result = register_netdev(netdev);
+ if (result)
goto err;
dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
return 0;
+
err:
free_netdev(netdev);
- return -ENOENT;
+ return result;
}
static int __devexit octeon_mgmt_remove(struct platform_device *pdev)
@@ -1137,10 +1230,19 @@ static int __devexit octeon_mgmt_remove(struct platform_device *pdev)
return 0;
}
+static struct of_device_id octeon_mgmt_match[] = {
+ {
+ .compatible = "cavium,octeon-5750-mix",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, octeon_mgmt_match);
+
static struct platform_driver octeon_mgmt_driver = {
.driver = {
.name = "octeon_mgmt",
.owner = THIS_MODULE,
+ .of_match_table = octeon_mgmt_match,
},
.probe = octeon_mgmt_probe,
.remove = __devexit_p(octeon_mgmt_remove),
--
1.7.2.3
^ permalink raw reply related
* [PATCH v2 2/5] netdev: mdio-octeon.c: Convert to use device tree.
From: David Daney @ 2012-04-27 1:20 UTC (permalink / raw)
To: linux-mips-6z/3iImG2C8G8FEW9MqTrA, ralf-6z/3iImG2C8G8FEW9MqTrA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Grant Likely,
Rob Herring
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, David S. Miller,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Daney
In-Reply-To: <1335489630-27017-1-git-send-email-ddaney.cavm-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Get the MDIO bus controller addresses from the device tree, small
clean up in use of devm_*
Remove, now unused, platform device setup code.
Acked-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
arch/mips/cavium-octeon/octeon-platform.c | 30 ---------
drivers/net/phy/mdio-octeon.c | 92 ++++++++++++++++++-----------
2 files changed, 58 insertions(+), 64 deletions(-)
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index f62a40f..66cabc2 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -168,36 +168,6 @@ out:
}
device_initcall(octeon_rng_device_init);
-/* Octeon SMI/MDIO interface. */
-static int __init octeon_mdiobus_device_init(void)
-{
- struct platform_device *pd;
- int ret = 0;
-
- if (octeon_is_simulation())
- return 0; /* No mdio in the simulator. */
-
- /* The bus number is the platform_device id. */
- pd = platform_device_alloc("mdio-octeon", 0);
- if (!pd) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = platform_device_add(pd);
- if (ret)
- goto fail;
-
- return ret;
-fail:
- platform_device_put(pd);
-
-out:
- return ret;
-
-}
-device_initcall(octeon_mdiobus_device_init);
-
/* Octeon mgmt port Ethernet interface. */
static int __init octeon_mgmt_device_init(void)
{
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
index 826d961..d4015aa 100644
--- a/drivers/net/phy/mdio-octeon.c
+++ b/drivers/net/phy/mdio-octeon.c
@@ -3,14 +3,17 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2009 Cavium Networks
+ * Copyright (C) 2009,2011 Cavium, Inc.
*/
-#include <linux/gfp.h>
-#include <linux/init.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/of_mdio.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
#include <linux/phy.h>
+#include <linux/io.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-smix-defs.h>
@@ -18,9 +21,17 @@
#define DRV_VERSION "1.0"
#define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
+#define SMI_CMD 0x0
+#define SMI_WR_DAT 0x8
+#define SMI_RD_DAT 0x10
+#define SMI_CLK 0x18
+#define SMI_EN 0x20
+
struct octeon_mdiobus {
struct mii_bus *mii_bus;
- int unit;
+ u64 register_base;
+ resource_size_t mdio_phys;
+ resource_size_t regsize;
int phy_irq[PHY_MAX_ADDR];
};
@@ -35,15 +46,15 @@ static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum;
- cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+ cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64);
do {
/*
* Wait 1000 clocks so we don't saturate the RSL bus
* doing reads.
*/
- cvmx_wait(1000);
- smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit));
+ __delay(1000);
+ smi_rd.u64 = cvmx_read_csr(p->register_base + SMI_RD_DAT);
} while (smi_rd.s.pending && --timeout);
if (smi_rd.s.val)
@@ -62,21 +73,21 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
smi_wr.u64 = 0;
smi_wr.s.dat = val;
- cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64);
+ cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64);
smi_cmd.u64 = 0;
smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum;
- cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+ cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64);
do {
/*
* Wait 1000 clocks so we don't saturate the RSL bus
* doing reads.
*/
- cvmx_wait(1000);
- smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit));
+ __delay(1000);
+ smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT);
} while (smi_wr.s.pending && --timeout);
if (timeout <= 0)
@@ -88,38 +99,44 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
{
struct octeon_mdiobus *bus;
+ struct resource *res_mem;
union cvmx_smix_en smi_en;
- int i;
int err = -ENOENT;
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
- /* The platform_device id is our unit number. */
- bus->unit = pdev->id;
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (res_mem == NULL) {
+ dev_err(&pdev->dev, "found no memory resource\n");
+ err = -ENXIO;
+ goto fail;
+ }
+ bus->mdio_phys = res_mem->start;
+ bus->regsize = resource_size(res_mem);
+ if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize,
+ res_mem->name)) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ goto fail;
+ }
+ bus->register_base =
+ (u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize);
bus->mii_bus = mdiobus_alloc();
if (!bus->mii_bus)
- goto err;
+ goto fail;
smi_en.u64 = 0;
smi_en.s.en = 1;
- cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
-
- /*
- * Standard Octeon evaluation boards don't support phy
- * interrupts, we need to poll.
- */
- for (i = 0; i < PHY_MAX_ADDR; i++)
- bus->phy_irq[i] = PHY_POLL;
+ cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64);
bus->mii_bus->priv = bus;
bus->mii_bus->irq = bus->phy_irq;
bus->mii_bus->name = "mdio-octeon";
- snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
- bus->mii_bus->name, bus->unit);
+ snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base);
bus->mii_bus->parent = &pdev->dev;
bus->mii_bus->read = octeon_mdiobus_read;
@@ -127,20 +144,18 @@ static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, bus);
- err = mdiobus_register(bus->mii_bus);
+ err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node);
if (err)
- goto err_register;
+ goto fail_register;
dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
return 0;
-err_register:
+fail_register:
mdiobus_free(bus->mii_bus);
-
-err:
- devm_kfree(&pdev->dev, bus);
+fail:
smi_en.u64 = 0;
- cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
+ cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64);
return err;
}
@@ -154,14 +169,23 @@ static int __devexit octeon_mdiobus_remove(struct platform_device *pdev)
mdiobus_unregister(bus->mii_bus);
mdiobus_free(bus->mii_bus);
smi_en.u64 = 0;
- cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
+ cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64);
return 0;
}
+static struct of_device_id octeon_mdiobus_match[] = {
+ {
+ .compatible = "cavium,octeon-3860-mdio",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, octeon_mdiobus_match);
+
static struct platform_driver octeon_mdiobus_driver = {
.driver = {
.name = "mdio-octeon",
.owner = THIS_MODULE,
+ .of_match_table = octeon_mdiobus_match,
},
.probe = octeon_mdiobus_probe,
.remove = __devexit_p(octeon_mdiobus_remove),
--
1.7.2.3
^ permalink raw reply related
* [PATCH v2 0/5] MIPS: OCTEON: Convert some device to use Device Tree.
From: David Daney @ 2012-04-27 1:20 UTC (permalink / raw)
To: linux-mips, ralf, devicetree-discuss, Grant Likely, Rob Herring
Cc: linux-kernel, David Daney, netdev, Greg Kroah-Hartman,
David S. Miller, Jean Delvare (PC drivers, core),
Ben Dooks (embedded platforms), Wolfram Sang (embedded platforms),
linux-i2c
From: David Daney <david.daney@cavium.com>
This patch set depends on the previous set to add Device Tree to
OCTEON. That set can be found among other places here:
http://marc.info/?l=linux-kernel&m=133548781607480
For v2:
No functional changes, but minor clean-ups to use some new device tree
helper functions.
Some Acked-bys added.
I am suggesting that all these go via Ralf's linux-mips.org tree as
they depend on other patches in that tree.
>From v1:
The patches are for drivers scattered throughout the tree, but there
is an order dependency as well as the dependency mentioned above, so
it may be preferable to merge them all via Ralf's linux-mips.org tree
rather that separately via the various device sub-system maintainers.
The mdio-octeon.c and octeon_mgmt patches were already Acked-by davem.
The i2c has been seen before, but to my knowledge was never acked.
The octeon_ethernet patch is in staging and has also been seen before.
The serial patch is new.
David Daney (5):
i2c: Convert i2c-octeon.c to use device tree.
netdev: mdio-octeon.c: Convert to use device tree.
netdev: octeon_mgmt: Convert to use device tree.
staging: octeon_ethernet: Convert to use device tree.
MIPS: Octeon: Use device tree to register serial ports.
arch/mips/cavium-octeon/octeon-irq.c | 8 -
arch/mips/cavium-octeon/octeon-platform.c | 176 ----------------
arch/mips/cavium-octeon/serial.c | 134 +++++--------
arch/mips/include/asm/octeon/octeon.h | 5 -
drivers/i2c/busses/i2c-octeon.c | 92 +++++----
drivers/net/ethernet/octeon/octeon_mgmt.c | 312 +++++++++++++++++++----------
drivers/net/phy/mdio-octeon.c | 92 ++++++---
drivers/staging/octeon/ethernet-mdio.c | 28 ++--
drivers/staging/octeon/ethernet.c | 153 +++++++++-----
drivers/staging/octeon/octeon-ethernet.h | 3 +
10 files changed, 484 insertions(+), 519 deletions(-)
Cc: netdev@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: "Jean Delvare (PC drivers, core)" <khali@linux-fr.org>
Cc: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
Cc: "Wolfram Sang (embedded platforms)" <w.sang@pengutronix.de>
Cc: linux-i2c@vger.kernel.org
--
1.7.2.3
^ permalink raw reply
* Re: [PATCH v4 1/3] make jump_labels wait while updates are in place
From: KAMEZAWA Hiroyuki @ 2012-04-27 1:05 UTC (permalink / raw)
To: Steven Rostedt
Cc: Glauber Costa, cgroups, netdev, linux-kernel, Li Zefan, Tejun Heo,
linux-mm, devel, Johannes Weiner, Michal Hocko, Ingo Molnar,
Jason Baron
In-Reply-To: <20120427004305.GC23877@home.goodmis.org>
(2012/04/27 9:43), Steven Rostedt wrote:
> On Thu, Apr 26, 2012 at 07:51:05PM -0300, Glauber Costa wrote:
>> In mem cgroup, we need to guarantee that two concurrent updates
>> of the jump_label interface wait for each other. IOW, we can't have
>> other updates returning while the first one is still patching the
>> kernel around, otherwise we'll race.
>
> But it shouldn't. The code as is should prevent that.
>
>>
>> I believe this is something that can fit well in the static branch
>> API, without noticeable disadvantages:
>>
>> * in the common case, it will be a quite simple lock/unlock operation
>> * Every context that calls static_branch_slow* already expects to be
>> in sleeping context because it will mutex_lock the unlikely case.
>> * static_key_slow_inc is not expected to be called in any fast path,
>> otherwise it would be expected to have quite a different name. Therefore
>> the mutex + atomic combination instead of just an atomic should not kill
>> us.
>>
>> Signed-off-by: Glauber Costa <glommer@parallels.com>
>> CC: Tejun Heo <tj@kernel.org>
>> CC: Li Zefan <lizefan@huawei.com>
>> CC: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
>> CC: Johannes Weiner <hannes@cmpxchg.org>
>> CC: Michal Hocko <mhocko@suse.cz>
>> CC: Ingo Molnar <mingo@elte.hu>
>> CC: Jason Baron <jbaron@redhat.com>
>> ---
>> kernel/jump_label.c | 21 +++++++++++----------
>> 1 files changed, 11 insertions(+), 10 deletions(-)
>>
>> diff --git a/kernel/jump_label.c b/kernel/jump_label.c
>> index 4304919..5d09cb4 100644
>> --- a/kernel/jump_label.c
>> +++ b/kernel/jump_label.c
>> @@ -57,17 +57,16 @@ static void jump_label_update(struct static_key *key, int enable);
>>
>> void static_key_slow_inc(struct static_key *key)
>> {
>> + jump_label_lock();
>> if (atomic_inc_not_zero(&key->enabled))
>> - return;
>
> If key->enabled is not zero, there's nothing to be done. As the jump
> label has already been enabled. Note, the key->enabled doesn't get set
> until after the jump label is updated. Thus, if two tasks were to come
> in, they both would be locked on the jump_label_lock().
>
Ah, sorry, I misunderstood somthing. I'm sorry, Glauber.
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH] IPVS: ip_vs_ftp.c: local functions should not be exposed globally
From: Simon Horman @ 2012-04-27 1:01 UTC (permalink / raw)
To: H Hartley Sweeten; +Cc: Linux Kernel, netdev, davem
In-Reply-To: <201204261117.28491.hartleys@visionengravers.com>
On Thu, Apr 26, 2012 at 11:17:28AM -0700, H Hartley Sweeten wrote:
> Functions not referenced outside of a source file should be marked
> static to prevent it from being exposed globally.
>
> This quiets the sparse warnings:
>
> warning: symbol 'ip_vs_ftp_init' was not declared. Should it be static?
On Thu, Apr 26, 2012 at 11:26:15AM -0700, H Hartley Sweeten wrote:
> Functions not referenced outside of a source file should be marked
> static to prevent it from being exposed globally.
>
> This quiets the sparse warnings:
>
> warning: symbol '__ipvs_proto_data_get' was not declared. Should it be static?
>
> Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
> Cc: "David S. Miller" <davem@davemloft.net>
Thanks, I have applied these to ipvs-next.
git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git
^ permalink raw reply
* Re: [PATCH] IPVS: ip_vs_sync.c: local functions should not be exposed globally
From: Simon Horman @ 2012-04-27 0:57 UTC (permalink / raw)
To: Julian Anastasov; +Cc: H Hartley Sweeten, Linux Kernel, netdev, David S. Miller
In-Reply-To: <alpine.LFD.2.00.1204262301160.2078@ja.ssi.bg>
On Thu, Apr 26, 2012 at 11:11:54PM +0300, Julian Anastasov wrote:
>
> Hello,
>
> On Thu, 26 Apr 2012, H Hartley Sweeten wrote:
>
> > Functions not referenced outside of a source file should be marked
> > static to prevent it from being exposed globally.
> >
> > This quiets the sparse warnings:
> >
> > warning: symbol 'ip_vs_sync_conn_v0' was not declared. Should it be static?
> >
> > Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
> > Cc: "David S. Miller" <davem@davemloft.net>
> >
> > ---
> >
> > diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
> > index bf5e538..49a1fe8 100644
> > --- a/net/netfilter/ipvs/ip_vs_sync.c
> > +++ b/net/netfilter/ipvs/ip_vs_sync.c
> > @@ -446,7 +446,7 @@ ip_vs_sync_buff_create_v0(struct netns_ipvs *ipvs)
> > * Version 0 , could be switched in by sys_ctl.
> > * Add an ip_vs_conn information into the current sync_buff.
> > */
> > -void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp)
> > +static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp)
>
> The 3 patches for IPVS look correct but this change
> is already not needed after one of our planned changes:
>
> "ipvs: reduce sync rate with time thresholds"
>
> Not sure how we will avoid the collision, may be
> Simon will take only the other 2 changes? Or David will
> take all changes and we have to rebase?
I think the best way forwards is for me to take only the first two changes.
I don't think that this fix is 3.4 material and as you say we expect this
problem to be resolved by other means in 3.5.
I am of course open to discussion on this.
^ permalink raw reply
* [GIT PULL net] IPVS
From: Simon Horman @ 2012-04-27 0:53 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Hans Schillstrom, Jesper Dangaard Brouer
Hi Pablo,
please consider the following 5 changes for 3.4, they are all bug fixes.
I would also like these changes considered for stable.
The following changes since commit 8f9b9a2fad47af27e14b037395e03cd8278d96d7:
ipvs: fix crash in ip_vs_control_net_cleanup on unload (2012-04-25 11:16:30 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs.git master
for you to fetch changes up to 1c3dc0f92d127d3fdefa84c7ef629b070bf8d32c:
ipvs: kernel oops - do_ip_vs_get_ctl (2012-04-26 18:04:31 +0900)
----------------------------------------------------------------
Hans Schillstrom (3):
ipvs: null check of net->ipvs in lblc(r) shedulers
ipvs: take care of return value from protocol init_netns
ipvs: kernel oops - do_ip_vs_get_ctl
Julian Anastasov (2):
ipvs: add check in ftp for initialized core
ipvs: reset ipvs pointer in netns
include/net/ip_vs.h | 4 ++-
net/netfilter/ipvs/ip_vs_core.c | 11 +++++++
net/netfilter/ipvs/ip_vs_ctl.c | 52 +++++++++++++++++++--------------
net/netfilter/ipvs/ip_vs_ftp.c | 2 ++
net/netfilter/ipvs/ip_vs_lblc.c | 3 ++
net/netfilter/ipvs/ip_vs_lblcr.c | 3 ++
net/netfilter/ipvs/ip_vs_proto.c | 11 +++++--
net/netfilter/ipvs/ip_vs_proto_sctp.c | 5 +++-
net/netfilter/ipvs/ip_vs_proto_tcp.c | 5 +++-
net/netfilter/ipvs/ip_vs_proto_udp.c | 5 +++-
10 files changed, 73 insertions(+), 28 deletions(-)
^ permalink raw reply
* [PATCH 3/5] ipvs: null check of net->ipvs in lblc(r) shedulers
From: Simon Horman @ 2012-04-27 0:53 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Hans Schillstrom, Jesper Dangaard Brouer,
Simon Horman
In-Reply-To: <1335488039-13471-1-git-send-email-horms@verge.net.au>
From: Hans Schillstrom <hans.schillstrom@ericsson.com>
Avoid crash when registering shedulers after
the IPVS core initialization for netns fails. Do this by
checking for present core (net->ipvs).
Signed-off-by: Hans Schillstrom <hans.schillstrom@ericsson.com>
Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_lblc.c | 3 +++
net/netfilter/ipvs/ip_vs_lblcr.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 0f16283..caa4370 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -551,6 +551,9 @@ static int __net_init __ip_vs_lblc_init(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);
+ if (!ipvs)
+ return -ENOENT;
+
if (!net_eq(net, &init_net)) {
ipvs->lblc_ctl_table = kmemdup(vs_vars_table,
sizeof(vs_vars_table),
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index eec797f..548bf37 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -745,6 +745,9 @@ static int __net_init __ip_vs_lblcr_init(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);
+ if (!ipvs)
+ return -ENOENT;
+
if (!net_eq(net, &init_net)) {
ipvs->lblcr_ctl_table = kmemdup(vs_vars_table,
sizeof(vs_vars_table),
--
1.7.9.5
^ permalink raw reply related
* [PATCH 5/5] ipvs: kernel oops - do_ip_vs_get_ctl
From: Simon Horman @ 2012-04-27 0:53 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Hans Schillstrom, Jesper Dangaard Brouer,
Simon Horman
In-Reply-To: <1335488039-13471-1-git-send-email-horms@verge.net.au>
From: Hans Schillstrom <hans.schillstrom@ericsson.com>
Change order of init so netns init is ready
when register ioctl and netlink.
Ver2
Whitespace fixes and __init added.
Reported-by: "Ryan O'Hara" <rohara@redhat.com>
Signed-off-by: Hans Schillstrom <hans.schillstrom@ericsson.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
include/net/ip_vs.h | 2 ++
net/netfilter/ipvs/ip_vs_core.c | 9 +++++++
net/netfilter/ipvs/ip_vs_ctl.c | 52 ++++++++++++++++++++++-----------------
3 files changed, 41 insertions(+), 22 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 6d90dda..72522f0 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -1203,6 +1203,8 @@ ip_vs_lookup_real_service(struct net *net, int af, __u16 protocol,
extern int ip_vs_use_count_inc(void);
extern void ip_vs_use_count_dec(void);
+extern int ip_vs_register_nl_ioctl(void);
+extern void ip_vs_unregister_nl_ioctl(void);
extern int ip_vs_control_init(void);
extern void ip_vs_control_cleanup(void);
extern struct ip_vs_dest *
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 260b9ef..00bdb1d 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1995,10 +1995,18 @@ static int __init ip_vs_init(void)
goto cleanup_dev;
}
+ ret = ip_vs_register_nl_ioctl();
+ if (ret < 0) {
+ pr_err("can't register netlink/ioctl.\n");
+ goto cleanup_hooks;
+ }
+
pr_info("ipvs loaded.\n");
return ret;
+cleanup_hooks:
+ nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
cleanup_dev:
unregister_pernet_device(&ipvs_core_dev_ops);
cleanup_sub:
@@ -2014,6 +2022,7 @@ exit:
static void __exit ip_vs_cleanup(void)
{
+ ip_vs_unregister_nl_ioctl();
nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
unregister_pernet_device(&ipvs_core_dev_ops);
unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 376d2b1..f558998 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -3750,21 +3750,10 @@ void __net_exit ip_vs_control_net_cleanup(struct net *net)
free_percpu(ipvs->tot_stats.cpustats);
}
-int __init ip_vs_control_init(void)
+int __init ip_vs_register_nl_ioctl(void)
{
- int idx;
int ret;
- EnterFunction(2);
-
- /* Initialize svc_table, ip_vs_svc_fwm_table, rs_table */
- for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
- INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
- }
-
- smp_wmb(); /* Do we really need it now ? */
-
ret = nf_register_sockopt(&ip_vs_sockopts);
if (ret) {
pr_err("cannot register sockopt.\n");
@@ -3776,28 +3765,47 @@ int __init ip_vs_control_init(void)
pr_err("cannot register Generic Netlink interface.\n");
goto err_genl;
}
-
- ret = register_netdevice_notifier(&ip_vs_dst_notifier);
- if (ret < 0)
- goto err_notf;
-
- LeaveFunction(2);
return 0;
-err_notf:
- ip_vs_genl_unregister();
err_genl:
nf_unregister_sockopt(&ip_vs_sockopts);
err_sock:
return ret;
}
+void ip_vs_unregister_nl_ioctl(void)
+{
+ ip_vs_genl_unregister();
+ nf_unregister_sockopt(&ip_vs_sockopts);
+}
+
+int __init ip_vs_control_init(void)
+{
+ int idx;
+ int ret;
+
+ EnterFunction(2);
+
+ /* Initialize svc_table, ip_vs_svc_fwm_table, rs_table */
+ for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+ INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
+ INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
+ }
+
+ smp_wmb(); /* Do we really need it now ? */
+
+ ret = register_netdevice_notifier(&ip_vs_dst_notifier);
+ if (ret < 0)
+ return ret;
+
+ LeaveFunction(2);
+ return 0;
+}
+
void ip_vs_control_cleanup(void)
{
EnterFunction(2);
unregister_netdevice_notifier(&ip_vs_dst_notifier);
- ip_vs_genl_unregister();
- nf_unregister_sockopt(&ip_vs_sockopts);
LeaveFunction(2);
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/5] ipvs: take care of return value from protocol init_netns
From: Simon Horman @ 2012-04-27 0:53 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Hans Schillstrom, Jesper Dangaard Brouer,
Simon Horman
In-Reply-To: <1335488039-13471-1-git-send-email-horms@verge.net.au>
From: Hans Schillstrom <hans.schillstrom@ericsson.com>
ip_vs_create_timeout_table() can return NULL
All functions protocol init_netns is affected of this patch.
Signed-off-by: Hans Schillstrom <hans.schillstrom@ericsson.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
include/net/ip_vs.h | 2 +-
net/netfilter/ipvs/ip_vs_proto.c | 11 +++++++++--
net/netfilter/ipvs/ip_vs_proto_sctp.c | 5 ++++-
net/netfilter/ipvs/ip_vs_proto_tcp.c | 5 ++++-
net/netfilter/ipvs/ip_vs_proto_udp.c | 5 ++++-
5 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 2bdee51..6d90dda 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -393,7 +393,7 @@ struct ip_vs_protocol {
void (*exit)(struct ip_vs_protocol *pp);
- void (*init_netns)(struct net *net, struct ip_vs_proto_data *pd);
+ int (*init_netns)(struct net *net, struct ip_vs_proto_data *pd);
void (*exit_netns)(struct net *net, struct ip_vs_proto_data *pd);
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index a62360e..ed835e6 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -78,8 +78,15 @@ register_ip_vs_proto_netns(struct net *net, struct ip_vs_protocol *pp)
ipvs->proto_data_table[hash] = pd;
atomic_set(&pd->appcnt, 0); /* Init app counter */
- if (pp->init_netns != NULL)
- pp->init_netns(net, pd);
+ if (pp->init_netns != NULL) {
+ int ret = pp->init_netns(net, pd);
+ if (ret) {
+ /* unlink an free proto data */
+ ipvs->proto_data_table[hash] = pd->next;
+ kfree(pd);
+ return ret;
+ }
+ }
return 0;
}
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index 1fbf7a2..9f3fb75 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -1090,7 +1090,7 @@ out:
* timeouts is netns related now.
* ---------------------------------------------
*/
-static void __ip_vs_sctp_init(struct net *net, struct ip_vs_proto_data *pd)
+static int __ip_vs_sctp_init(struct net *net, struct ip_vs_proto_data *pd)
{
struct netns_ipvs *ipvs = net_ipvs(net);
@@ -1098,6 +1098,9 @@ static void __ip_vs_sctp_init(struct net *net, struct ip_vs_proto_data *pd)
spin_lock_init(&ipvs->sctp_app_lock);
pd->timeout_table = ip_vs_create_timeout_table((int *)sctp_timeouts,
sizeof(sctp_timeouts));
+ if (!pd->timeout_table)
+ return -ENOMEM;
+ return 0;
}
static void __ip_vs_sctp_exit(struct net *net, struct ip_vs_proto_data *pd)
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index ef8641f..cd609cc 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -677,7 +677,7 @@ void ip_vs_tcp_conn_listen(struct net *net, struct ip_vs_conn *cp)
* timeouts is netns related now.
* ---------------------------------------------
*/
-static void __ip_vs_tcp_init(struct net *net, struct ip_vs_proto_data *pd)
+static int __ip_vs_tcp_init(struct net *net, struct ip_vs_proto_data *pd)
{
struct netns_ipvs *ipvs = net_ipvs(net);
@@ -685,7 +685,10 @@ static void __ip_vs_tcp_init(struct net *net, struct ip_vs_proto_data *pd)
spin_lock_init(&ipvs->tcp_app_lock);
pd->timeout_table = ip_vs_create_timeout_table((int *)tcp_timeouts,
sizeof(tcp_timeouts));
+ if (!pd->timeout_table)
+ return -ENOMEM;
pd->tcp_state_table = tcp_states;
+ return 0;
}
static void __ip_vs_tcp_exit(struct net *net, struct ip_vs_proto_data *pd)
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index f4b7262..2fedb2d 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -467,7 +467,7 @@ udp_state_transition(struct ip_vs_conn *cp, int direction,
cp->timeout = pd->timeout_table[IP_VS_UDP_S_NORMAL];
}
-static void __udp_init(struct net *net, struct ip_vs_proto_data *pd)
+static int __udp_init(struct net *net, struct ip_vs_proto_data *pd)
{
struct netns_ipvs *ipvs = net_ipvs(net);
@@ -475,6 +475,9 @@ static void __udp_init(struct net *net, struct ip_vs_proto_data *pd)
spin_lock_init(&ipvs->udp_app_lock);
pd->timeout_table = ip_vs_create_timeout_table((int *)udp_timeouts,
sizeof(udp_timeouts));
+ if (!pd->timeout_table)
+ return -ENOMEM;
+ return 0;
}
static void __udp_exit(struct net *net, struct ip_vs_proto_data *pd)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/5] ipvs: reset ipvs pointer in netns
From: Simon Horman @ 2012-04-27 0:53 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Hans Schillstrom, Jesper Dangaard Brouer,
Simon Horman
In-Reply-To: <1335488039-13471-1-git-send-email-horms@verge.net.au>
From: Julian Anastasov <ja@ssi.bg>
Make sure net->ipvs is reset on netns cleanup or failed
initialization. It is needed for IPVS applications to know that
IPVS core is not loaded in netns.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Hans Schillstrom <hans.schillstrom@ericsson.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 2555816..260b9ef 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1924,6 +1924,7 @@ protocol_fail:
control_fail:
ip_vs_estimator_net_cleanup(net);
estimator_fail:
+ net->ipvs = NULL;
return -ENOMEM;
}
@@ -1936,6 +1937,7 @@ static void __net_exit __ip_vs_cleanup(struct net *net)
ip_vs_control_net_cleanup(net);
ip_vs_estimator_net_cleanup(net);
IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen);
+ net->ipvs = NULL;
}
static void __net_exit __ip_vs_dev_cleanup(struct net *net)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/5] ipvs: add check in ftp for initialized core
From: Simon Horman @ 2012-04-27 0:53 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Hans Schillstrom, Jesper Dangaard Brouer,
Simon Horman
In-Reply-To: <1335488039-13471-1-git-send-email-horms@verge.net.au>
From: Julian Anastasov <ja@ssi.bg>
Avoid crash when registering ip_vs_ftp after
the IPVS core initialization for netns fails. Do this by
checking for present core (net->ipvs).
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Hans Schillstrom <hans.schillstrom@ericsson.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_ftp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 538d74e..e39f693 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -439,6 +439,8 @@ static int __net_init __ip_vs_ftp_init(struct net *net)
struct ip_vs_app *app;
struct netns_ipvs *ipvs = net_ipvs(net);
+ if (!ipvs)
+ return -ENOENT;
app = kmemdup(&ip_vs_ftp, sizeof(struct ip_vs_app), GFP_KERNEL);
if (!app)
return -ENOMEM;
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH] e1000e: MSI interrupt test failed, using legacy interrupt
From: Jeff Kirsher @ 2012-04-27 0:46 UTC (permalink / raw)
To: prasanna.panchamukhi
Cc: bruce.w.allan, jeffrey.e.pieper, bhutchings, gospo, sassmann,
jesse.brandeburg, e1000-devel, netdev
In-Reply-To: <4F99EB6B.7090000@riverbed.com>
[-- Attachment #1: Type: text/plain, Size: 2909 bytes --]
On Thu, 2012-04-26 at 17:42 -0700, Prasanna Panchamukhi wrote:
> On 04/26/2012 05:20 PM, Jeff Kirsher wrote:
> > On 04/26/2012 05:05 PM, prasanna.panchamukhi@riverbed.com wrote:
> >> From: Prasanna S. Panchamukhi<ppanchamukhi@riverbed.com>
> >>
> >> Following logs where seen on Systems with multiple NICs& ports,
> >> while using MSI interrupts as shown below:
> >>
> >> Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0d.0: lan0_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: wan0_1: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: lan0_1: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:32 (none) user.warn kernel: 0000:40:0e.0: wan4_0: MSI interrupt
> >> test failed, using legacy interrupt.
> >> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >> Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0e.0: wan1_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0e.0: lan1_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: wan2_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: lan2_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: wan3_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: lan3_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0e.0: lan4_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: wan5_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: lan5_0: NIC Link is Up
> >> 1000 Mbps Full Duplex, Flow Control: RX/TX
> >>
> >> This patch changes the IRQ tests to use polling loops starting with a
> >> delay of 1 tick and doubling that if necessary up to a maximum total
> >> delay of approximately 1 second.
> >>
> >> Signed-off-by: Prasanna S. Panchamukhi<ppanchamukhi@riverbed.com>
> >> ---
> >> drivers/net/ethernet/intel/e1000e/netdev.c | 27 +++++++++++++++++++++++----
> >> 1 files changed, 23 insertions(+), 4 deletions(-)
> > Thanks Prasanna, Dave did accept the previous patch, so does this patch
> > take that into account?
> No, If Dave has already accepted previous patch we can ignore this patch
> for now.
>
> Thanks,
> Prasanna
Yeah, he has accepted the previous patch so I will ignore this patch.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v4 1/3] make jump_labels wait while updates are in place
From: Steven Rostedt @ 2012-04-27 0:43 UTC (permalink / raw)
To: Glauber Costa
Cc: cgroups, netdev, linux-kernel, Li Zefan, Tejun Heo,
kamezawa.hiroyu, linux-mm, devel, Johannes Weiner, Michal Hocko,
Ingo Molnar, Jason Baron
In-Reply-To: <1335480667-8301-2-git-send-email-glommer@parallels.com>
On Thu, Apr 26, 2012 at 07:51:05PM -0300, Glauber Costa wrote:
> In mem cgroup, we need to guarantee that two concurrent updates
> of the jump_label interface wait for each other. IOW, we can't have
> other updates returning while the first one is still patching the
> kernel around, otherwise we'll race.
But it shouldn't. The code as is should prevent that.
>
> I believe this is something that can fit well in the static branch
> API, without noticeable disadvantages:
>
> * in the common case, it will be a quite simple lock/unlock operation
> * Every context that calls static_branch_slow* already expects to be
> in sleeping context because it will mutex_lock the unlikely case.
> * static_key_slow_inc is not expected to be called in any fast path,
> otherwise it would be expected to have quite a different name. Therefore
> the mutex + atomic combination instead of just an atomic should not kill
> us.
>
> Signed-off-by: Glauber Costa <glommer@parallels.com>
> CC: Tejun Heo <tj@kernel.org>
> CC: Li Zefan <lizefan@huawei.com>
> CC: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
> CC: Johannes Weiner <hannes@cmpxchg.org>
> CC: Michal Hocko <mhocko@suse.cz>
> CC: Ingo Molnar <mingo@elte.hu>
> CC: Jason Baron <jbaron@redhat.com>
> ---
> kernel/jump_label.c | 21 +++++++++++----------
> 1 files changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/kernel/jump_label.c b/kernel/jump_label.c
> index 4304919..5d09cb4 100644
> --- a/kernel/jump_label.c
> +++ b/kernel/jump_label.c
> @@ -57,17 +57,16 @@ static void jump_label_update(struct static_key *key, int enable);
>
> void static_key_slow_inc(struct static_key *key)
> {
> + jump_label_lock();
> if (atomic_inc_not_zero(&key->enabled))
> - return;
If key->enabled is not zero, there's nothing to be done. As the jump
label has already been enabled. Note, the key->enabled doesn't get set
until after the jump label is updated. Thus, if two tasks were to come
in, they both would be locked on the jump_label_lock().
> + goto out;
>
> - jump_label_lock();
> - if (atomic_read(&key->enabled) == 0) {
> - if (!jump_label_get_branch_default(key))
> - jump_label_update(key, JUMP_LABEL_ENABLE);
> - else
> - jump_label_update(key, JUMP_LABEL_DISABLE);
> - }
> + if (!jump_label_get_branch_default(key))
> + jump_label_update(key, JUMP_LABEL_ENABLE);
> + else
> + jump_label_update(key, JUMP_LABEL_DISABLE);
> atomic_inc(&key->enabled);
> +out:
> jump_label_unlock();
> }
> EXPORT_SYMBOL_GPL(static_key_slow_inc);
> @@ -75,10 +74,11 @@ EXPORT_SYMBOL_GPL(static_key_slow_inc);
> static void __static_key_slow_dec(struct static_key *key,
> unsigned long rate_limit, struct delayed_work *work)
> {
> - if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) {
> + jump_label_lock();
> + if (atomic_dec_and_test(&key->enabled)) {
> WARN(atomic_read(&key->enabled) < 0,
> "jump label: negative count!\n");
> - return;
Here, it is similar. If enabled is > 1, it wouldn't need to do anything,
thus it would dec the counter and return. But if it were one, then the
lock would be taken. and set to zero. There shouldn't be a case where
two tasks came in to set it less than zero (then something is
unbalanced).
Are you hitting the WARN_ON?
-- Steve
> + goto out;
> }
>
> if (rate_limit) {
> @@ -90,6 +90,7 @@ static void __static_key_slow_dec(struct static_key *key,
> else
> jump_label_update(key, JUMP_LABEL_ENABLE);
> }
> +out:
> jump_label_unlock();
> }
>
> --
> 1.7.7.6
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH] e1000e: MSI interrupt test failed, using legacy interrupt
From: Prasanna Panchamukhi @ 2012-04-27 0:42 UTC (permalink / raw)
To: jeffrey.t.kirsher
Cc: Jeff Kirsher, prasanna.panchamukhi, bruce.w.allan,
jeffrey.e.pieper, bhutchings, gospo, sassmann, jesse.brandeburg,
e1000-devel, netdev
In-Reply-To: <4F99E653.4000608@gmail.com>
On 04/26/2012 05:20 PM, Jeff Kirsher wrote:
> On 04/26/2012 05:05 PM, prasanna.panchamukhi@riverbed.com wrote:
>> From: Prasanna S. Panchamukhi<ppanchamukhi@riverbed.com>
>>
>> Following logs where seen on Systems with multiple NICs& ports,
>> while using MSI interrupts as shown below:
>>
>> Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0d.0: lan0_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: wan0_1: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: lan0_1: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:32 (none) user.warn kernel: 0000:40:0e.0: wan4_0: MSI interrupt
>> test failed, using legacy interrupt.
>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0e.0: wan1_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0e.0: lan1_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: wan2_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: lan2_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: wan3_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: lan3_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0e.0: lan4_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: wan5_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: lan5_0: NIC Link is Up
>> 1000 Mbps Full Duplex, Flow Control: RX/TX
>>
>> This patch changes the IRQ tests to use polling loops starting with a
>> delay of 1 tick and doubling that if necessary up to a maximum total
>> delay of approximately 1 second.
>>
>> Signed-off-by: Prasanna S. Panchamukhi<ppanchamukhi@riverbed.com>
>> ---
>> drivers/net/ethernet/intel/e1000e/netdev.c | 27 +++++++++++++++++++++++----
>> 1 files changed, 23 insertions(+), 4 deletions(-)
> Thanks Prasanna, Dave did accept the previous patch, so does this patch
> take that into account?
No, If Dave has already accepted previous patch we can ignore this patch
for now.
Thanks,
Prasanna
>
>
^ permalink raw reply
* Re: [PATCH] e1000e: MSI interrupt test failed, using legacy interrupt
From: Jeff Kirsher @ 2012-04-27 0:20 UTC (permalink / raw)
To: prasanna.panchamukhi
Cc: bruce.w.allan, jeffrey.t.kirsher, jeffrey.e.pieper, bhutchings,
gospo, sassmann, jesse.brandeburg, e1000-devel, netdev
In-Reply-To: <1335485150-2765-1-git-send-email-prasanna.panchamukhi@riverbed.com>
[-- Attachment #1: Type: text/plain, Size: 2478 bytes --]
On 04/26/2012 05:05 PM, prasanna.panchamukhi@riverbed.com wrote:
> From: Prasanna S. Panchamukhi <ppanchamukhi@riverbed.com>
>
> Following logs where seen on Systems with multiple NICs & ports,
> while using MSI interrupts as shown below:
>
> Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0d.0: lan0_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: wan0_1: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: lan0_1: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:32 (none) user.warn kernel: 0000:40:0e.0: wan4_0: MSI interrupt
> test failed, using legacy interrupt.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0e.0: wan1_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0e.0: lan1_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: wan2_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: lan2_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: wan3_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: lan3_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0e.0: lan4_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: wan5_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
> Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: lan5_0: NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX/TX
>
> This patch changes the IRQ tests to use polling loops starting with a
> delay of 1 tick and doubling that if necessary up to a maximum total
> delay of approximately 1 second.
>
> Signed-off-by: Prasanna S. Panchamukhi <ppanchamukhi@riverbed.com>
> ---
> drivers/net/ethernet/intel/e1000e/netdev.c | 27 +++++++++++++++++++++++----
> 1 files changed, 23 insertions(+), 4 deletions(-)
Thanks Prasanna, Dave did accept the previous patch, so does this patch
take that into account?
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 900 bytes --]
^ permalink raw reply
* [PATCH] e1000e: MSI interrupt test failed, using legacy interrupt
From: prasanna.panchamukhi @ 2012-04-27 0:05 UTC (permalink / raw)
To: bruce.w.allan, jeffrey.t.kirsher, jeffrey.e.pieper, bhutchings,
gospo, sassmann, jesse.brandeburg
Cc: e1000-devel, netdev, prasanna.panchamukhi
From: Prasanna S. Panchamukhi <ppanchamukhi@riverbed.com>
Following logs where seen on Systems with multiple NICs & ports,
while using MSI interrupts as shown below:
Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0d.0: lan0_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: wan0_1: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:32 (none) user.notice kernel: 0000:40:0d.0: lan0_1: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:32 (none) user.warn kernel: 0000:40:0e.0: wan4_0: MSI interrupt
test failed, using legacy interrupt.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Feb 16 15:09:32 (none) user.notice kernel: 0000:00:0e.0: wan1_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0e.0: lan1_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: wan2_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:33 (none) user.notice kernel: 0000:00:0f.0: lan2_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: wan3_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:33 (none) user.notice kernel: 0000:40:0a.0: lan3_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0e.0: lan4_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: wan5_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
Feb 16 15:09:34 (none) user.notice kernel: 0000:40:0f.0: lan5_0: NIC Link is Up
1000 Mbps Full Duplex, Flow Control: RX/TX
This patch changes the IRQ tests to use polling loops starting with a
delay of 1 tick and doubling that if necessary up to a maximum total
delay of approximately 1 second.
Signed-off-by: Prasanna S. Panchamukhi <ppanchamukhi@riverbed.com>
---
drivers/net/ethernet/intel/e1000e/netdev.c | 27 +++++++++++++++++++++++----
1 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 19ab215..8ff0fff 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -98,6 +98,16 @@ struct e1000_reg_info {
#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
+/* IRQ latency can be enormous because:
+ * - All IRQs may be disabled on a CPU for a *long* time by e.g. a
+ * slow serial console or an old IDE driver doing error recovery
+ * - The PREEMPT_RT patches mostly deal with this, but also allow a
+ * tasklet or normal task to be given higher priority than our IRQ
+ * threads
+ * Try to avoid blaming the hardware for this.
+ */
+#define IRQ_TIMEOUT HZ
+
static const struct e1000_reg_info e1000_reg_info_tbl[] = {
/* General Registers */
@@ -3767,6 +3777,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
+ unsigned long timeout, wait;
int err;
/* poll_enable hasn't been called yet, so don't need disable */
@@ -3799,12 +3810,20 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
/* fire an unusual interrupt on the test handler */
ew32(ICS, E1000_ICS_RXSEQ);
e1e_flush();
- msleep(50);
-
+ timeout = jiffies + IRQ_TIMEOUT;
+ wait = 1;
+ e_dbg("Waiting for MSI interrupt!\n");
+ do {
+ schedule_timeout_uninterruptible(wait);
+ rmb();
+ if (!(adapter->flags & FLAG_MSI_TEST_FAILED))
+ goto success;
+ wait *= 2;
+ } while (time_before(jiffies, timeout));
+
+success:
e1000_irq_disable(adapter);
- rmb();
-
if (adapter->flags & FLAG_MSI_TEST_FAILED) {
adapter->int_mode = E1000E_INT_MODE_LEGACY;
e_info("MSI interrupt test failed, using legacy interrupt.\n");
--
1.7.0.4
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
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 related
* static_branch() for netpoll?
From: Stephen Hemminger @ 2012-04-26 23:22 UTC (permalink / raw)
To: Eric Dumazet, David Miller; +Cc: netdev
It would be good to use static_branch instead of the current logic used
to detect if traffic trapping is need for netpoll. Most distro's end up
enabling NETPOLL, yet most users never need it. Not sure about the locking
requirements since netpoll_rx() runs in both hard and soft irq context.
^ permalink raw reply
* [PATCH v4 3/3] decrement static keys on real destroy time
From: Glauber Costa @ 2012-04-26 22:51 UTC (permalink / raw)
To: cgroups
Cc: netdev, linux-kernel, Li Zefan, Tejun Heo, kamezawa.hiroyu,
linux-mm, devel, Glauber Costa, Johannes Weiner, Michal Hocko
In-Reply-To: <1335480667-8301-1-git-send-email-glommer@parallels.com>
We call the destroy function when a cgroup starts to be removed,
such as by a rmdir event.
However, because of our reference counters, some objects are still
inflight. Right now, we are decrementing the static_keys at destroy()
time, meaning that if we get rid of the last static_key reference,
some objects will still have charges, but the code to properly
uncharge them won't be run.
This becomes a problem specially if it is ever enabled again, because
now new charges will be added to the staled charges making keeping
it pretty much impossible.
We just need to be careful with the static branch activation:
since there is no particular preferred order of their activation,
we need to make sure that we only start using it after all
call sites are active. This is achieved by having a per-memcg
flag that is only updated after static_key_slow_inc() returns.
At this time, we are sure all sites are active.
This is made per-memcg, not global, for a reason:
it also has the effect of making socket accounting more
consistent. The first memcg to be limited will trigger static_key()
activation, therefore, accounting. But all the others will then be
accounted no matter what. After this patch, only limited memcgs
will have its sockets accounted.
[v2: changed a tcp limited flag for a generic proto limited flag ]
[v3: update the current active flag only after the static_key update ]
[v4: disarm_static_keys() inside free_work ]
[v5: got rid of tcp_limit_mutex, now in the static_key interface ]
Signed-off-by: Glauber Costa <glommer@parallels.com>
CC: Tejun Heo <tj@kernel.org>
CC: Li Zefan <lizefan@huawei.com>
CC: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
CC: Johannes Weiner <hannes@cmpxchg.org>
CC: Michal Hocko <mhocko@suse.cz>
---
include/net/sock.h | 9 +++++++++
mm/memcontrol.c | 26 ++++++++++++++++++++++++--
net/ipv4/tcp_memcontrol.c | 34 +++++++++++++++++++++++++++-------
3 files changed, 60 insertions(+), 9 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index b3ebe6b..c5a2010 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -914,6 +914,15 @@ struct cg_proto {
int *memory_pressure;
long *sysctl_mem;
/*
+ * active means it is currently active, and new sockets should
+ * be assigned to cgroups.
+ *
+ * activated means it was ever activated, and we need to
+ * disarm the static keys on destruction
+ */
+ bool activated;
+ bool active;
+ /*
* memcg field is used to find which memcg we belong directly
* Each memcg struct can hold more than one cg_proto, so container_of
* won't really cut.
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index b0076cc..3d004ee 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -404,6 +404,7 @@ void sock_update_memcg(struct sock *sk)
{
if (mem_cgroup_sockets_enabled) {
struct mem_cgroup *memcg;
+ struct cg_proto *cg_proto;
BUG_ON(!sk->sk_prot->proto_cgroup);
@@ -423,9 +424,10 @@ void sock_update_memcg(struct sock *sk)
rcu_read_lock();
memcg = mem_cgroup_from_task(current);
- if (!mem_cgroup_is_root(memcg)) {
+ cg_proto = sk->sk_prot->proto_cgroup(memcg);
+ if (!mem_cgroup_is_root(memcg) && cg_proto->active) {
mem_cgroup_get(memcg);
- sk->sk_cgrp = sk->sk_prot->proto_cgroup(memcg);
+ sk->sk_cgrp = cg_proto;
}
rcu_read_unlock();
}
@@ -442,6 +444,14 @@ void sock_release_memcg(struct sock *sk)
}
}
+static void disarm_static_keys(struct mem_cgroup *memcg)
+{
+#ifdef CONFIG_INET
+ if (memcg->tcp_mem.cg_proto.activated)
+ static_key_slow_dec(&memcg_socket_limit_enabled);
+#endif
+}
+
#ifdef CONFIG_INET
struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg)
{
@@ -452,6 +462,11 @@ struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg)
}
EXPORT_SYMBOL(tcp_proto_cgroup);
#endif /* CONFIG_INET */
+#else
+static inline void disarm_static_keys(struct mem_cgroup *memcg)
+{
+}
+
#endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */
static void drain_all_stock_async(struct mem_cgroup *memcg);
@@ -4836,6 +4851,13 @@ static void free_work(struct work_struct *work)
int size = sizeof(struct mem_cgroup);
memcg = container_of(work, struct mem_cgroup, work_freeing);
+ /*
+ * We need to make sure that (at least for now), the jump label
+ * destruction code runs outside of the cgroup lock. schedule_work()
+ * will guarantee this happens. Be careful if you need to move this
+ * disarm_static_keys around
+ */
+ disarm_static_keys(memcg);
if (size < PAGE_SIZE)
kfree(memcg);
else
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index 1517037..81004df 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -54,6 +54,8 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
cg_proto->sysctl_mem = tcp->tcp_prot_mem;
cg_proto->memory_allocated = &tcp->tcp_memory_allocated;
cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
+ cg_proto->active = false;
+ cg_proto->activated = false;
cg_proto->memcg = memcg;
return 0;
@@ -74,9 +76,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)
percpu_counter_destroy(&tcp->tcp_sockets_allocated);
val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
-
- if (val != RESOURCE_MAX)
- static_key_slow_dec(&memcg_socket_limit_enabled);
}
EXPORT_SYMBOL(tcp_destroy_cgroup);
@@ -107,10 +106,31 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
tcp->tcp_prot_mem[i] = min_t(long, val >> PAGE_SHIFT,
net->ipv4.sysctl_tcp_mem[i]);
- if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX)
- static_key_slow_dec(&memcg_socket_limit_enabled);
- else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX)
- static_key_slow_inc(&memcg_socket_limit_enabled);
+ if (val == RESOURCE_MAX)
+ cg_proto->active = false;
+ else if (val != RESOURCE_MAX) {
+ /*
+ * ->activated needs to be written after the static_key update.
+ * This is what guarantees that the socket activation function
+ * is the last one to run. See sock_update_memcg() for details,
+ * and note that we don't mark any socket as belonging to this
+ * memcg until that flag is up.
+ *
+ * We need to do this, because static_keys will span multiple
+ * sites, but we can't control their order. If we mark a socket
+ * as accounted, but the accounting functions are not patched in
+ * yet, we'll lose accounting.
+ *
+ * We never race with the readers in sock_update_memcg(), because
+ * when this value change, the code to process it is not patched in
+ * yet.
+ */
+ if (!cg_proto->activated) {
+ static_key_slow_inc(&memcg_socket_limit_enabled);
+ cg_proto->activated = true;
+ }
+ cg_proto->active = true;
+ }
return 0;
}
--
1.7.7.6
^ permalink raw reply related
* [PATCH v4 2/3] Always free struct memcg through schedule_work()
From: Glauber Costa @ 2012-04-26 22:51 UTC (permalink / raw)
To: cgroups
Cc: netdev, linux-kernel, Li Zefan, Tejun Heo, kamezawa.hiroyu,
linux-mm, devel, Glauber Costa, Johannes Weiner, Michal Hocko
In-Reply-To: <1335480667-8301-1-git-send-email-glommer@parallels.com>
Right now we free struct memcg with kfree right after a
rcu grace period, but defer it if we need to use vfree() to get
rid of that memory area. We do that by need, because we need vfree
to be called in a process context.
This patch unifies this behavior, by ensuring that even kfree will
happen in a separate thread. The goal is to have a stable place to
call the upcoming jump label destruction function outside the realm
of the complicated and quite far-reaching cgroup lock (that can't be
held when calling neither the cpu_hotplug.lock nor the jump_label_mutex)
Signed-off-by: Glauber Costa <glommer@parallels.com>
CC: Tejun Heo <tj@kernel.org>
CC: Li Zefan <lizefan@huawei.com>
CC: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
CC: Johannes Weiner <hannes@cmpxchg.org>
CC: Michal Hocko <mhocko@suse.cz>
---
mm/memcontrol.c | 24 +++++++++++++-----------
1 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7832b4d..b0076cc 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -245,8 +245,8 @@ struct mem_cgroup {
*/
struct rcu_head rcu_freeing;
/*
- * But when using vfree(), that cannot be done at
- * interrupt time, so we must then queue the work.
+ * We also need some space for a worker in deferred freeing.
+ * By the time we call it, rcu_freeing is not longer in use.
*/
struct work_struct work_freeing;
};
@@ -4826,23 +4826,28 @@ out_free:
}
/*
- * Helpers for freeing a vzalloc()ed mem_cgroup by RCU,
+ * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU,
* but in process context. The work_freeing structure is overlaid
* on the rcu_freeing structure, which itself is overlaid on memsw.
*/
-static void vfree_work(struct work_struct *work)
+static void free_work(struct work_struct *work)
{
struct mem_cgroup *memcg;
+ int size = sizeof(struct mem_cgroup);
memcg = container_of(work, struct mem_cgroup, work_freeing);
- vfree(memcg);
+ if (size < PAGE_SIZE)
+ kfree(memcg);
+ else
+ vfree(memcg);
}
-static void vfree_rcu(struct rcu_head *rcu_head)
+
+static void free_rcu(struct rcu_head *rcu_head)
{
struct mem_cgroup *memcg;
memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing);
- INIT_WORK(&memcg->work_freeing, vfree_work);
+ INIT_WORK(&memcg->work_freeing, free_work);
schedule_work(&memcg->work_freeing);
}
@@ -4868,10 +4873,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
free_mem_cgroup_per_zone_info(memcg, node);
free_percpu(memcg->stat);
- if (sizeof(struct mem_cgroup) < PAGE_SIZE)
- kfree_rcu(memcg, rcu_freeing);
- else
- call_rcu(&memcg->rcu_freeing, vfree_rcu);
+ call_rcu(&memcg->rcu_freeing, free_rcu);
}
static void mem_cgroup_get(struct mem_cgroup *memcg)
--
1.7.7.6
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH v4 1/3] make jump_labels wait while updates are in place
From: Glauber Costa @ 2012-04-26 22:51 UTC (permalink / raw)
To: cgroups
Cc: netdev, linux-kernel, Li Zefan, Tejun Heo, kamezawa.hiroyu,
linux-mm, devel, Glauber Costa, Johannes Weiner, Michal Hocko,
Ingo Molnar, Jason Baron
In-Reply-To: <1335480667-8301-1-git-send-email-glommer@parallels.com>
In mem cgroup, we need to guarantee that two concurrent updates
of the jump_label interface wait for each other. IOW, we can't have
other updates returning while the first one is still patching the
kernel around, otherwise we'll race.
I believe this is something that can fit well in the static branch
API, without noticeable disadvantages:
* in the common case, it will be a quite simple lock/unlock operation
* Every context that calls static_branch_slow* already expects to be
in sleeping context because it will mutex_lock the unlikely case.
* static_key_slow_inc is not expected to be called in any fast path,
otherwise it would be expected to have quite a different name. Therefore
the mutex + atomic combination instead of just an atomic should not kill
us.
Signed-off-by: Glauber Costa <glommer@parallels.com>
CC: Tejun Heo <tj@kernel.org>
CC: Li Zefan <lizefan@huawei.com>
CC: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
CC: Johannes Weiner <hannes@cmpxchg.org>
CC: Michal Hocko <mhocko@suse.cz>
CC: Ingo Molnar <mingo@elte.hu>
CC: Jason Baron <jbaron@redhat.com>
---
kernel/jump_label.c | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index 4304919..5d09cb4 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -57,17 +57,16 @@ static void jump_label_update(struct static_key *key, int enable);
void static_key_slow_inc(struct static_key *key)
{
+ jump_label_lock();
if (atomic_inc_not_zero(&key->enabled))
- return;
+ goto out;
- jump_label_lock();
- if (atomic_read(&key->enabled) == 0) {
- if (!jump_label_get_branch_default(key))
- jump_label_update(key, JUMP_LABEL_ENABLE);
- else
- jump_label_update(key, JUMP_LABEL_DISABLE);
- }
+ if (!jump_label_get_branch_default(key))
+ jump_label_update(key, JUMP_LABEL_ENABLE);
+ else
+ jump_label_update(key, JUMP_LABEL_DISABLE);
atomic_inc(&key->enabled);
+out:
jump_label_unlock();
}
EXPORT_SYMBOL_GPL(static_key_slow_inc);
@@ -75,10 +74,11 @@ EXPORT_SYMBOL_GPL(static_key_slow_inc);
static void __static_key_slow_dec(struct static_key *key,
unsigned long rate_limit, struct delayed_work *work)
{
- if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) {
+ jump_label_lock();
+ if (atomic_dec_and_test(&key->enabled)) {
WARN(atomic_read(&key->enabled) < 0,
"jump label: negative count!\n");
- return;
+ goto out;
}
if (rate_limit) {
@@ -90,6 +90,7 @@ static void __static_key_slow_dec(struct static_key *key,
else
jump_label_update(key, JUMP_LABEL_ENABLE);
}
+out:
jump_label_unlock();
}
--
1.7.7.6
^ permalink raw reply related
* [PATCH v4 0/3] fix problem with static_branch() for sock memcg
From: Glauber Costa @ 2012-04-26 22:51 UTC (permalink / raw)
To: cgroups
Cc: netdev, linux-kernel, Li Zefan, Tejun Heo, kamezawa.hiroyu,
linux-mm, devel
Hi,
While trying to fulfill's Christoph's request for using static_branches
to do part of the role of number_of_cpusets in the cpuset cgroup, I took
a much more extensive look at the cpuset code (Thanks Christoph).
I started to feel that removing the cgroup_lock() from cpuset's
destroy is not as safe as I first imagined. At the very best, is not safe
enough to be bundled in a bugfix and deserves its own analysis.
I started then to consider another approach. While I voiced many times
that I would not like to do deferred updates for the static_branches, doing
that during destroy time would be perfectly acceptable IMHO (creation is
another story). In a summary, we are effectively calling the static_branch
updates only when the last reference to the memcg is gone. And that is
already asynchronous by nature, and we cope well with that.
In memcg, it turns out that we already do deferred freeing of the memcg
structure depending on the size of struct mem_cgroup.
My proposal is to always do that, and then we get a worker more or less
for free. Patch 3 is basically the same I had posted before, but without
the mutex lock protection, now in the static branch guaranteed interface.
Let me know if this is acceptable.
Thanks
Glauber Costa (3):
make jump_labels wait while updates are in place
Always free struct memcg through schedule_work()
decrement static keys on real destroy time
include/net/sock.h | 9 ++++++++
kernel/jump_label.c | 13 ++++++++---
mm/memcontrol.c | 50 +++++++++++++++++++++++++++++++++-----------
net/ipv4/tcp_memcontrol.c | 34 ++++++++++++++++++++++++------
4 files changed, 82 insertions(+), 24 deletions(-)
--
1.7.7.6
^ permalink raw reply
* Re: [PATCH v3 2/2] decrement static keys on real destroy time
From: Tejun Heo @ 2012-04-26 22:32 UTC (permalink / raw)
To: Glauber Costa
Cc: cgroups-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
Li Zefan, kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A,
linux-mm-Bw31MaZKKs3YtjvyW6yDsg, devel-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <4F99CC17.4080006-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
On Thu, Apr 26, 2012 at 3:28 PM, Glauber Costa <glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org> wrote:
> We need a broader audience for this, but if I understand the interface
> right, those functions should not be called in fast paths at all (contrary
> to the static_branch tests)
>
> The static_branch tests can be called from irq context, so we can't just get
> rid of the atomic op and use the mutex everywhere, we'd have
> to live with both.
>
> I will repost this series, with some more people in the CC list.
Great, thanks!
--
tejun
^ 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