* [PATCH v8 1/2] Ethernet driver for the WIZnet W5300 chip
From: Mike Sinkovsky @ 2012-04-04 11:57 UTC (permalink / raw)
To: netdev, linux-kernel, broonie; +Cc: Mike Sinkovsky, Mike Sinkovsky
In-Reply-To: <1333524216-23488-1-git-send-email-msink@permonline.ru>
Based on original driver from chip manufacturer, but nearly full rewite.
Tested and used in production with Blackfin BF531 embedded processor.
Signed-off-by: Mike Sinkovsky <msink@permonline.ru>
---
drivers/net/ethernet/wiznet/Kconfig | 64 +++
drivers/net/ethernet/wiznet/Makefile | 1 +
drivers/net/ethernet/wiznet/w5300.c | 720 ++++++++++++++++++++++++++++++++++
include/linux/platform_data/wiznet.h | 24 ++
4 files changed, 809 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/ethernet/wiznet/Kconfig
create mode 100644 drivers/net/ethernet/wiznet/Makefile
create mode 100644 drivers/net/ethernet/wiznet/w5300.c
create mode 100644 include/linux/platform_data/wiznet.h
diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig
new file mode 100644
index 0000000..364292b
--- /dev/null
+++ b/drivers/net/ethernet/wiznet/Kconfig
@@ -0,0 +1,64 @@
+#
+# WIZnet devices configuration
+#
+
+config NET_VENDOR_WIZNET
+ bool "WIZnet devices"
+ default y
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about WIZnet devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_WIZNET
+
+config WIZNET_W5300
+ tristate "WIZnet W5300 Ethernet support"
+ ---help---
+ Support for WIZnet W5300 chips.
+
+ W5300 is a single chip with integrated 10/100 Ethernet MAC,
+ PHY and hardware TCP/IP stack, but this driver is limited to
+ the MAC and PHY functions only, onchip TCP/IP is unused.
+
+ To compile this driver as a module, choose M here: the module
+ will be called w5300.
+
+choice
+ prompt "WIZnet interface mode"
+ default WIZNET_BUS_ANY
+
+config WIZNET_BUS_DIRECT
+ bool "Direct address bus mode"
+ ---help---
+ In direct address mode host system can directly access all registers
+ after mapping to Memory-Mapped I/O space.
+
+config WIZNET_BUS_INDIRECT
+ bool "Indirect address bus mode"
+ ---help---
+ In indirect address mode host system indirectly accesses registers
+ using Indirect Mode Address Register and Indirect Mode Data Register,
+ which are directly mapped to Memory-Mapped I/O space.
+
+config WIZNET_BUS_ANY
+ bool "Select interface mode in runtime"
+ ---help---
+ If interface mode is unknown in compile time, it can be selected
+ in runtime from board/platform resources configuration.
+
+ Performance may decrease compared to explicitly selected bus mode.
+endchoice
+
+config WIZNET_TX_FLOW
+ bool "Use transmit flow control"
+ help
+ This enables transmit flow control for WIZnet chips.
+ If unsure, say Y.
+
+endif # NET_VENDOR_WIZNET
diff --git a/drivers/net/ethernet/wiznet/Makefile b/drivers/net/ethernet/wiznet/Makefile
new file mode 100644
index 0000000..88e0a3e
--- /dev/null
+++ b/drivers/net/ethernet/wiznet/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_WIZNET_W5300) += w5300.o
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
new file mode 100644
index 0000000..f35a101
--- /dev/null
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -0,0 +1,720 @@
+/*
+ * Ethernet driver for the WIZnet W5300 chip.
+ *
+ * Copyright (C) 2008-2009 WIZnet Co.,Ltd.
+ * Copyright (C) 2011 Taehun Kim <kth3321 <at> gmail.com>
+ * Copyright (C) 2012 Mike Sinkovsky <msink@permonline.ru>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kconfig.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/wiznet.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#define DRV_NAME "w5300"
+#define DRV_VERSION "2012-04-04"
+
+MODULE_DESCRIPTION("WIZnet W5300 Ethernet driver v"DRV_VERSION);
+MODULE_AUTHOR("Mike Sinkovsky <msink@permonline.ru>");
+MODULE_ALIAS("platform:"DRV_NAME);
+MODULE_LICENSE("GPL");
+
+/*
+ * Registers
+ */
+#define W5300_MR 0x0000 /* Mode Register */
+#define MR_DBW (1 << 15) /* Data bus width */
+#define MR_MPF (1 << 14) /* Mac layer pause frame */
+#define MR_WDF(n) (((n)&7)<<11) /* Write data fetch time */
+#define MR_RDH (1 << 10) /* Read data hold time */
+#define MR_FS (1 << 8) /* FIFO swap */
+#define MR_RST (1 << 7) /* S/W reset */
+#define MR_PB (1 << 4) /* Ping block */
+#define MR_DBS (1 << 2) /* Data bus swap */
+#define MR_IND (1 << 0) /* Indirect mode */
+#define W5300_IR 0x0002 /* Interrupt Register */
+#define W5300_IMR 0x0004 /* Interrupt Mask Register */
+#define IR_S0 0x0001 /* S0 interrupt */
+#define W5300_SHARL 0x0008 /* Source MAC address (0123) */
+#define W5300_SHARH 0x000c /* Source MAC address (45) */
+#define W5300_TMSRL 0x0020 /* Transmit Memory Size (0123) */
+#define W5300_TMSRH 0x0024 /* Transmit Memory Size (4567) */
+#define W5300_RMSRL 0x0028 /* Receive Memory Size (0123) */
+#define W5300_RMSRH 0x002c /* Receive Memory Size (4567) */
+#define W5300_MTYPE 0x0030 /* Memory Type */
+#define W5300_IDR 0x00fe /* Chip ID register */
+#define IDR_W5300 0x5300 /* =0x5300 for WIZnet W5300 */
+#define W5300_S0_MR 0x0200 /* S0 Mode Register */
+#define S0_MR_CLOSED 0x0000 /* Close mode */
+#define S0_MR_MACRAW 0x0004 /* MAC RAW mode (promiscous) */
+#define S0_MR_MACRAW_MF 0x0044 /* MAC RAW mode (filtered) */
+#define W5300_S0_CR 0x0202 /* S0 Command Register */
+#define S0_CR_OPEN 0x0001 /* OPEN command */
+#define S0_CR_CLOSE 0x0010 /* CLOSE command */
+#define S0_CR_SEND 0x0020 /* SEND command */
+#define S0_CR_RECV 0x0040 /* RECV command */
+#define W5300_S0_IMR 0x0204 /* S0 Interrupt Mask Register */
+#define W5300_S0_IR 0x0206 /* S0 Interrupt Register */
+#define S0_IR_RECV 0x0004 /* Receive interrupt */
+#define S0_IR_SENDOK 0x0010 /* Send OK interrupt */
+#define W5300_S0_SSR 0x0208 /* S0 Socket Status Register */
+#define W5300_S0_TX_WRSR 0x0220 /* S0 TX Write Size Register */
+#define W5300_S0_TX_FSR 0x0224 /* S0 TX Free Size Register */
+#define W5300_S0_RX_RSR 0x0228 /* S0 Received data Size */
+#define W5300_S0_TX_FIFO 0x022e /* S0 Transmit FIFO */
+#define W5300_S0_RX_FIFO 0x0230 /* S0 Receive FIFO */
+#define W5300_REGS_LEN 0x0400
+
+/*
+ * Device driver private data structure
+ */
+struct w5300_priv {
+ void __iomem *base;
+ spinlock_t reg_lock;
+ bool indirect;
+ u16 (*read) (struct w5300_priv *priv, u16 addr);
+ void (*write)(struct w5300_priv *priv, u16 addr, u16 data);
+ int irq;
+ int link_irq;
+ int link_gpio;
+
+ struct napi_struct napi;
+ struct net_device *ndev;
+ bool promisc;
+ u32 msg_enable;
+};
+
+/************************************************************************
+ *
+ * Lowlevel I/O functions
+ *
+ ***********************************************************************/
+
+/*
+ * In direct address mode host system can directly access W5300 registers
+ * after mapping to Memory-Mapped I/O space.
+ *
+ * 0x400 bytes are required for memory space.
+ */
+static inline u16 w5300_read_direct(struct w5300_priv *priv, u16 addr)
+{
+ return ioread16(priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT));
+}
+
+static inline void w5300_write_direct(struct w5300_priv *priv,
+ u16 addr, u16 data)
+{
+ iowrite16(data, priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT));
+}
+
+/*
+ * In indirect address mode host system indirectly accesses registers by
+ * using Indirect Mode Address Register (IDM_AR) and Indirect Mode Data
+ * Register (IDM_DR), which are directly mapped to Memory-Mapped I/O space.
+ * Mode Register (MR) is directly accessible.
+ *
+ * Only 0x06 bytes are required for memory space.
+ */
+#define W5300_IDM_AR 0x0002 /* Indirect Mode Address */
+#define W5300_IDM_DR 0x0004 /* Indirect Mode Data */
+
+static u16 w5300_read_indirect(struct w5300_priv *priv, u16 addr)
+{
+ unsigned long flags;
+ u16 data;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5300_write_direct(priv, W5300_IDM_AR, addr);
+ mmiowb();
+ data = w5300_read_direct(priv, W5300_IDM_DR);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+ return data;
+}
+
+static void w5300_write_indirect(struct w5300_priv *priv, u16 addr, u16 data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5300_write_direct(priv, W5300_IDM_AR, addr);
+ mmiowb();
+ w5300_write_direct(priv, W5300_IDM_DR, data);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+#if defined(CONFIG_WIZNET_BUS_DIRECT)
+#define w5300_read w5300_read_direct
+#define w5300_write w5300_write_direct
+
+#elif defined(CONFIG_WIZNET_BUS_INDIRECT)
+#define w5300_read w5300_read_indirect
+#define w5300_write w5300_write_indirect
+
+#else /* CONFIG_WIZNET_BUS_ANY */
+#define w5300_read priv->read
+#define w5300_write priv->write
+#endif
+
+static u32 w5300_read32(struct w5300_priv *priv, u16 addr)
+{
+ u32 data;
+ data = w5300_read(priv, addr) << 16;
+ data |= w5300_read(priv, addr + 2);
+ return data;
+}
+
+static void w5300_write32(struct w5300_priv *priv, u16 addr, u32 data)
+{
+ w5300_write(priv, addr, data >> 16);
+ w5300_write(priv, addr + 2, data);
+}
+
+static int w5300_command(struct w5300_priv *priv, u16 cmd)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+ w5300_write(priv, W5300_S0_CR, cmd);
+ mmiowb();
+
+ while (w5300_read(priv, W5300_S0_CR) != 0) {
+ if (time_after(jiffies, timeout))
+ return -EIO;
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static void w5300_read_frame(struct w5300_priv *priv, u8 *buf, int len)
+{
+ u16 fifo;
+ int i;
+
+ for (i = 0; i < len; i += 2) {
+ fifo = w5300_read(priv, W5300_S0_RX_FIFO);
+ *buf++ = fifo >> 8;
+ *buf++ = fifo;
+ }
+ fifo = w5300_read(priv, W5300_S0_RX_FIFO);
+ fifo = w5300_read(priv, W5300_S0_RX_FIFO);
+}
+
+static void w5300_write_frame(struct w5300_priv *priv, u8 *buf, int len)
+{
+ u16 fifo;
+ int i;
+
+ for (i = 0; i < len; i += 2) {
+ fifo = *buf++ << 8;
+ fifo |= *buf++;
+ w5300_write(priv, W5300_S0_TX_FIFO, fifo);
+ }
+ w5300_write32(priv, W5300_S0_TX_WRSR, len);
+}
+
+static void w5300_write_macaddr(struct w5300_priv *priv)
+{
+ struct net_device *ndev = priv->ndev;
+ w5300_write32(priv, W5300_SHARL,
+ ndev->dev_addr[0] << 24 |
+ ndev->dev_addr[1] << 16 |
+ ndev->dev_addr[2] << 8 |
+ ndev->dev_addr[3]);
+ w5300_write(priv, W5300_SHARH,
+ ndev->dev_addr[4] << 8 |
+ ndev->dev_addr[5]);
+ mmiowb();
+}
+
+static void w5300_hw_reset(struct w5300_priv *priv)
+{
+ w5300_write_direct(priv, W5300_MR, MR_RST);
+ mmiowb();
+ mdelay(5);
+ w5300_write_direct(priv, W5300_MR, priv->indirect ?
+ MR_WDF(7) | MR_PB | MR_IND :
+ MR_WDF(7) | MR_PB);
+ mmiowb();
+ w5300_write(priv, W5300_IMR, 0);
+ w5300_write_macaddr(priv);
+
+ /* Configure 128K of internal memory
+ * as 64K RX fifo and 64K TX fifo
+ */
+ w5300_write32(priv, W5300_RMSRL, 64 << 24);
+ w5300_write32(priv, W5300_RMSRH, 0);
+ w5300_write32(priv, W5300_TMSRL, 64 << 24);
+ w5300_write32(priv, W5300_TMSRH, 0);
+ w5300_write(priv, W5300_MTYPE, 0x00ff);
+ mmiowb();
+}
+
+static void w5300_hw_start(struct w5300_priv *priv)
+{
+ w5300_write(priv, W5300_S0_MR, priv->promisc ?
+ S0_MR_MACRAW : S0_MR_MACRAW_MF);
+ mmiowb();
+ w5300_command(priv, S0_CR_OPEN);
+ w5300_write(priv, W5300_S0_IMR, IS_ENABLED(CONFIG_WIZNET_TX_FLOW) ?
+ S0_IR_RECV | S0_IR_SENDOK :
+ S0_IR_RECV);
+ w5300_write(priv, W5300_IMR, IR_S0);
+ mmiowb();
+}
+
+static void w5300_hw_close(struct w5300_priv *priv)
+{
+ w5300_write(priv, W5300_IMR, 0);
+ mmiowb();
+ w5300_command(priv, S0_CR_CLOSE);
+}
+
+/***********************************************************************
+ *
+ * Device driver functions / callbacks
+ *
+ ***********************************************************************/
+
+static void w5300_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, dev_name(ndev->dev.parent),
+ sizeof(info->bus_info));
+}
+
+static u32 w5300_get_link(struct net_device *ndev)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ if (gpio_is_valid(priv->link_gpio))
+ return !!gpio_get_value(priv->link_gpio);
+
+ return 1;
+}
+
+static u32 w5300_get_msglevel(struct net_device *ndev)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ return priv->msg_enable;
+}
+
+static void w5300_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ priv->msg_enable = value;
+}
+
+static int w5300_get_regs_len(struct net_device *ndev)
+{
+ return W5300_REGS_LEN;
+}
+
+static void w5300_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *_buf)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+ u8 *buf = _buf;
+ u16 addr;
+ u16 data;
+
+ regs->version = 1;
+ for (addr = 0; addr < W5300_REGS_LEN; addr += 2) {
+ switch (addr & 0x23f) {
+ case W5300_S0_TX_FIFO: /* cannot read TX_FIFO */
+ case W5300_S0_RX_FIFO: /* cannot read RX_FIFO */
+ data = 0xffff;
+ break;
+ default:
+ data = w5300_read(priv, addr);
+ break;
+ }
+ *buf++ = data >> 8;
+ *buf++ = data;
+ }
+}
+
+static void w5300_tx_timeout(struct net_device *ndev)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ w5300_hw_reset(priv);
+ w5300_hw_start(priv);
+ ndev->stats.tx_errors++;
+ ndev->trans_start = jiffies;
+ netif_wake_queue(ndev);
+}
+
+static int w5300_start_tx(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ if (IS_ENABLED(CONFIG_WIZNET_TX_FLOW))
+ netif_stop_queue(ndev);
+
+ w5300_write_frame(priv, skb->data, skb->len);
+ mmiowb();
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+ dev_kfree_skb(skb);
+ netif_dbg(priv, tx_queued, ndev, "tx queued\n");
+
+ w5300_command(priv, S0_CR_SEND);
+
+ return NETDEV_TX_OK;
+}
+
+static int w5300_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct w5300_priv *priv = container_of(napi, struct w5300_priv, napi);
+ struct net_device *ndev = priv->ndev;
+ struct sk_buff *skb;
+ int rx_count;
+ u16 rx_len;
+
+ for (rx_count = 0; rx_count < budget; rx_count++) {
+ u32 rx_fifo_len = w5300_read32(priv, W5300_S0_RX_RSR);
+ if (rx_fifo_len == 0)
+ break;
+
+ rx_len = w5300_read(priv, W5300_S0_RX_FIFO);
+
+ skb = netdev_alloc_skb_ip_align(ndev, roundup(rx_len, 2));
+ if (unlikely(!skb)) {
+ u32 i;
+ for (i = 0; i < rx_fifo_len; i += 2)
+ w5300_read(priv, W5300_S0_RX_FIFO);
+ ndev->stats.rx_dropped++;
+ return -ENOMEM;
+ }
+
+ skb_put(skb, rx_len);
+ w5300_read_frame(priv, skb->data, rx_len);
+ skb->protocol = eth_type_trans(skb, ndev);
+
+ netif_receive_skb(skb);
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += rx_len;
+ }
+
+ if (rx_count < budget) {
+ w5300_write(priv, W5300_IMR, IR_S0);
+ mmiowb();
+ napi_complete(napi);
+ }
+
+ return rx_count;
+}
+
+static irqreturn_t w5300_interrupt(int irq, void *ndev_instance)
+{
+ struct net_device *ndev = ndev_instance;
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ int ir = w5300_read(priv, W5300_S0_IR);
+ if (!ir)
+ return IRQ_NONE;
+ w5300_write(priv, W5300_S0_IR, ir);
+ mmiowb();
+
+ if (IS_ENABLED(CONFIG_WIZNET_TX_FLOW) && (ir & S0_IR_SENDOK)) {
+ netif_dbg(priv, tx_done, ndev, "tx done\n");
+ netif_wake_queue(ndev);
+ }
+
+ if (ir & S0_IR_RECV) {
+ if (napi_schedule_prep(&priv->napi)) {
+ w5300_write(priv, W5300_IMR, 0);
+ mmiowb();
+ __napi_schedule(&priv->napi);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t w5300_detect_link(int irq, void *ndev_instance)
+{
+ struct net_device *ndev = ndev_instance;
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ if (gpio_get_value(priv->link_gpio) != 0) {
+ netif_info(priv, link, ndev, "link is up\n");
+ netif_carrier_on(ndev);
+ } else {
+ netif_info(priv, link, ndev, "link is down\n");
+ netif_carrier_off(ndev);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void w5300_set_rx_mode(struct net_device *ndev)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+ bool set_promisc = (ndev->flags & IFF_PROMISC) != 0;
+
+ if (priv->promisc != set_promisc) {
+ priv->promisc = set_promisc;
+ w5300_hw_start(priv);
+ }
+}
+
+static int w5300_set_macaddr(struct net_device *ndev, void *addr)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+ struct sockaddr *sock_addr = addr;
+
+ if (!is_valid_ether_addr(sock_addr->sa_data))
+ return -EADDRNOTAVAIL;
+ memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN);
+ ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
+ w5300_write_macaddr(priv);
+ return 0;
+}
+
+static int w5300_open(struct net_device *ndev)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ netif_info(priv, ifup, ndev, "enabling\n");
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ return -EINVAL;
+ w5300_hw_start(priv);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+ if (!gpio_is_valid(priv->link_gpio) ||
+ gpio_get_value(priv->link_gpio) != 0)
+ netif_carrier_on(ndev);
+ return 0;
+}
+
+static int w5300_stop(struct net_device *ndev)
+{
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ netif_info(priv, ifdown, ndev, "shutting down\n");
+ w5300_hw_close(priv);
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+ return 0;
+}
+
+static const struct ethtool_ops w5300_ethtool_ops = {
+ .get_drvinfo = w5300_get_drvinfo,
+ .get_msglevel = w5300_get_msglevel,
+ .set_msglevel = w5300_set_msglevel,
+ .get_link = w5300_get_link,
+ .get_regs_len = w5300_get_regs_len,
+ .get_regs = w5300_get_regs,
+};
+
+static const struct net_device_ops w5300_netdev_ops = {
+ .ndo_open = w5300_open,
+ .ndo_stop = w5300_stop,
+ .ndo_start_xmit = w5300_start_tx,
+ .ndo_tx_timeout = w5300_tx_timeout,
+ .ndo_set_rx_mode = w5300_set_rx_mode,
+ .ndo_set_mac_address = w5300_set_macaddr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static int __devinit w5300_hw_probe(struct platform_device *pdev)
+{
+ struct wiznet_platform_data *data = pdev->dev.platform_data;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5300_priv *priv = netdev_priv(ndev);
+ const char *name = netdev_name(ndev);
+ struct resource *mem;
+ int mem_size;
+ int irq;
+ int ret;
+
+ if (data && is_valid_ether_addr(data->mac_addr)) {
+ memcpy(ndev->dev_addr, data->mac_addr, ETH_ALEN);
+ } else {
+ random_ether_addr(ndev->dev_addr);
+ ndev->addr_assign_type |= NET_ADDR_RANDOM;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENXIO;
+ mem_size = resource_size(mem);
+ if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name))
+ return -EBUSY;
+ priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size);
+ if (!priv->base)
+ return -EBUSY;
+
+ spin_lock_init(&priv->reg_lock);
+ priv->indirect = mem_size < W5300_BUS_DIRECT_SIZE;
+ if (priv->indirect) {
+ priv->read = w5300_read_indirect;
+ priv->write = w5300_write_indirect;
+ } else {
+ priv->read = w5300_read_direct;
+ priv->write = w5300_write_direct;
+ }
+
+ w5300_hw_reset(priv);
+ if (w5300_read(priv, W5300_IDR) != IDR_W5300)
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ ret = request_irq(irq, w5300_interrupt,
+ IRQ_TYPE_LEVEL_LOW, name, ndev);
+ if (ret < 0)
+ return ret;
+ priv->irq = irq;
+
+ priv->link_gpio = data->link_gpio;
+ if (gpio_is_valid(priv->link_gpio)) {
+ char *link_name = devm_kzalloc(&pdev->dev, 16, GFP_KERNEL);
+ if (!link_name)
+ return -ENOMEM;
+ snprintf(link_name, 16, "%s-link", name);
+ priv->link_irq = gpio_to_irq(priv->link_gpio);
+ if (request_any_context_irq(priv->link_irq, w5300_detect_link,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ link_name, priv->ndev) < 0)
+ priv->link_gpio = -EINVAL;
+ }
+
+ netdev_info(ndev, "at 0x%llx irq %d\n", (u64)mem->start, irq);
+ return 0;
+}
+
+static int __devinit w5300_probe(struct platform_device *pdev)
+{
+ struct w5300_priv *priv;
+ struct net_device *ndev;
+ int err;
+
+ ndev = alloc_etherdev(sizeof(*priv));
+ if (!ndev)
+ return -ENOMEM;
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ platform_set_drvdata(pdev, ndev);
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+
+ ether_setup(ndev);
+ ndev->netdev_ops = &w5300_netdev_ops;
+ ndev->ethtool_ops = &w5300_ethtool_ops;
+ ndev->watchdog_timeo = HZ;
+ netif_napi_add(ndev, &priv->napi, w5300_napi_poll, 16);
+
+ /* This chip doesn't support VLAN packets with normal MTU,
+ * so disable VLAN for this device.
+ */
+ ndev->features |= NETIF_F_VLAN_CHALLENGED;
+
+ err = register_netdev(ndev);
+ if (err < 0)
+ goto err_register;
+
+ err = w5300_hw_probe(pdev);
+ if (err < 0)
+ goto err_hw_probe;
+
+ return 0;
+
+err_hw_probe:
+ unregister_netdev(ndev);
+err_register:
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static int __devexit w5300_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ w5300_hw_reset(priv);
+ free_irq(priv->irq, ndev);
+ if (gpio_is_valid(priv->link_gpio))
+ free_irq(priv->link_irq, ndev);
+
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int w5300_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ netif_carrier_off(ndev);
+ netif_device_detach(ndev);
+
+ w5300_hw_close(priv);
+ }
+ return 0;
+}
+
+static int w5300_resume(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5300_priv *priv = netdev_priv(ndev);
+
+ if (!netif_running(ndev)) {
+ w5300_hw_reset(priv);
+ w5300_hw_start(priv);
+
+ netif_device_attach(ndev);
+ if (!gpio_is_valid(priv->link_gpio) ||
+ gpio_get_value(priv->link_gpio) != 0)
+ netif_carrier_on(ndev);
+ }
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(w5300_pm_ops, w5300_suspend, w5300_resume);
+
+static struct platform_driver w5300_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &w5300_pm_ops,
+ },
+ .probe = w5300_probe,
+ .remove = __devexit_p(w5300_remove),
+};
+
+module_platform_driver(w5300_driver);
diff --git a/include/linux/platform_data/wiznet.h b/include/linux/platform_data/wiznet.h
new file mode 100644
index 0000000..b5d8c19
--- /dev/null
+++ b/include/linux/platform_data/wiznet.h
@@ -0,0 +1,24 @@
+/*
+ * Ethernet driver for the WIZnet W5x00 chip.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef PLATFORM_DATA_WIZNET_H
+#define PLATFORM_DATA_WIZNET_H
+
+#include <linux/if_ether.h>
+
+struct wiznet_platform_data {
+ int link_gpio;
+ u8 mac_addr[ETH_ALEN];
+};
+
+#ifndef CONFIG_WIZNET_BUS_SHIFT
+#define CONFIG_WIZNET_BUS_SHIFT 0
+#endif
+
+#define W5100_BUS_DIRECT_SIZE (0x8000 << CONFIG_WIZNET_BUS_SHIFT)
+#define W5300_BUS_DIRECT_SIZE (0x0400 << CONFIG_WIZNET_BUS_SHIFT)
+
+#endif /* PLATFORM_DATA_WIZNET_H */
--
1.6.3.3
^ permalink raw reply related
* [PATCH v8 0/2] Ethernet drivers for WIZnet chips
From: Mike Sinkovsky @ 2012-04-04 11:57 UTC (permalink / raw)
To: netdev, linux-kernel, broonie; +Cc: Mike Sinkovsky
In-Reply-To: <1333524216-23488-1-git-send-email-msink@permonline.ru>
From: Mike Sinkovsky <msink@permonline.ru>
Based on original driver from chip manufacturer, but nearly full rewite.
Tested and used in production with Blackfin BF531 embedded processor.
Signed-off-by: Mike Sinkovsky <msink@permonline.ru>
---
v8:
- use plain request_irq() and request_any_context_irq() in probe(),
and free_irq() in remove(), to avoid races when removing driver
v7:
- new tx flow control, configurable from Kconfig
v6:
- remove (S0_TX_FSR < skb->len) check in TX handler, it doesn't work
anyway. Chip can transmit only one frame with MTU 1500 at a time,
and tx buffer size is bigger.
- move link_gpio from RES_IO resource to wiznet_platform_data
- remove dependency (ARM || BLACKFIN) - should work on any arch
- interrupt handler returns IRQ_NONE if status register is zero
- use devm_request_threaded_irq for request detect_link handler
- remove dev_info if probe failed
v5:
- added driver for WIZnet W5100
- disabled VLAN (NETIF_F_VLAN_CHALLENGED)
v4:
- netif_stop_queue if tx fifo is full, netif_wake_queue in interrupt
- use netif_info macro
v3:
- reading macaddr from platform_data
- ethtool: get_link, get_msglevel, set_msglevel
- more cleanups
v2:
- corrected handling of NET_ADDR_RANDOM flag
- support for WIZNET_BUS_ANY mode
- link detection using gpio
- registers read using ethtool
- more cleanups
^ permalink raw reply
* bridge: Do not send queries on multicast group leaves
From: Herbert Xu @ 2012-04-04 11:01 UTC (permalink / raw)
To: David S. Miller, netdev
Hi:
bridge: Do not send queries on multicast group leaves
As it stands the bridge IGMP snooping system will respond to
group leave messages with queries for remaining membership.
This is both unnecessary and undesirable. First of all any
multicast routers present should be doing this rather than us.
What's more the queries that we send may end up upsetting other
multicast snooping swithces in the system that are buggy.
In fact, we can simply remove the code that send these queries
because the existing membership expiry mechanism doesn't rely
on them anyway.
So this patch simply removes all code associated with group
queries in response to group leave messages.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 702a1ae..27ca25e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -241,7 +241,6 @@ static void br_multicast_group_expired(unsigned long data)
hlist_del_rcu(&mp->hlist[mdb->ver]);
mdb->size--;
- del_timer(&mp->query_timer);
call_rcu_bh(&mp->rcu, br_multicast_free_group);
out:
@@ -271,7 +270,6 @@ static void br_multicast_del_pg(struct net_bridge *br,
rcu_assign_pointer(*pp, p->next);
hlist_del_init(&p->mglist);
del_timer(&p->timer);
- del_timer(&p->query_timer);
call_rcu_bh(&p->rcu, br_multicast_free_pg);
if (!mp->ports && !mp->mglist &&
@@ -507,74 +505,6 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
return NULL;
}
-static void br_multicast_send_group_query(struct net_bridge_mdb_entry *mp)
-{
- struct net_bridge *br = mp->br;
- struct sk_buff *skb;
-
- skb = br_multicast_alloc_query(br, &mp->addr);
- if (!skb)
- goto timer;
-
- netif_rx(skb);
-
-timer:
- if (++mp->queries_sent < br->multicast_last_member_count)
- mod_timer(&mp->query_timer,
- jiffies + br->multicast_last_member_interval);
-}
-
-static void br_multicast_group_query_expired(unsigned long data)
-{
- struct net_bridge_mdb_entry *mp = (void *)data;
- struct net_bridge *br = mp->br;
-
- spin_lock(&br->multicast_lock);
- if (!netif_running(br->dev) || !mp->mglist ||
- mp->queries_sent >= br->multicast_last_member_count)
- goto out;
-
- br_multicast_send_group_query(mp);
-
-out:
- spin_unlock(&br->multicast_lock);
-}
-
-static void br_multicast_send_port_group_query(struct net_bridge_port_group *pg)
-{
- struct net_bridge_port *port = pg->port;
- struct net_bridge *br = port->br;
- struct sk_buff *skb;
-
- skb = br_multicast_alloc_query(br, &pg->addr);
- if (!skb)
- goto timer;
-
- br_deliver(port, skb);
-
-timer:
- if (++pg->queries_sent < br->multicast_last_member_count)
- mod_timer(&pg->query_timer,
- jiffies + br->multicast_last_member_interval);
-}
-
-static void br_multicast_port_group_query_expired(unsigned long data)
-{
- struct net_bridge_port_group *pg = (void *)data;
- struct net_bridge_port *port = pg->port;
- struct net_bridge *br = port->br;
-
- spin_lock(&br->multicast_lock);
- if (!netif_running(br->dev) || hlist_unhashed(&pg->mglist) ||
- pg->queries_sent >= br->multicast_last_member_count)
- goto out;
-
- br_multicast_send_port_group_query(pg);
-
-out:
- spin_unlock(&br->multicast_lock);
-}
-
static struct net_bridge_mdb_entry *br_multicast_get_group(
struct net_bridge *br, struct net_bridge_port *port,
struct br_ip *group, int hash)
@@ -690,8 +620,6 @@ rehash:
mp->addr = *group;
setup_timer(&mp->timer, br_multicast_group_expired,
(unsigned long)mp);
- setup_timer(&mp->query_timer, br_multicast_group_query_expired,
- (unsigned long)mp);
hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
mdb->size++;
@@ -746,8 +674,6 @@ static int br_multicast_add_group(struct net_bridge *br,
hlist_add_head(&p->mglist, &port->mglist);
setup_timer(&p->timer, br_multicast_port_group_expired,
(unsigned long)p);
- setup_timer(&p->query_timer, br_multicast_port_group_query_expired,
- (unsigned long)p);
rcu_assign_pointer(*pp, p);
@@ -1291,9 +1217,6 @@ static void br_multicast_leave_group(struct net_bridge *br,
time_after(mp->timer.expires, time) :
try_to_del_timer_sync(&mp->timer) >= 0)) {
mod_timer(&mp->timer, time);
-
- mp->queries_sent = 0;
- mod_timer(&mp->query_timer, now);
}
goto out;
@@ -1310,9 +1233,6 @@ static void br_multicast_leave_group(struct net_bridge *br,
time_after(p->timer.expires, time) :
try_to_del_timer_sync(&p->timer) >= 0)) {
mod_timer(&p->timer, time);
-
- p->queries_sent = 0;
- mod_timer(&p->query_timer, now);
}
break;
@@ -1681,7 +1601,6 @@ void br_multicast_stop(struct net_bridge *br)
hlist_for_each_entry_safe(mp, p, n, &mdb->mhash[i],
hlist[ver]) {
del_timer(&mp->timer);
- del_timer(&mp->query_timer);
call_rcu_bh(&mp->rcu, br_multicast_free_group);
}
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 0b67a63..e1d8822 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -82,9 +82,7 @@ struct net_bridge_port_group {
struct hlist_node mglist;
struct rcu_head rcu;
struct timer_list timer;
- struct timer_list query_timer;
struct br_ip addr;
- u32 queries_sent;
};
struct net_bridge_mdb_entry
@@ -94,10 +92,8 @@ struct net_bridge_mdb_entry
struct net_bridge_port_group __rcu *ports;
struct rcu_head rcu;
struct timer_list timer;
- struct timer_list query_timer;
struct br_ip addr;
bool mglist;
- u32 queries_sent;
};
struct net_bridge_mdb_htable
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related
* Re: [PATCH v6 1/2] Ethernet driver for the WIZnet W5300 chip
From: Mike Sinkovsky @ 2012-04-04 11:00 UTC (permalink / raw)
To: Mark Brown; +Cc: netdev, linux-kernel
In-Reply-To: <20120404100148.GB3002@opensource.wolfsonmicro.com>
04.04.2012 16:01, Mark Brown написал:
> On Wed, Apr 04, 2012 at 12:18:12PM +0600, Mike Sinkovsky wrote:
>> 03.04.2012 19:36, Mark Brown написал:
>
>>> ...you use devm_request_threaded_irq() here and rely on it for cleanup.
>>> Are you sure there's no possibility of the interrupt firing after you
>>> start to tear down the device?
>
>>> By using a specifically threaded IRQ you're also adding a performance
>>> overhead for no good reason if you can call netdev_carrier_*() from IRQ
>>> context and the GPIO is capable of generating a hard IRQ. If you use
>>> request_any_context_irq() instead then the driver will get a hard IRQ if
>>> that's supported.
>
>> There isn't devm* variant of request_any_context_irq(), and using
>> plain version looks inconsistent with other resources handling.
>> Anyway, this is not performance critical procedure, and latency
>> around 100 millisecond is acceptable. Some our boards even don't
>> have this gpio at all, and nothing bad happens, just userspace
>> doesn't know is carrier on or off.
>
> None of this addresses the primary concern which is that because you're
> not (as far as I can tell) ensuring that the interrupt won't fire the
> driver might crash if the interrupt fires in between the resources it
> needs to handle the interrupt being deallocated and the interrupt being
> unregistered. Managed interrupts are relatively tricky to use because
> of this issue, with most things like memory it doesn't matter exactly
> when it's deallocated but interrupts can potentially trigger actions
> themselves.
>
> If you can use it and devm_request_any_context_irq() doesn't exist it'd
> be better to add it.
Ok, now I understand - better don't use devm* functions for interrupts,
use plain request* in probe() and free_irq() in remove().
Will post v8.
--
Mike
^ permalink raw reply
* [PATCH net-next V6 6/8] IB/rdma_cm: TOS <=> UP mapping for IBoE
From: Amir Vadai @ 2012-04-04 10:58 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai, Sean Hefty
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
Both tagged traffic and untagged traffic use tc tool mapping.
Treat RDMA TOS same as IP TOS when mapping to SL
Signed-off-by: Amir Vadai <amirv@mellanox.com>
CC: Sean Hefty <sean.hefty@intel.com>
---
drivers/infiniband/core/cma.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index e3e470f..59fbd70 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -42,6 +42,7 @@
#include <linux/inetdevice.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <net/route.h>
#include <net/tcp.h>
#include <net/ipv6.h>
@@ -1826,7 +1827,10 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
route->path_rec->reversible = 1;
route->path_rec->pkey = cpu_to_be16(0xffff);
route->path_rec->mtu_selector = IB_SA_EQ;
- route->path_rec->sl = id_priv->tos >> 5;
+ route->path_rec->sl = netdev_get_prio_tc_map(
+ ndev->priv_flags & IFF_802_1Q_VLAN ?
+ vlan_dev_real_dev(ndev) : ndev,
+ rt_tos2priority(id_priv->tos));
route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
route->path_rec->rate_selector = IB_SA_EQ;
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next V6 0/8] net/mlx4_en: DCB QoS support
From: Amir Vadai @ 2012-04-04 10:57 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai, John Fastabend, Eric Dumazet
DCBX version 802.1qaz is supported.
User Priority (UP) is set in QP context instead of in WQE (QP Work Queue
Element), which means that all traffic from a queue will have the same UP.
UP is also set for untagged traffic to be able to classify such traffic too.
Mapping from sk_prio to User Priority is done by sch_mqprio mapping. Although
confusingly sch_mqprio maps sk_prio to something called TC, it is not related
to DCBX's TC, and is interpreted by mlx4_en driver as UP.
User can set maximal BW for an ETS TC. This could be done by a new optional
attribute added to DCB_ATTR_IEEE called DCBNL DCB_ATTR_IEEE_MAXRATE. It accept
an array of 8 64 bits values, 1 for every ETS TC. Units are in Kbps.
CC: John Fastabend <john.r.fastabend@intel.com>
CC: Eric Dumazet <eric.dumazet@gmail.com>
---
Changes from V5:
- Patch 7/8 Add an optional max rate attribute to DCBNL
- Do not use NLA_PUT macro
Changes from V4:
- Patch 2/8 - set port QoS attributes
- HW commands are using HW ratelimit units (100Mbps)
- Patch 3/8 - DCB QoS support
- ets attributes are stored inline mlx4_en_priv and not alloced separately
- Changed variable name: priv->mlx4_en_ieee_ets into priv->ets
- Patch 8/8 - Set max rate-limit for a TC in mlx4 driver using the
- ratelimit is stored inline mlx4_en_priv and not allocated separately
- ratelimit values are converted from Kbps into HW units (100Mbps) in the
netlink callback instead of in the HW access function.
- ratelimit values are rounded up. 0 is used for unlimited.
- moving ratelimit to be inline mlx4_en_priv also addresses Eric D. comments
Changes from V3:
After having a discussion about the API to set/get rate limit of an ETS TC,
decided to extend DCBNL with an optional attribute for that:
- new patch 7/8 Add an optional max rate attribute to DCBNL
- new patch 8/8 Set max rate-limit for a TC in mlx4 driver using the
infrastructure from patch 7/8
Changes from V2:
- Removed patch 4 who deal with setting ratelimit through sysfs - Still under discussion
- Patch 2/7 - set port QoS attributes
- ratelimit is given in Kbps instead of Mbps units.
Changes from V1:
- Patch 1/7 - Force user priority by QP attribute
- removed unneeded comment
- Patch 2/7 - set port QoS attributes
- ratelimit is given in Mbps instead of 100Mbps units.
- Patch 3/7 - DCB QoS support
- Split mlx4_en_config_port_scheduler from mlx4_en_dcbnl_ieee_setets - enable
setting ratelimit only, without setting up to tc mapping
- Patch 4/7 - Set max rate-limit for a TC
- Rewritten patch according to comment from Eric D.
- setting ratelimit is through sysfs files:
/sys/class/net/<intf>/ratelimit/tc0
/sys/class/net/<intf>/ratelimit/tc1
...
/sys/class/net/<intf>/ratelimit/tc7
- Patch 5/7 - sk_prio <=> UP for untagged traffic
- Using skb_tx_hash for queue selection of untagged traffic
- Added Patch 6/7 - export symbol ip_tos2prio
- Fixed patch according to comment from Eric D.
- Patch 7/7 - TOS <=> UP mapping for IBoE
- No need to clone code from route.c anymore - removed it
Changes from V0:
- Removed patches 6 and 7 who deal with the interaction between the kernel HW
QoS constructs to the queue selection logic are still under discussion with
John and some changes might be needed there.
Amir Vadai (8):
net/mlx4_en: Force user priority by QP attribute
net/mlx4_core: set port QoS attributes
net/mlx4_en: DCB QoS support
net/mlx4_en: sk_prio <=> UP for untagged traffic
net/route: export symbol ip_tos2prio
IB/rdma_cm: TOS <=> UP mapping for IBoE
net/dcb: Add an optional max rate attribute
net/mlx4_en: Set max rate-limit for a TC
drivers/infiniband/core/cma.c | 6 +-
drivers/net/ethernet/mellanox/mlx4/Kconfig | 12 +
drivers/net/ethernet/mellanox/mlx4/Makefile | 1 +
drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 254 +++++++++++++++++++++
drivers/net/ethernet/mellanox/mlx4/en_main.c | 2 +-
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 26 ++-
drivers/net/ethernet/mellanox/mlx4/en_port.h | 2 +
drivers/net/ethernet/mellanox/mlx4/en_resources.c | 6 +-
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 4 +-
drivers/net/ethernet/mellanox/mlx4/en_tx.c | 10 +-
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 20 ++
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 28 ++-
drivers/net/ethernet/mellanox/mlx4/port.c | 62 +++++
include/linux/dcbnl.h | 5 +
include/linux/mlx4/cmd.h | 4 +
include/linux/mlx4/device.h | 3 +
include/linux/mlx4/qp.h | 3 +-
include/net/dcbnl.h | 2 +
net/dcb/dcbnl.c | 21 ++
net/ipv4/route.c | 2 +-
20 files changed, 455 insertions(+), 18 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
--
1.7.8.2
^ permalink raw reply
* [PATCH net-next V6 1/8] net/mlx4_en: Force user priority by QP attribute
From: Amir Vadai @ 2012-04-04 10:57 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
Instead of relying on HW to change schedule queue by UP, schedule
queue is fixed for a tx_ring, and UP in WQE is ignored in this aspect. This
resolves two issues with untagged traffic:
1. untagged traffic has no UP in packet which is needed for QoS. The change
above allows setting the schedule queue (and by that the UP) of such a stream.
2. BlueFlame uses the same field used by vlan tag. So forcing UP from QPC
allows using BF for untagged but prioritized traffic.
In old firmware that force UP is not supported, untagged traffic will not subject to
QoS.
Because UP is set by QP, need to always have a tx ring per UP, even if pfcrx
module paramter is false.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_main.c | 2 +-
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 3 ++-
drivers/net/ethernet/mellanox/mlx4/en_resources.c | 6 +++++-
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 4 ++--
drivers/net/ethernet/mellanox/mlx4/en_tx.c | 12 ++++--------
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 6 +++---
include/linux/mlx4/qp.h | 3 ++-
7 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index 2097a7d..346fdb2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -114,7 +114,7 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS +
- (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS;
+ MLX4_EN_NUM_PPP_RINGS;
params->prof[i].rss_rings = 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 31b455a..2322622 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -650,7 +650,8 @@ int mlx4_en_start_port(struct net_device *dev)
/* Configure ring */
tx_ring = &priv->tx_ring[i];
- err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn);
+ err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn,
+ max(0, i - MLX4_EN_NUM_TX_RINGS));
if (err) {
en_err(priv, "Failed allocating Tx ring\n");
mlx4_en_deactivate_cq(priv, cq);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
index bcbc54c..10c24c7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
@@ -39,7 +39,7 @@
void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
int is_tx, int rss, int qpn, int cqn,
- struct mlx4_qp_context *context)
+ int user_prio, struct mlx4_qp_context *context)
{
struct mlx4_en_dev *mdev = priv->mdev;
@@ -57,6 +57,10 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
context->local_qpn = cpu_to_be32(qpn);
context->pri_path.ackto = 1 & 0x07;
context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6;
+ if (user_prio >= 0) {
+ context->pri_path.sched_queue |= user_prio << 3;
+ context->pri_path.feup = 1 << 6;
+ }
context->pri_path.counter_index = 0xff;
context->cqn_send = cpu_to_be32(cqn);
context->cqn_recv = cpu_to_be32(cqn);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 9adbd53..d49a7ac 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -823,7 +823,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
memset(context, 0, sizeof *context);
mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0,
- qpn, ring->cqn, context);
+ qpn, ring->cqn, -1, context);
context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma);
/* Cancel FCS removal if FW allows */
@@ -890,7 +890,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
}
rss_map->indir_qp.event = mlx4_en_sqp_event;
mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn,
- priv->rx_ring[0].cqn, &context);
+ priv->rx_ring[0].cqn, -1, &context);
if (!priv->prof->rss_rings || priv->prof->rss_rings > priv->rx_ring_num)
rss_rings = priv->rx_ring_num;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 1796824..94a605a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -156,7 +156,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring,
- int cq)
+ int cq, int user_prio)
{
struct mlx4_en_dev *mdev = priv->mdev;
int err;
@@ -174,7 +174,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
ring->doorbell_qpn = ring->qp.qpn << 8;
mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
- ring->cqn, &ring->context);
+ ring->cqn, user_prio, &ring->context);
if (ring->bf_enabled)
ring->context.usr_page = cpu_to_be32(ring->bf.uar->index);
@@ -570,18 +570,14 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
{
- struct mlx4_en_priv *priv = netdev_priv(dev);
u16 vlan_tag = 0;
- /* If we support per priority flow control and the packet contains
- * a vlan tag, send the packet to the TX ring assigned to that priority
- */
- if (priv->prof->rx_ppp && vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb)) {
vlan_tag = vlan_tx_tag_get(skb);
return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13);
}
- return skb_tx_hash(dev, skb);
+ return __skb_tx_hash(dev, skb, MLX4_EN_NUM_TX_RINGS);
}
static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 9e2b911..5bd7c2a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -521,7 +521,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ri
void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring);
int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring,
- int cq);
+ int cq, int user_prio);
void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring);
@@ -539,8 +539,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev,
int budget);
int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget);
void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
- int is_tx, int rss, int qpn, int cqn,
- struct mlx4_qp_context *context);
+ int is_tx, int rss, int qpn, int cqn, int user_prio,
+ struct mlx4_qp_context *context);
void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event);
int mlx4_en_map_buffer(struct mlx4_buf *buf);
void mlx4_en_unmap_buffer(struct mlx4_buf *buf);
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
index 091f9e7..96005d7 100644
--- a/include/linux/mlx4/qp.h
+++ b/include/linux/mlx4/qp.h
@@ -139,7 +139,8 @@ struct mlx4_qp_path {
u8 rgid[16];
u8 sched_queue;
u8 vlan_index;
- u8 reserved3[2];
+ u8 feup;
+ u8 reserved3;
u8 reserved4[2];
u8 dmac[6];
};
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next V6 3/8] net/mlx4_en: DCB QoS support
From: Amir Vadai @ 2012-04-04 10:57 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
Set TSA, promised BW and PFC using IEEE 802.1qaz netlink commands.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/Kconfig | 12 ++
drivers/net/ethernet/mellanox/mlx4/Makefile | 1 +
drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 209 ++++++++++++++++++++++++
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 5 +
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 21 +++
5 files changed, 248 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
diff --git a/drivers/net/ethernet/mellanox/mlx4/Kconfig b/drivers/net/ethernet/mellanox/mlx4/Kconfig
index 1bb9353..5f027f9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx4/Kconfig
@@ -11,6 +11,18 @@ config MLX4_EN
This driver supports Mellanox Technologies ConnectX Ethernet
devices.
+config MLX4_EN_DCB
+ bool "Data Center Bridging (DCB) Support"
+ default y
+ depends on MLX4_EN && DCB
+ ---help---
+ Say Y here if you want to use Data Center Bridging (DCB) in the
+ driver.
+ If set to N, will not be able to configure QoS and ratelimit attributes.
+ This flag is depended on the kernel's DCB support.
+
+ If unsure, set to Y
+
config MLX4_CORE
tristate
depends on PCI
diff --git a/drivers/net/ethernet/mellanox/mlx4/Makefile b/drivers/net/ethernet/mellanox/mlx4/Makefile
index 4a40ab9..293127d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx4/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_MLX4_EN) += mlx4_en.o
mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
en_resources.o en_netdev.o en_selftest.o
+mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
new file mode 100644
index 0000000..6892320
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2011 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/dcbnl.h>
+
+#include "mlx4_en.h"
+
+static int mlx4_en_dcbnl_ieee_getets(struct net_device *dev,
+ struct ieee_ets *ets)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct ieee_ets *my_ets = &priv->ets;
+
+ /* No IEEE PFC settings available */
+ if (!my_ets)
+ return -EINVAL;
+
+ ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
+ ets->cbs = my_ets->cbs;
+ memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
+ memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
+ memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
+
+ return 0;
+}
+
+static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets)
+{
+ int i;
+ int total_ets_bw = 0;
+ int has_ets_tc = 0;
+
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+ if (ets->prio_tc[i] > MLX4_EN_NUM_UP) {
+ en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n",
+ i, ets->prio_tc[i]);
+ return -EINVAL;
+ }
+
+ switch (ets->tc_tsa[i]) {
+ case IEEE_8021QAZ_TSA_STRICT:
+ break;
+ case IEEE_8021QAZ_TSA_ETS:
+ has_ets_tc = 1;
+ total_ets_bw += ets->tc_tx_bw[i];
+ break;
+ default:
+ en_err(priv, "TC[%d]: Not supported TSA: %d\n",
+ i, ets->tc_tsa[i]);
+ return -ENOTSUPP;
+ }
+ }
+
+ if (has_ets_tc && total_ets_bw != MLX4_EN_BW_MAX) {
+ en_err(priv, "Bad ETS BW sum: %d. Should be exactly 100%%\n",
+ total_ets_bw);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mlx4_en_config_port_scheduler(struct mlx4_en_priv *priv,
+ struct ieee_ets *ets, u16 *ratelimit)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int num_strict = 0;
+ int i;
+ __u8 tc_tx_bw[IEEE_8021QAZ_MAX_TCS] = { 0 };
+ __u8 pg[IEEE_8021QAZ_MAX_TCS] = { 0 };
+
+ ets = ets ?: &priv->ets;
+
+ /* higher TC means higher priority => lower pg */
+ for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) {
+ switch (ets->tc_tsa[i]) {
+ case IEEE_8021QAZ_TSA_STRICT:
+ pg[i] = num_strict++;
+ tc_tx_bw[i] = MLX4_EN_BW_MAX;
+ break;
+ case IEEE_8021QAZ_TSA_ETS:
+ pg[i] = MLX4_EN_TC_ETS;
+ tc_tx_bw[i] = ets->tc_tx_bw[i] ?: MLX4_EN_BW_MIN;
+ break;
+ }
+ }
+
+ return mlx4_SET_PORT_SCHEDULER(mdev->dev, priv->port, tc_tx_bw, pg,
+ ratelimit);
+}
+
+static int
+mlx4_en_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ err = mlx4_en_ets_validate(priv, ets);
+ if (err)
+ return err;
+
+ err = mlx4_SET_PORT_PRIO2TC(mdev->dev, priv->port, ets->prio_tc);
+ if (err)
+ return err;
+
+ err = mlx4_en_config_port_scheduler(priv, ets, NULL);
+ if (err)
+ return err;
+
+ memcpy(&priv->ets, ets, sizeof(priv->ets));
+
+ return 0;
+}
+
+static int mlx4_en_dcbnl_ieee_getpfc(struct net_device *dev,
+ struct ieee_pfc *pfc)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
+ pfc->pfc_en = priv->prof->tx_ppp;
+
+ return 0;
+}
+
+static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev,
+ struct ieee_pfc *pfc)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int err;
+
+ en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n",
+ pfc->pfc_cap,
+ pfc->pfc_en,
+ pfc->mbc,
+ pfc->delay);
+
+ priv->prof->rx_pause = priv->prof->tx_pause = !!pfc->pfc_en;
+ priv->prof->rx_ppp = priv->prof->tx_ppp = pfc->pfc_en;
+
+ err = mlx4_SET_PORT_general(mdev->dev, priv->port,
+ priv->rx_skb_size + ETH_FCS_LEN,
+ priv->prof->tx_pause,
+ priv->prof->tx_ppp,
+ priv->prof->rx_pause,
+ priv->prof->rx_ppp);
+ if (err)
+ en_err(priv, "Failed setting pause params\n");
+
+ return err;
+}
+
+static u8 mlx4_en_dcbnl_getdcbx(struct net_device *dev)
+{
+ return DCB_CAP_DCBX_VER_IEEE;
+}
+
+static u8 mlx4_en_dcbnl_setdcbx(struct net_device *dev, u8 mode)
+{
+ if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
+ (mode & DCB_CAP_DCBX_VER_CEE) ||
+ !(mode & DCB_CAP_DCBX_VER_IEEE) ||
+ !(mode & DCB_CAP_DCBX_HOST))
+ return 1;
+
+ return 0;
+}
+
+const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops = {
+ .ieee_getets = mlx4_en_dcbnl_ieee_getets,
+ .ieee_setets = mlx4_en_dcbnl_ieee_setets,
+ .ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc,
+ .ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc,
+
+ .getdcbx = mlx4_en_dcbnl_getdcbx,
+ .setdcbx = mlx4_en_dcbnl_setdcbx,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 2322622..107f005 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -967,6 +967,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
mutex_unlock(&mdev->state_lock);
mlx4_en_free_resources(priv);
+
free_netdev(dev);
}
@@ -1080,6 +1081,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
+#ifdef CONFIG_MLX4_EN_DCB
+ if (!mlx4_is_slave(priv->mdev->dev))
+ dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
+#endif
/* Query for default mac and max mtu */
priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 5bd7c2a..97d4f35 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -40,6 +40,9 @@
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
+#ifdef CONFIG_MLX4_EN_DCB
+#include <linux/dcbnl.h>
+#endif
#include <linux/mlx4/device.h>
#include <linux/mlx4/qp.h>
@@ -110,6 +113,7 @@ enum {
#define MLX4_EN_NUM_TX_RINGS 8
#define MLX4_EN_NUM_PPP_RINGS 8
#define MAX_TX_RINGS (MLX4_EN_NUM_TX_RINGS + MLX4_EN_NUM_PPP_RINGS)
+#define MLX4_EN_NUM_UP 8
#define MLX4_EN_DEF_TX_RING_SIZE 512
#define MLX4_EN_DEF_RX_RING_SIZE 1024
@@ -410,6 +414,15 @@ struct mlx4_en_frag_info {
};
+#ifdef CONFIG_MLX4_EN_DCB
+/* Minimal TC BW - setting to 0 will block traffic */
+#define MLX4_EN_BW_MIN 1
+#define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */
+
+#define MLX4_EN_TC_ETS 7
+
+#endif
+
struct mlx4_en_priv {
struct mlx4_en_dev *mdev;
struct mlx4_en_port_profile *prof;
@@ -483,6 +496,10 @@ struct mlx4_en_priv {
int vids[128];
bool wol;
struct device *ddev;
+
+#ifdef CONFIG_MLX4_EN_DCB
+ struct ieee_ets ets;
+#endif
};
enum mlx4_en_wol {
@@ -557,6 +574,10 @@ int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv);
int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset);
int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port);
+#ifdef CONFIG_MLX4_EN_DCB
+extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops;
+#endif
+
#define MLX4_EN_NUM_SELF_TEST 5
void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
u64 mlx4_en_mac_to_u64(u8 *addr);
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next V6 7/8] net/dcb: Add an optional max rate attribute
From: Amir Vadai @ 2012-04-04 10:58 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
Although not specified in 8021Qaz spec, it could be useful to enable drivers
whose HW supports setting a rate limit for an ETS TC. This patch adds this
optional attribute to DCB netlink. To use it, drivers should implement and
register the callbacks ieee_setmaxrate and ieee_getmaxrate. The units are 64
bits long and specified in Kbps to enable usage over both slow and very fast
networks.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
include/linux/dcbnl.h | 5 +++++
include/net/dcbnl.h | 2 ++
net/dcb/dcbnl.c | 21 +++++++++++++++++++++
3 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h
index 65a2562..ec8e372 100644
--- a/include/linux/dcbnl.h
+++ b/include/linux/dcbnl.h
@@ -67,6 +67,10 @@ struct ieee_ets {
__u8 reco_prio_tc[IEEE_8021QAZ_MAX_TCS];
};
+struct ieee_maxrate {
+ __u64 tc_maxrate[IEEE_8021QAZ_MAX_TCS];
+};
+
/* This structure contains the IEEE 802.1Qaz PFC managed object
*
* @pfc_cap: Indicates the number of traffic classes on the local device
@@ -321,6 +325,7 @@ enum ieee_attrs {
DCB_ATTR_IEEE_PEER_ETS,
DCB_ATTR_IEEE_PEER_PFC,
DCB_ATTR_IEEE_PEER_APP,
+ DCB_ATTR_IEEE_MAXRATE,
__DCB_ATTR_IEEE_MAX
};
#define DCB_ATTR_IEEE_MAX (__DCB_ATTR_IEEE_MAX - 1)
diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h
index f55c980..fc5d5dc 100644
--- a/include/net/dcbnl.h
+++ b/include/net/dcbnl.h
@@ -48,6 +48,8 @@ struct dcbnl_rtnl_ops {
/* IEEE 802.1Qaz std */
int (*ieee_getets) (struct net_device *, struct ieee_ets *);
int (*ieee_setets) (struct net_device *, struct ieee_ets *);
+ int (*ieee_getmaxrate) (struct net_device *, struct ieee_maxrate *);
+ int (*ieee_setmaxrate) (struct net_device *, struct ieee_maxrate *);
int (*ieee_getpfc) (struct net_device *, struct ieee_pfc *);
int (*ieee_setpfc) (struct net_device *, struct ieee_pfc *);
int (*ieee_getapp) (struct net_device *, struct dcb_app *);
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 36f37af..d3df048 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -178,6 +178,8 @@ static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
[DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)},
[DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)},
[DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED},
+ [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)},
+
};
static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
@@ -1246,6 +1248,17 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
goto nla_put_failure;
}
+ if (ops->ieee_getmaxrate) {
+ struct ieee_maxrate maxrate;
+ err = ops->ieee_getmaxrate(netdev, &maxrate);
+ if (!err) {
+ err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE,
+ sizeof(maxrate), &maxrate);
+ if (err)
+ goto nla_put_failure;
+ }
+ }
+
if (ops->ieee_getpfc) {
struct ieee_pfc pfc;
err = ops->ieee_getpfc(netdev, &pfc);
@@ -1601,6 +1614,14 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
goto err;
}
+ if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) {
+ struct ieee_maxrate *maxrate =
+ nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]);
+ err = ops->ieee_setmaxrate(netdev, maxrate);
+ if (err)
+ goto err;
+ }
+
if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
err = ops->ieee_setpfc(netdev, pfc);
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next V6 5/8] net/route: export symbol ip_tos2prio
From: Amir Vadai @ 2012-04-04 10:58 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
Need to export this to enable drivers use rt_tos2priority()
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
net/ipv4/route.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e5647b4..634aa82 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -230,7 +230,7 @@ const __u8 ip_tos2prio[16] = {
TC_PRIO_INTERACTIVE_BULK,
ECN_OR_COST(INTERACTIVE_BULK)
};
-
+EXPORT_SYMBOL(ip_tos2prio);
/*
* Route cache.
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next V6 8/8] net/mlx4_en: Set max rate-limit for a TC
From: Amir Vadai @ 2012-04-04 10:58 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
This patch is using the DCB netlink to set rate limit per ETS TC
Values are accepted in Kbps and rounded up to the nearest multiply of 100Mbps.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 45 ++++++++++++++++++++++++
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 +
2 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
index 6892320..0cc6c96 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -100,6 +100,7 @@ static int mlx4_en_config_port_scheduler(struct mlx4_en_priv *priv,
__u8 pg[IEEE_8021QAZ_MAX_TCS] = { 0 };
ets = ets ?: &priv->ets;
+ ratelimit = ratelimit ?: priv->maxrate;
/* higher TC means higher priority => lower pg */
for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) {
@@ -198,9 +199,53 @@ static u8 mlx4_en_dcbnl_setdcbx(struct net_device *dev, u8 mode)
return 0;
}
+#define MLX4_RATELIMIT_UNITS_IN_KB 100000 /* rate-limit HW unit in Kbps */
+static int mlx4_en_dcbnl_ieee_getmaxrate(struct net_device *dev,
+ struct ieee_maxrate *maxrate)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int i;
+
+ if (!priv->maxrate)
+ return -EINVAL;
+
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+ maxrate->tc_maxrate[i] =
+ priv->maxrate[i] * MLX4_RATELIMIT_UNITS_IN_KB;
+
+ return 0;
+}
+
+static int mlx4_en_dcbnl_ieee_setmaxrate(struct net_device *dev,
+ struct ieee_maxrate *maxrate)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ u16 tmp[IEEE_8021QAZ_MAX_TCS];
+ int i, err;
+
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+ /* Convert from Kbps into HW units, rounding result up.
+ * Setting to 0, means unlimited BW.
+ */
+ tmp[i] =
+ (maxrate->tc_maxrate[i] + MLX4_RATELIMIT_UNITS_IN_KB -
+ 1) / MLX4_RATELIMIT_UNITS_IN_KB;
+ }
+
+ err = mlx4_en_config_port_scheduler(priv, NULL, tmp);
+ if (err)
+ return err;
+
+ memcpy(priv->maxrate, tmp, sizeof(*priv->maxrate));
+
+ return 0;
+}
+
const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops = {
.ieee_getets = mlx4_en_dcbnl_ieee_getets,
.ieee_setets = mlx4_en_dcbnl_ieee_setets,
+ .ieee_getmaxrate = mlx4_en_dcbnl_ieee_getmaxrate,
+ .ieee_setmaxrate = mlx4_en_dcbnl_ieee_setmaxrate,
.ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc,
.ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc,
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 97d4f35..3879c5e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -499,6 +499,7 @@ struct mlx4_en_priv {
#ifdef CONFIG_MLX4_EN_DCB
struct ieee_ets ets;
+ u16 maxrate[IEEE_8021QAZ_MAX_TCS];
#endif
};
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next V6 4/8] net/mlx4_en: sk_prio <=> UP for untagged traffic
From: Amir Vadai @ 2012-04-04 10:58 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
Since vlan egress map is only good for tagged traffic, need to have other
mapping to be used by untagged traffic.
For that, the driver uses sch_mqprio mapping. This mapping could be set by
using tc tool from iproute2 package.
Mapped UP will be used by the HW for QoS purposes, but won't go out on the
wire.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 18 ++++++++++++++++++
drivers/net/ethernet/mellanox/mlx4/en_tx.c | 2 +-
2 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 107f005..35003ad 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -45,6 +45,14 @@
#include "mlx4_en.h"
#include "en_port.h"
+static int mlx4_en_setup_tc(struct net_device *dev, u8 up)
+{
+ if (up != MLX4_EN_NUM_UP)
+ return -EINVAL;
+
+ return 0;
+}
+
static int mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
@@ -1038,6 +1046,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
.ndo_poll_controller = mlx4_en_netpoll,
#endif
.ndo_set_features = mlx4_en_set_features,
+ .ndo_setup_tc = mlx4_en_setup_tc,
};
int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
@@ -1119,6 +1128,15 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
+ netdev_set_num_tc(dev, MLX4_EN_NUM_UP);
+
+ /* First 9 rings are for UP 0 */
+ netdev_set_tc_queue(dev, 0, MLX4_EN_NUM_TX_RINGS + 1, 0);
+
+ /* Partition Tx queues evenly amongst UP's 1-7 */
+ for (i = 1; i < MLX4_EN_NUM_UP; i++)
+ netdev_set_tc_queue(dev, i, 1, MLX4_EN_NUM_TX_RINGS + i);
+
SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
/* Set defualt MAC */
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 94a605a..d9bab53 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -577,7 +577,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13);
}
- return __skb_tx_hash(dev, skb, MLX4_EN_NUM_TX_RINGS);
+ return skb_tx_hash(dev, skb);
}
static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
--
1.7.8.2
^ permalink raw reply related
* [PATCH net-next V6 2/8] net/mlx4_core: set port QoS attributes
From: Amir Vadai @ 2012-04-04 10:57 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Roland Dreier, Yevgeny Petrilin, Oren Duer, Amir Vadai,
Amir Vadai
In-Reply-To: <1333537084-9186-1-git-send-email-amirv@mellanox.com>
Adding QoS firmware commands:
- mlx4_en_SET_PORT_PRIO2TC - set UP <=> TC
- mlx4_en_SET_PORT_SCHEDULER - set promised BW, max BW and PG number
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_port.h | 2 +
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 20 ++++++++
drivers/net/ethernet/mellanox/mlx4/port.c | 62 ++++++++++++++++++++++++++
include/linux/mlx4/cmd.h | 4 ++
include/linux/mlx4/device.h | 3 +
5 files changed, 91 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.h b/drivers/net/ethernet/mellanox/mlx4/en_port.h
index 6934fd7..745090b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.h
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.h
@@ -39,6 +39,8 @@
#define SET_PORT_PROMISC_SHIFT 31
#define SET_PORT_MC_PROMISC_SHIFT 30
+#define MLX4_EN_NUM_TC 8
+
#define VLAN_FLTR_SIZE 128
struct mlx4_set_vlan_fltr_mbox {
__be32 entry[VLAN_FLTR_SIZE];
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 2a0ff2c..cd56f1a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -53,6 +53,26 @@
#define DRV_VERSION "1.1"
#define DRV_RELDATE "Dec, 2011"
+#define MLX4_NUM_UP 8
+#define MLX4_NUM_TC 8
+#define MLX4_RATELIMIT_UNITS 3 /* 100 Mbps */
+#define MLX4_RATELIMIT_DEFAULT 0xffff
+
+struct mlx4_set_port_prio2tc_context {
+ u8 prio2tc[4];
+};
+
+struct mlx4_port_scheduler_tc_cfg_be {
+ __be16 pg;
+ __be16 bw_precentage;
+ __be16 max_bw_units; /* 3-100Mbps, 4-1Gbps, other values - reserved */
+ __be16 max_bw_value;
+};
+
+struct mlx4_set_port_scheduler_context {
+ struct mlx4_port_scheduler_tc_cfg_be tc[MLX4_NUM_TC];
+};
+
enum {
MLX4_HCR_BASE = 0x80680,
MLX4_HCR_SIZE = 0x0001c,
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 77535ff..55b12e6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -834,6 +834,68 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
}
EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
+int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_set_port_prio2tc_context *context;
+ int err;
+ u32 in_mod;
+ int i;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ context = mailbox->buf;
+ memset(context, 0, sizeof *context);
+
+ for (i = 0; i < MLX4_NUM_UP; i += 2)
+ context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1];
+
+ in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port;
+ err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC);
+
+int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw,
+ u8 *pg, u16 *ratelimit)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_set_port_scheduler_context *context;
+ int err;
+ u32 in_mod;
+ int i;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ context = mailbox->buf;
+ memset(context, 0, sizeof *context);
+
+ for (i = 0; i < MLX4_NUM_TC; i++) {
+ struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i];
+ u16 r = ratelimit && ratelimit[i] ? ratelimit[i] :
+ MLX4_RATELIMIT_DEFAULT;
+
+ tc->pg = htons(pg[i]);
+ tc->bw_precentage = htons(tc_tx_bw[i]);
+
+ tc->max_bw_units = htons(MLX4_RATELIMIT_UNITS);
+ tc->max_bw_value = htons(r);
+ }
+
+ in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port;
+ err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
+ MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER);
+
int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h
index 9958ff2..1f3860a 100644
--- a/include/linux/mlx4/cmd.h
+++ b/include/linux/mlx4/cmd.h
@@ -150,6 +150,10 @@ enum {
/* statistics commands */
MLX4_CMD_QUERY_IF_STAT = 0X54,
MLX4_CMD_SET_IF_STAT = 0X55,
+
+ /* set port opcode modifiers */
+ MLX4_SET_PORT_PRIO2TC = 0x8,
+ MLX4_SET_PORT_SCHEDULER = 0x9,
};
enum {
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 834c96c..6d02824 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -628,6 +628,9 @@ int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx);
int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
u8 promisc);
+int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc);
+int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw,
+ u8 *pg, u16 *ratelimit);
int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx);
int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index);
--
1.7.8.2
^ permalink raw reply related
* Re: Commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 has broken ss command
From: Eric Dumazet @ 2012-04-04 10:21 UTC (permalink / raw)
To: Kusanagi Kouichi; +Cc: netdev, Pavel Emelyanov, linux-kernel
In-Reply-To: <20120404100015.D41B162C03E@msa106.auone-net.jp>
On Wed, 2012-04-04 at 19:00 +0900, Kusanagi Kouichi wrote:
> On 2012-04-04 11:07:43 +0200, Eric Dumazet wrote:
> > On Wed, 2012-04-04 at 18:03 +0900, Kusanagi Kouichi wrote:
> > > Since commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 ("sock_diag:
> > > Move the sock_ code to net/core/"), ss command from iproute package
> > > doesn't work if INET_DIAG is not enabled.
> > >
> > > $ ss
> > > State Recv-Q Send-Q Local Address:Port Peer Address:Port
> > > TCPDIAG answers: Operation not supported
> > > --
> >
> > Try to update your iproute2 package ?
>
> iproute seems up to date.
> $ ss --version
> ss utility, iproute2-ss120319
>
> I tried git master commit 4bb00cd2b7525ad7d6cf6bbea945ad6e546873f4.
> It still fails.
Please try this patch :
diff --git a/misc/ss.c b/misc/ss.c
index 5414f75..8c00760 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -1534,8 +1534,10 @@ static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
.msg_iovlen = f->f ? 3 : 1,
};
- if (sendmsg(fd, &msg, 0) < 0)
+ if (sendmsg(fd, &msg, 0) < 0) {
+ close(fd);
return -1;
+ }
iov[0] = (struct iovec){
.iov_base = buf,
@@ -1589,6 +1591,10 @@ static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
fprintf(stderr, "ERROR truncated\n");
} else {
errno = -err->error;
+ if (errno == EOPNOTSUPP) {
+ close(fd);
+ return -1;
+ }
perror("TCPDIAG answers");
}
close(fd);
^ permalink raw reply related
* Re: [PATCH V4 net-next 00/26] ethtool: support time stamping and phc clocks
From: Jeff Kirsher @ 2012-04-04 10:02 UTC (permalink / raw)
To: David Miller
Cc: richardcochran, netdev, bhutchings, mporter, jacob.e.keller,
john.ronciak, e1000-devel
In-Reply-To: <20120404.052916.1495763141439052807.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 694 bytes --]
On Wed, 2012-04-04 at 05:29 -0400, David Miller wrote:
> From: Richard Cochran <richardcochran@gmail.com>
> Date: Wed, 4 Apr 2012 10:59:15 +0200
>
> > * Changes in V4:
> > - drop two patches requiring out of tree support
> > - added Ben's Reviewed-by tag on two commit messages
> > * Changes in V3:
> > - works without ethtool_ops
> > - does not require special privileges
> > - neaten user space tool output
>
> Applied, let's see if this one compiles :-)
Just to make it clear, I have added the two patches that were dropped in
v4 of this series (igb & e100) to my queue and plan to push them
upstream through my tree after validation takes a look at them. :-)
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v6 1/2] Ethernet driver for the WIZnet W5300 chip
From: Mark Brown @ 2012-04-04 10:01 UTC (permalink / raw)
To: Mike Sinkovsky; +Cc: netdev, linux-kernel
In-Reply-To: <4F7BE7A4.1060202@permonline.ru>
[-- Attachment #1: Type: text/plain, Size: 1615 bytes --]
On Wed, Apr 04, 2012 at 12:18:12PM +0600, Mike Sinkovsky wrote:
> 03.04.2012 19:36, Mark Brown написал:
> >...you use devm_request_threaded_irq() here and rely on it for cleanup.
> >Are you sure there's no possibility of the interrupt firing after you
> >start to tear down the device?
> >By using a specifically threaded IRQ you're also adding a performance
> >overhead for no good reason if you can call netdev_carrier_*() from IRQ
> >context and the GPIO is capable of generating a hard IRQ. If you use
> >request_any_context_irq() instead then the driver will get a hard IRQ if
> >that's supported.
> There isn't devm* variant of request_any_context_irq(), and using
> plain version looks inconsistent with other resources handling.
> Anyway, this is not performance critical procedure, and latency
> around 100 millisecond is acceptable. Some our boards even don't
> have this gpio at all, and nothing bad happens, just userspace
> doesn't know is carrier on or off.
None of this addresses the primary concern which is that because you're
not (as far as I can tell) ensuring that the interrupt won't fire the
driver might crash if the interrupt fires in between the resources it
needs to handle the interrupt being deallocated and the interrupt being
unregistered. Managed interrupts are relatively tricky to use because
of this issue, with most things like memory it doesn't matter exactly
when it's deallocated but interrupts can potentially trigger actions
themselves.
If you can use it and devm_request_any_context_irq() doesn't exist it'd
be better to add it.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: Commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 has broken ss command
From: Kusanagi Kouichi @ 2012-04-04 10:00 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, Pavel Emelyanov, linux-kernel
In-Reply-To: <1333530463.18626.545.camel@edumazet-glaptop>
On 2012-04-04 11:07:43 +0200, Eric Dumazet wrote:
> On Wed, 2012-04-04 at 18:03 +0900, Kusanagi Kouichi wrote:
> > Since commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 ("sock_diag:
> > Move the sock_ code to net/core/"), ss command from iproute package
> > doesn't work if INET_DIAG is not enabled.
> >
> > $ ss
> > State Recv-Q Send-Q Local Address:Port Peer Address:Port
> > TCPDIAG answers: Operation not supported
> > --
>
> Try to update your iproute2 package ?
iproute seems up to date.
$ ss --version
ss utility, iproute2-ss120319
I tried git master commit 4bb00cd2b7525ad7d6cf6bbea945ad6e546873f4.
It still fails.
^ permalink raw reply
* Re: Commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 has broken ss command
From: Eric Dumazet @ 2012-04-04 9:48 UTC (permalink / raw)
To: David Miller; +Cc: slash, netdev, xemul, linux-kernel
In-Reply-To: <1333532694.18626.563.camel@edumazet-glaptop>
On Wed, 2012-04-04 at 11:44 +0200, Eric Dumazet wrote:
> On Wed, 2012-04-04 at 05:24 -0400, David Miller wrote:
> > From: Eric Dumazet <eric.dumazet@gmail.com>
> > Date: Wed, 04 Apr 2012 11:07:43 +0200
> >
> > > On Wed, 2012-04-04 at 18:03 +0900, Kusanagi Kouichi wrote:
> > >> Since commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 ("sock_diag:
> > >> Move the sock_ code to net/core/"), ss command from iproute package
> > >> doesn't work if INET_DIAG is not enabled.
> > >>
> > >> $ ss
> > >> State Recv-Q Send-Q Local Address:Port Peer Address:Port
> > >> TCPDIAG answers: Operation not supported
> > >> --
> > >
> > > Try to update your iproute2 package ?
> >
> > Well, he doesn't INET_DIAG enabled in his kernel, so no matter what
> > iproute2 version he uses it won't work :-)
>
> iproute2 misc/ss.c has a fallback using /proc/net/tcp
>
> Dont know when this broke.
>
> I guess we should fix ss to cope INET_DIAG being disabled.
>
> tcp_show_netlink() should return -1 instead of 0
>
Kusanagi Kouichi is right. Commit 8ef874bfc72 apparently changed things
since socket(AF_NETLINK, SOCK_RAW, NETINK_INET_DIAG) doesnt fail
anymore...
^ permalink raw reply
* Re: question about napi_disable (was Re: [PATCH] virtio_net: set/cancel work on ndo_open/ndo_stop)
From: Michael S. Tsirkin @ 2012-04-04 9:47 UTC (permalink / raw)
To: Rusty Russell; +Cc: kvm, netdev, virtualization, Amit Shah, David Miller
In-Reply-To: <20120404093229.GA3804@redhat.com>
On Wed, Apr 04, 2012 at 12:32:29PM +0300, Michael S. Tsirkin wrote:
> On Thu, Dec 29, 2011 at 09:12:38PM +1030, Rusty Russell wrote:
> > Michael S. Tsirkin noticed that we could run the refill work after
> > ndo_close, which can re-enable napi - we don't disable it until
> > virtnet_remove. This is clearly wrong, so move the workqueue control
> > to ndo_open and ndo_stop (aka. virtnet_open and virtnet_close).
> >
> > One subtle point: virtnet_probe() could simply fail if it couldn't
> > allocate a receive buffer, but that's less polite in virtnet_open() so
> > we schedule a refill as we do in the normal receive path if we run out
> > of memory.
> >
> > Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
>
> Doh.
> napi_disable does not prevent the following
> napi_schedule, does it?
>
> Can someone confirm that I am not seeing things please?
Yes, I *was* seeing things. After napi_disable, NAPI_STATE_SCHED
is set to napi_schedule does nothing.
Sorry about the noise.
> And this means this hack does not work:
> try_fill_recv can still run in parallel with
> napi, corrupting the vq.
>
> I suspect we need to resurrect a patch that used a
> dedicated flag to avoid this race.
>
> Comments?
>
> > ---
> > drivers/net/virtio_net.c | 17 +++++++++++++----
> > 1 file changed, 13 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -439,7 +439,13 @@ static int add_recvbuf_mergeable(struct
> > return err;
> > }
> >
> > -/* Returns false if we couldn't fill entirely (OOM). */
> > +/*
> > + * Returns false if we couldn't fill entirely (OOM).
> > + *
> > + * Normally run in the receive path, but can also be run from ndo_open
> > + * before we're receiving packets, or from refill_work which is
> > + * careful to disable receiving (using napi_disable).
> > + */
> > static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
> > {
> > int err;
> > @@ -719,6 +725,10 @@ static int virtnet_open(struct net_devic
> > {
> > struct virtnet_info *vi = netdev_priv(dev);
> >
> > + /* Make sure we have some buffers: if oom use wq. */
> > + if (!try_fill_recv(vi, GFP_KERNEL))
> > + schedule_delayed_work(&vi->refill, 0);
> > +
> > virtnet_napi_enable(vi);
> > return 0;
> > }
> > @@ -772,6 +782,8 @@ static int virtnet_close(struct net_devi
> > {
> > struct virtnet_info *vi = netdev_priv(dev);
> >
> > + /* Make sure refill_work doesn't re-enable napi! */
> > + cancel_delayed_work_sync(&vi->refill);
> > napi_disable(&vi->napi);
> >
> > return 0;
> > @@ -1082,7 +1094,6 @@ static int virtnet_probe(struct virtio_d
> >
> > unregister:
> > unregister_netdev(dev);
> > - cancel_delayed_work_sync(&vi->refill);
> > free_vqs:
> > vdev->config->del_vqs(vdev);
> > free_stats:
> > @@ -1121,9 +1132,7 @@ static void __devexit virtnet_remove(str
> > /* Stop all the virtqueues. */
> > vdev->config->reset(vdev);
> >
> > -
> > unregister_netdev(vi->dev);
> > - cancel_delayed_work_sync(&vi->refill);
> >
> > /* Free unused buffers in both send and recv, if any. */
> > free_unused_bufs(vi);
^ permalink raw reply
* Re: Commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 has broken ss command
From: Eric Dumazet @ 2012-04-04 9:44 UTC (permalink / raw)
To: David Miller; +Cc: slash, netdev, xemul, linux-kernel
In-Reply-To: <20120404.052423.998527504342669775.davem@davemloft.net>
On Wed, 2012-04-04 at 05:24 -0400, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Wed, 04 Apr 2012 11:07:43 +0200
>
> > On Wed, 2012-04-04 at 18:03 +0900, Kusanagi Kouichi wrote:
> >> Since commit 8ef874bfc7296fa206eea2ad1e8a426f576bf6f6 ("sock_diag:
> >> Move the sock_ code to net/core/"), ss command from iproute package
> >> doesn't work if INET_DIAG is not enabled.
> >>
> >> $ ss
> >> State Recv-Q Send-Q Local Address:Port Peer Address:Port
> >> TCPDIAG answers: Operation not supported
> >> --
> >
> > Try to update your iproute2 package ?
>
> Well, he doesn't INET_DIAG enabled in his kernel, so no matter what
> iproute2 version he uses it won't work :-)
iproute2 misc/ss.c has a fallback using /proc/net/tcp
Dont know when this broke.
I guess we should fix ss to cope INET_DIAG being disabled.
tcp_show_netlink() should return -1 instead of 0
^ permalink raw reply
* [net 10/10] bnx2x: Clear MDC/MDIO warning message
From: Yaniv Rosner @ 2012-04-04 11:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Yaniv Rosner, Eilon Greenstein
This patch clears a warning message of "MDC/MDIO access timeout" which may
appear when interface is loaded due to missing clock setting before resetting
the LED, and starting periodic function too early.
Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 1 -
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 2 +-
2 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 44556b7..4b05481 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1874,7 +1874,6 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
* bnx2x_periodic_task().
*/
smp_mb();
- queue_delayed_work(bnx2x_wq, &bp->period_task, 0);
} else
bp->port.pmf = 0;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 7e41682..ad95324 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -12205,10 +12205,10 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
* Hold it as vars low
*/
/* clear link led */
+ bnx2x_set_mdio_clk(bp, params->chip_id, port);
bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
if (reset_ext_phy) {
- bnx2x_set_mdio_clk(bp, params->chip_id, port);
for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) {
if (params->phy[phy_index].link_reset) {
--
1.7.7.1
^ permalink raw reply related
* Re: [net 00/10] bnx2x: Link fixes
From: David Miller @ 2012-04-04 9:38 UTC (permalink / raw)
To: yanivr; +Cc: netdev
In-Reply-To: <1333538942-9904-1-git-send-email-yanivr@broadcom.com>
Where's patch #10? It didn't show up yet?
^ permalink raw reply
* Re: [PATCH net-next 2/2] e100: enable transmit time stamping.
From: Jeff Kirsher @ 2012-04-04 9:34 UTC (permalink / raw)
To: Richard Cochran; +Cc: netdev@vger.kernel.org, David Miller
In-Reply-To: <20120404093011.GA4292@netboy.at.omicron.at>
[-- Attachment #1: Type: text/plain, Size: 1103 bytes --]
On Wed, 2012-04-04 at 11:30 +0200, Richard Cochran wrote:
> On Wed, Apr 04, 2012 at 02:04:43AM -0700, Jeff Kirsher wrote:
> >
> > I had this patch in my queue, but during testing we found some serious
> > issues with some adapters. With every 82559 based adapter Aaron tried
> > the system would panic on driver load. This included at least one
> > sampling of D101S and D101M. Every other e100 chipset Aaron tried
> > (82557, 82558, 82550) appeared to work fine.
> >
> > So I am dropping this patch as is due to the kernel panics.
>
> Okay, fine. That driver is strangely written, with weird callbacks and
> passing function pointers around.
>
> Taking a second look, I think I might have found the problem. The
> drivers casts a firmware pointer onto a skb, and my patch then tries
> to timestamp the firmware blob.
>
> If I rework this, are you willing to give it another try?
>
> Thanks,
> Richard
Yeah, we appreciate the work your doing. Just send me an updated patch
and I will add it to my queue.
That was our thoughts as well regarding the firmware blobs.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* question about napi_disable (was Re: [PATCH] virtio_net: set/cancel work on ndo_open/ndo_stop)
From: Michael S. Tsirkin @ 2012-04-04 9:32 UTC (permalink / raw)
To: Rusty Russell; +Cc: kvm, netdev, virtualization, Amit Shah, David Miller
In-Reply-To: <87pqf7fyld.fsf@rustcorp.com.au>
On Thu, Dec 29, 2011 at 09:12:38PM +1030, Rusty Russell wrote:
> Michael S. Tsirkin noticed that we could run the refill work after
> ndo_close, which can re-enable napi - we don't disable it until
> virtnet_remove. This is clearly wrong, so move the workqueue control
> to ndo_open and ndo_stop (aka. virtnet_open and virtnet_close).
>
> One subtle point: virtnet_probe() could simply fail if it couldn't
> allocate a receive buffer, but that's less polite in virtnet_open() so
> we schedule a refill as we do in the normal receive path if we run out
> of memory.
>
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Doh.
napi_disable does not prevent the following
napi_schedule, does it?
Can someone confirm that I am not seeing things please?
And this means this hack does not work:
try_fill_recv can still run in parallel with
napi, corrupting the vq.
I suspect we need to resurrect a patch that used a
dedicated flag to avoid this race.
Comments?
> ---
> drivers/net/virtio_net.c | 17 +++++++++++++----
> 1 file changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -439,7 +439,13 @@ static int add_recvbuf_mergeable(struct
> return err;
> }
>
> -/* Returns false if we couldn't fill entirely (OOM). */
> +/*
> + * Returns false if we couldn't fill entirely (OOM).
> + *
> + * Normally run in the receive path, but can also be run from ndo_open
> + * before we're receiving packets, or from refill_work which is
> + * careful to disable receiving (using napi_disable).
> + */
> static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
> {
> int err;
> @@ -719,6 +725,10 @@ static int virtnet_open(struct net_devic
> {
> struct virtnet_info *vi = netdev_priv(dev);
>
> + /* Make sure we have some buffers: if oom use wq. */
> + if (!try_fill_recv(vi, GFP_KERNEL))
> + schedule_delayed_work(&vi->refill, 0);
> +
> virtnet_napi_enable(vi);
> return 0;
> }
> @@ -772,6 +782,8 @@ static int virtnet_close(struct net_devi
> {
> struct virtnet_info *vi = netdev_priv(dev);
>
> + /* Make sure refill_work doesn't re-enable napi! */
> + cancel_delayed_work_sync(&vi->refill);
> napi_disable(&vi->napi);
>
> return 0;
> @@ -1082,7 +1094,6 @@ static int virtnet_probe(struct virtio_d
>
> unregister:
> unregister_netdev(dev);
> - cancel_delayed_work_sync(&vi->refill);
> free_vqs:
> vdev->config->del_vqs(vdev);
> free_stats:
> @@ -1121,9 +1132,7 @@ static void __devexit virtnet_remove(str
> /* Stop all the virtqueues. */
> vdev->config->reset(vdev);
>
> -
> unregister_netdev(vi->dev);
> - cancel_delayed_work_sync(&vi->refill);
>
> /* Free unused buffers in both send and recv, if any. */
> free_unused_bufs(vi);
^ permalink raw reply
* Re: [PATCH net-next 2/2] e100: enable transmit time stamping.
From: Richard Cochran @ 2012-04-04 9:30 UTC (permalink / raw)
To: Jeff Kirsher; +Cc: netdev@vger.kernel.org, David Miller
In-Reply-To: <1333530283.3046.14.camel@jtkirshe-mobl>
On Wed, Apr 04, 2012 at 02:04:43AM -0700, Jeff Kirsher wrote:
>
> I had this patch in my queue, but during testing we found some serious
> issues with some adapters. With every 82559 based adapter Aaron tried
> the system would panic on driver load. This included at least one
> sampling of D101S and D101M. Every other e100 chipset Aaron tried
> (82557, 82558, 82550) appeared to work fine.
>
> So I am dropping this patch as is due to the kernel panics.
Okay, fine. That driver is strangely written, with weird callbacks and
passing function pointers around.
Taking a second look, I think I might have found the problem. The
drivers casts a firmware pointer onto a skb, and my patch then tries
to timestamp the firmware blob.
If I rework this, are you willing to give it another try?
Thanks,
Richard
^ 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