* Re: [PATCH v8 0/2] Ethernet drivers for WIZnet chips
From: Mike Sinkovsky @ 2012-04-05 5:36 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-kernel, broonie
In-Reply-To: <20120404.211506.929057223227809703.davem@davemloft.net>
05.04.2012 7:15, David Miller wrote:
> From: Mike Sinkovsky<msink@trikom.ru>
> Date: Wed, 4 Apr 2012 17:57:38 +0600
>
>> 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>
>
> I don't see the appropriate changes in your patches to make
> sure that drivers/net/ethernet/{Kconfig,Makefile} consider
> and traverse down into the wiznet/ subdirectory.
>
> Furthermore, once that is fixed these drivers generate warnings
> when built:
>
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.suspend’) [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.resume’) [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.freeze’) [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.thaw’) [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.poweroff’) [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
> drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.restore’) [enabled by default]
>
> It seems that the arguments and return types for these operations have
> changed since you worked on these patches, but this should be easy
> to fix up.
>
> Please cure these two issues and I'll happily put these new drivers
> into net-next, and meanwhile you can continue to work with Eric
> Dumazet to correct the TX flow control and locking issues.
>
> Thanks.
Fixed and posted v9.
Thanks.
--
Mike
^ permalink raw reply
* [PATCH v9 2/2] Ethernet driver for the WIZnet W5100 chip
From: Mike Sinkovsky @ 2012-04-05 5:33 UTC (permalink / raw)
To: netdev, linux-kernel, broonie; +Cc: Mike Sinkovsky
In-Reply-To: <1333541339-30776-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 | 12 +
drivers/net/ethernet/wiznet/Makefile | 1 +
drivers/net/ethernet/wiznet/w5100.c | 808 ++++++++++++++++++++++++++++++++++
3 files changed, 821 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/ethernet/wiznet/w5100.c
diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig
index f45cef1..2bb383c 100644
--- a/drivers/net/ethernet/wiznet/Kconfig
+++ b/drivers/net/ethernet/wiznet/Kconfig
@@ -17,6 +17,18 @@ config NET_VENDOR_WIZNET
if NET_VENDOR_WIZNET
+config WIZNET_W5100
+ tristate "WIZnet W5100 Ethernet support"
+ ---help---
+ Support for WIZnet W5100 chips.
+
+ W5100 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 w5100.
+
config WIZNET_W5300
tristate "WIZnet W5300 Ethernet support"
---help---
diff --git a/drivers/net/ethernet/wiznet/Makefile b/drivers/net/ethernet/wiznet/Makefile
index 88e0a3e..c614535 100644
--- a/drivers/net/ethernet/wiznet/Makefile
+++ b/drivers/net/ethernet/wiznet/Makefile
@@ -1 +1,2 @@
+obj-$(CONFIG_WIZNET_W5100) += w5100.o
obj-$(CONFIG_WIZNET_W5300) += w5300.o
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
new file mode 100644
index 0000000..c28e1d5
--- /dev/null
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -0,0 +1,808 @@
+/*
+ * Ethernet driver for the WIZnet W5100 chip.
+ *
+ * Copyright (C) 2006-2008 WIZnet Co.,Ltd.
+ * 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 "w5100"
+#define DRV_VERSION "2012-04-04"
+
+MODULE_DESCRIPTION("WIZnet W5100 Ethernet driver v"DRV_VERSION);
+MODULE_AUTHOR("Mike Sinkovsky <msink@permonline.ru>");
+MODULE_ALIAS("platform:"DRV_NAME);
+MODULE_LICENSE("GPL");
+
+/*
+ * Registers
+ */
+#define W5100_COMMON_REGS 0x0000
+#define W5100_MR 0x0000 /* Mode Register */
+#define MR_RST 0x80 /* S/W reset */
+#define MR_PB 0x10 /* Ping block */
+#define MR_AI 0x02 /* Address Auto-Increment */
+#define MR_IND 0x01 /* Indirect mode */
+#define W5100_SHAR 0x0009 /* Source MAC address */
+#define W5100_IR 0x0015 /* Interrupt Register */
+#define W5100_IMR 0x0016 /* Interrupt Mask Register */
+#define IR_S0 0x01 /* S0 interrupt */
+#define W5100_RTR 0x0017 /* Retry Time-value Register */
+#define RTR_DEFAULT 2000 /* =0x07d0 (2000) */
+#define W5100_RMSR 0x001a /* Receive Memory Size */
+#define W5100_TMSR 0x001b /* Transmit Memory Size */
+#define W5100_COMMON_REGS_LEN 0x0040
+
+#define W5100_S0_REGS 0x0400
+#define W5100_S0_MR 0x0400 /* S0 Mode Register */
+#define S0_MR_MACRAW 0x04 /* MAC RAW mode (promiscous) */
+#define S0_MR_MACRAW_MF 0x44 /* MAC RAW mode (filtered) */
+#define W5100_S0_CR 0x0401 /* S0 Command Register */
+#define S0_CR_OPEN 0x01 /* OPEN command */
+#define S0_CR_CLOSE 0x10 /* CLOSE command */
+#define S0_CR_SEND 0x20 /* SEND command */
+#define S0_CR_RECV 0x40 /* RECV command */
+#define W5100_S0_IR 0x0402 /* S0 Interrupt Register */
+#define S0_IR_SENDOK 0x10 /* complete sending */
+#define S0_IR_RECV 0x04 /* receiving data */
+#define W5100_S0_SR 0x0403 /* S0 Status Register */
+#define S0_SR_MACRAW 0x42 /* mac raw mode */
+#define W5100_S0_TX_FSR 0x0420 /* S0 Transmit free memory size */
+#define W5100_S0_TX_RD 0x0422 /* S0 Transmit memory read pointer */
+#define W5100_S0_TX_WR 0x0424 /* S0 Transmit memory write pointer */
+#define W5100_S0_RX_RSR 0x0426 /* S0 Receive free memory size */
+#define W5100_S0_RX_RD 0x0428 /* S0 Receive memory read pointer */
+#define W5100_S0_REGS_LEN 0x0040
+
+#define W5100_TX_MEM_START 0x4000
+#define W5100_TX_MEM_END 0x5fff
+#define W5100_TX_MEM_MASK 0x1fff
+#define W5100_RX_MEM_START 0x6000
+#define W5100_RX_MEM_END 0x7fff
+#define W5100_RX_MEM_MASK 0x1fff
+
+/*
+ * Device driver private data structure
+ */
+struct w5100_priv {
+ void __iomem *base;
+ spinlock_t reg_lock;
+ bool indirect;
+ u8 (*read)(struct w5100_priv *priv, u16 addr);
+ void (*write)(struct w5100_priv *priv, u16 addr, u8 data);
+ u16 (*read16)(struct w5100_priv *priv, u16 addr);
+ void (*write16)(struct w5100_priv *priv, u16 addr, u16 data);
+ void (*readbuf)(struct w5100_priv *priv, u16 addr, u8 *buf, int len);
+ void (*writebuf)(struct w5100_priv *priv, u16 addr, u8 *buf, int len);
+ 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 W5100 registers
+ * after mapping to Memory-Mapped I/O space.
+ *
+ * 0x8000 bytes are required for memory space.
+ */
+static inline u8 w5100_read_direct(struct w5100_priv *priv, u16 addr)
+{
+ return ioread8(priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT));
+}
+
+static inline void w5100_write_direct(struct w5100_priv *priv,
+ u16 addr, u8 data)
+{
+ iowrite8(data, priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT));
+}
+
+static u16 w5100_read16_direct(struct w5100_priv *priv, u16 addr)
+{
+ u16 data;
+ data = w5100_read_direct(priv, addr) << 8;
+ data |= w5100_read_direct(priv, addr + 1);
+ return data;
+}
+
+static void w5100_write16_direct(struct w5100_priv *priv, u16 addr, u16 data)
+{
+ w5100_write_direct(priv, addr, data >> 8);
+ w5100_write_direct(priv, addr + 1, data);
+}
+
+static void w5100_readbuf_direct(struct w5100_priv *priv,
+ u16 offset, u8 *buf, int len)
+{
+ u16 addr = W5100_RX_MEM_START + (offset & W5100_RX_MEM_MASK);
+ int i;
+
+ for (i = 0; i < len; i++, addr++) {
+ if (unlikely(addr > W5100_RX_MEM_END))
+ addr = W5100_RX_MEM_START;
+ *buf++ = w5100_read_direct(priv, addr);
+ }
+}
+
+static void w5100_writebuf_direct(struct w5100_priv *priv,
+ u16 offset, u8 *buf, int len)
+{
+ u16 addr = W5100_TX_MEM_START + (offset & W5100_TX_MEM_MASK);
+ int i;
+
+ for (i = 0; i < len; i++, addr++) {
+ if (unlikely(addr > W5100_TX_MEM_END))
+ addr = W5100_TX_MEM_START;
+ w5100_write_direct(priv, addr, *buf++);
+ }
+}
+
+/*
+ * 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 0x04 bytes are required for memory space.
+ */
+#define W5100_IDM_AR 0x01 /* Indirect Mode Address Register */
+#define W5100_IDM_DR 0x03 /* Indirect Mode Data Register */
+
+static u8 w5100_read_indirect(struct w5100_priv *priv, u16 addr)
+{
+ unsigned long flags;
+ u8 data;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+ data = w5100_read_direct(priv, W5100_IDM_DR);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+ return data;
+}
+
+static void w5100_write_indirect(struct w5100_priv *priv, u16 addr, u8 data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+ w5100_write_direct(priv, W5100_IDM_DR, data);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+static u16 w5100_read16_indirect(struct w5100_priv *priv, u16 addr)
+{
+ unsigned long flags;
+ u16 data;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+ data = w5100_read_direct(priv, W5100_IDM_DR) << 8;
+ data |= w5100_read_direct(priv, W5100_IDM_DR);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+ return data;
+}
+
+static void w5100_write16_indirect(struct w5100_priv *priv, u16 addr, u16 data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+ w5100_write_direct(priv, W5100_IDM_DR, data >> 8);
+ w5100_write_direct(priv, W5100_IDM_DR, data);
+ mmiowb();
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+static void w5100_readbuf_indirect(struct w5100_priv *priv,
+ u16 offset, u8 *buf, int len)
+{
+ u16 addr = W5100_RX_MEM_START + (offset & W5100_RX_MEM_MASK);
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+
+ for (i = 0; i < len; i++, addr++) {
+ if (unlikely(addr > W5100_RX_MEM_END)) {
+ addr = W5100_RX_MEM_START;
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+ }
+ *buf++ = w5100_read_direct(priv, W5100_IDM_DR);
+ }
+ mmiowb();
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+static void w5100_writebuf_indirect(struct w5100_priv *priv,
+ u16 offset, u8 *buf, int len)
+{
+ u16 addr = W5100_TX_MEM_START + (offset & W5100_TX_MEM_MASK);
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+
+ for (i = 0; i < len; i++, addr++) {
+ if (unlikely(addr > W5100_TX_MEM_END)) {
+ addr = W5100_TX_MEM_START;
+ w5100_write16_direct(priv, W5100_IDM_AR, addr);
+ mmiowb();
+ }
+ w5100_write_direct(priv, W5100_IDM_DR, *buf++);
+ }
+ mmiowb();
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+#if defined(CONFIG_WIZNET_BUS_DIRECT)
+#define w5100_read w5100_read_direct
+#define w5100_write w5100_write_direct
+#define w5100_read16 w5100_read16_direct
+#define w5100_write16 w5100_write16_direct
+#define w5100_readbuf w5100_readbuf_direct
+#define w5100_writebuf w5100_writebuf_direct
+
+#elif defined(CONFIG_WIZNET_BUS_INDIRECT)
+#define w5100_read w5100_read_indirect
+#define w5100_write w5100_write_indirect
+#define w5100_read16 w5100_read16_indirect
+#define w5100_write16 w5100_write16_indirect
+#define w5100_readbuf w5100_readbuf_indirect
+#define w5100_writebuf w5100_writebuf_indirect
+
+#else /* CONFIG_WIZNET_BUS_ANY */
+#define w5100_read priv->read
+#define w5100_write priv->write
+#define w5100_read16 priv->read16
+#define w5100_write16 priv->write16
+#define w5100_readbuf priv->readbuf
+#define w5100_writebuf priv->writebuf
+#endif
+
+static int w5100_command(struct w5100_priv *priv, u16 cmd)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+ w5100_write(priv, W5100_S0_CR, cmd);
+ mmiowb();
+
+ while (w5100_read(priv, W5100_S0_CR) != 0) {
+ if (time_after(jiffies, timeout))
+ return -EIO;
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static void w5100_write_macaddr(struct w5100_priv *priv)
+{
+ struct net_device *ndev = priv->ndev;
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ w5100_write(priv, W5100_SHAR + i, ndev->dev_addr[i]);
+ mmiowb();
+}
+
+static void w5100_hw_reset(struct w5100_priv *priv)
+{
+ w5100_write_direct(priv, W5100_MR, MR_RST);
+ mmiowb();
+ mdelay(5);
+ w5100_write_direct(priv, W5100_MR, priv->indirect ?
+ MR_PB | MR_AI | MR_IND :
+ MR_PB);
+ mmiowb();
+ w5100_write(priv, W5100_IMR, 0);
+ w5100_write_macaddr(priv);
+
+ /* Configure 16K of internal memory
+ * as 8K RX buffer and 8K TX buffer
+ */
+ w5100_write(priv, W5100_RMSR, 0x03);
+ w5100_write(priv, W5100_TMSR, 0x03);
+ mmiowb();
+}
+
+static void w5100_hw_start(struct w5100_priv *priv)
+{
+ w5100_write(priv, W5100_S0_MR, priv->promisc ?
+ S0_MR_MACRAW : S0_MR_MACRAW_MF);
+ mmiowb();
+ w5100_command(priv, S0_CR_OPEN);
+ w5100_write(priv, W5100_IMR, IR_S0);
+ mmiowb();
+}
+
+static void w5100_hw_close(struct w5100_priv *priv)
+{
+ w5100_write(priv, W5100_IMR, 0);
+ mmiowb();
+ w5100_command(priv, S0_CR_CLOSE);
+}
+
+/***********************************************************************
+ *
+ * Device driver functions / callbacks
+ *
+ ***********************************************************************/
+
+static void w5100_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 w5100_get_link(struct net_device *ndev)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ if (gpio_is_valid(priv->link_gpio))
+ return !!gpio_get_value(priv->link_gpio);
+
+ return 1;
+}
+
+static u32 w5100_get_msglevel(struct net_device *ndev)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ return priv->msg_enable;
+}
+
+static void w5100_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ priv->msg_enable = value;
+}
+
+static int w5100_get_regs_len(struct net_device *ndev)
+{
+ return W5100_COMMON_REGS_LEN + W5100_S0_REGS_LEN;
+}
+
+static void w5100_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *_buf)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+ u8 *buf = _buf;
+ u16 i;
+
+ regs->version = 1;
+ for (i = 0; i < W5100_COMMON_REGS_LEN; i++)
+ *buf++ = w5100_read(priv, W5100_COMMON_REGS + i);
+ for (i = 0; i < W5100_S0_REGS_LEN; i++)
+ *buf++ = w5100_read(priv, W5100_S0_REGS + i);
+}
+
+static void w5100_tx_timeout(struct net_device *ndev)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ w5100_hw_reset(priv);
+ w5100_hw_start(priv);
+ ndev->stats.tx_errors++;
+ ndev->trans_start = jiffies;
+ netif_wake_queue(ndev);
+}
+
+static int w5100_start_tx(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+ u16 offset;
+
+ if (IS_ENABLED(CONFIG_WIZNET_TX_FLOW))
+ netif_stop_queue(ndev);
+
+ offset = w5100_read16(priv, W5100_S0_TX_WR);
+ w5100_writebuf(priv, offset, skb->data, skb->len);
+ w5100_write16(priv, W5100_S0_TX_WR, offset + skb->len);
+ mmiowb();
+ ndev->stats.tx_bytes += skb->len;
+ ndev->stats.tx_packets++;
+ dev_kfree_skb(skb);
+
+ w5100_command(priv, S0_CR_SEND);
+
+ return NETDEV_TX_OK;
+}
+
+static int w5100_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct w5100_priv *priv = container_of(napi, struct w5100_priv, napi);
+ struct net_device *ndev = priv->ndev;
+ struct sk_buff *skb;
+ int rx_count;
+ u16 rx_len;
+ u16 offset;
+ u8 header[2];
+
+ for (rx_count = 0; rx_count < budget; rx_count++) {
+ u16 rx_buf_len = w5100_read16(priv, W5100_S0_RX_RSR);
+ if (rx_buf_len == 0)
+ break;
+
+ offset = w5100_read16(priv, W5100_S0_RX_RD);
+ w5100_readbuf(priv, offset, header, 2);
+ rx_len = get_unaligned_be16(header) - 2;
+
+ skb = netdev_alloc_skb_ip_align(ndev, rx_len);
+ if (unlikely(!skb)) {
+ w5100_write16(priv, W5100_S0_RX_RD,
+ offset + rx_buf_len);
+ w5100_command(priv, S0_CR_RECV);
+ ndev->stats.rx_dropped++;
+ return -ENOMEM;
+ }
+
+ skb_put(skb, rx_len);
+ w5100_readbuf(priv, offset + 2, skb->data, rx_len);
+ w5100_write16(priv, W5100_S0_RX_RD, offset + 2 + rx_len);
+ mmiowb();
+ w5100_command(priv, S0_CR_RECV);
+ 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) {
+ w5100_write(priv, W5100_IMR, IR_S0);
+ mmiowb();
+ napi_complete(napi);
+ }
+
+ return rx_count;
+}
+
+static irqreturn_t w5100_interrupt(int irq, void *ndev_instance)
+{
+ struct net_device *ndev = ndev_instance;
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ int ir = w5100_read(priv, W5100_S0_IR);
+ if (!ir)
+ return IRQ_NONE;
+ w5100_write(priv, W5100_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)) {
+ w5100_write(priv, W5100_IMR, 0);
+ mmiowb();
+ __napi_schedule(&priv->napi);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t w5100_detect_link(int irq, void *ndev_instance)
+{
+ struct net_device *ndev = ndev_instance;
+ struct w5100_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 w5100_set_rx_mode(struct net_device *ndev)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+ bool set_promisc = (ndev->flags & IFF_PROMISC) != 0;
+
+ if (priv->promisc != set_promisc) {
+ priv->promisc = set_promisc;
+ w5100_hw_start(priv);
+ }
+}
+
+static int w5100_set_macaddr(struct net_device *ndev, void *addr)
+{
+ struct w5100_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;
+ w5100_write_macaddr(priv);
+ return 0;
+}
+
+static int w5100_open(struct net_device *ndev)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ netif_info(priv, ifup, ndev, "enabling\n");
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ return -EINVAL;
+ w5100_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 w5100_stop(struct net_device *ndev)
+{
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ netif_info(priv, ifdown, ndev, "shutting down\n");
+ w5100_hw_close(priv);
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+ return 0;
+}
+
+static const struct ethtool_ops w5100_ethtool_ops = {
+ .get_drvinfo = w5100_get_drvinfo,
+ .get_msglevel = w5100_get_msglevel,
+ .set_msglevel = w5100_set_msglevel,
+ .get_link = w5100_get_link,
+ .get_regs_len = w5100_get_regs_len,
+ .get_regs = w5100_get_regs,
+};
+
+static const struct net_device_ops w5100_netdev_ops = {
+ .ndo_open = w5100_open,
+ .ndo_stop = w5100_stop,
+ .ndo_start_xmit = w5100_start_tx,
+ .ndo_tx_timeout = w5100_tx_timeout,
+ .ndo_set_rx_mode = w5100_set_rx_mode,
+ .ndo_set_mac_address = w5100_set_macaddr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static int __devinit w5100_hw_probe(struct platform_device *pdev)
+{
+ struct wiznet_platform_data *data = pdev->dev.platform_data;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5100_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 < W5100_BUS_DIRECT_SIZE;
+ if (priv->indirect) {
+ priv->read = w5100_read_indirect;
+ priv->write = w5100_write_indirect;
+ priv->read16 = w5100_read16_indirect;
+ priv->write16 = w5100_write16_indirect;
+ priv->readbuf = w5100_readbuf_indirect;
+ priv->writebuf = w5100_writebuf_indirect;
+ } else {
+ priv->read = w5100_read_direct;
+ priv->write = w5100_write_direct;
+ priv->read16 = w5100_read16_direct;
+ priv->write16 = w5100_write16_direct;
+ priv->readbuf = w5100_readbuf_direct;
+ priv->writebuf = w5100_writebuf_direct;
+ }
+
+ w5100_hw_reset(priv);
+ if (w5100_read16(priv, W5100_RTR) != RTR_DEFAULT)
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ ret = request_irq(irq, w5100_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, w5100_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 w5100_probe(struct platform_device *pdev)
+{
+ struct w5100_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 = &w5100_netdev_ops;
+ ndev->ethtool_ops = &w5100_ethtool_ops;
+ ndev->watchdog_timeo = HZ;
+ netif_napi_add(ndev, &priv->napi, w5100_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 = w5100_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 w5100_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ w5100_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 w5100_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ netif_carrier_off(ndev);
+ netif_device_detach(ndev);
+
+ w5100_hw_close(priv);
+ }
+ return 0;
+}
+
+static int w5100_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct w5100_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ w5100_hw_reset(priv);
+ w5100_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(w5100_pm_ops, w5100_suspend, w5100_resume);
+
+static struct platform_driver w5100_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &w5100_pm_ops,
+ },
+ .probe = w5100_probe,
+ .remove = __devexit_p(w5100_remove),
+};
+
+module_platform_driver(w5100_driver);
--
1.6.3.3
^ permalink raw reply related
* [PATCH v9 1/2] Ethernet driver for the WIZnet W5300 chip
From: Mike Sinkovsky @ 2012-04-05 5:33 UTC (permalink / raw)
To: netdev, linux-kernel, broonie; +Cc: Mike Sinkovsky
In-Reply-To: <1333541339-30776-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/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/wiznet/Kconfig | 65 +++
drivers/net/ethernet/wiznet/Makefile | 1 +
drivers/net/ethernet/wiznet/w5300.c | 722 ++++++++++++++++++++++++++++++++++
include/linux/platform_data/wiznet.h | 24 ++
6 files changed, 814 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/Kconfig b/drivers/net/ethernet/Kconfig
index c63a64c..a11af5c 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -174,6 +174,7 @@ source "drivers/net/ethernet/tile/Kconfig"
source "drivers/net/ethernet/toshiba/Kconfig"
source "drivers/net/ethernet/tundra/Kconfig"
source "drivers/net/ethernet/via/Kconfig"
+source "drivers/net/ethernet/wiznet/Kconfig"
source "drivers/net/ethernet/xilinx/Kconfig"
source "drivers/net/ethernet/xircom/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 9676a51..878ad32 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -73,5 +73,6 @@ obj-$(CONFIG_TILE_NET) += tile/
obj-$(CONFIG_NET_VENDOR_TOSHIBA) += toshiba/
obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundra/
obj-$(CONFIG_NET_VENDOR_VIA) += via/
+obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig
new file mode 100644
index 0000000..f45cef1
--- /dev/null
+++ b/drivers/net/ethernet/wiznet/Kconfig
@@ -0,0 +1,65 @@
+#
+# 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"
+ default y
+ 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..88afde9
--- /dev/null
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -0,0 +1,722 @@
+/*
+ * 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 device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ 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 device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ 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 v9 0/2] Ethernet drivers for WIZnet chips
From: Mike Sinkovsky @ 2012-04-05 5:33 UTC (permalink / raw)
To: netdev, linux-kernel, broonie; +Cc: Mike Sinkovsky
In-Reply-To: <1333541339-30776-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>
---
v9:
- fixed suspend()/restore() parameters
- restored references to wiznet/ subdirectory in
drivers/net/ethernet/{Kconfig,Makefile}, somewhat lost when
rebasing to net-next tree
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
* Re: [PATCH net-next] net: sh_eth: add support R8A7740
From: Kuninori Morimoto @ 2012-04-05 4:53 UTC (permalink / raw)
To: Shimoda, Yoshihiro; +Cc: netdev, SH-Linux
In-Reply-To: <4F7D2176.3030807@renesas.com>
Hi
> The R8A7740 has a Gigabit Ethernet MAC. This patch supports it.
>
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> ---
This patch works well on R8A7740/Armadillo800eva board
Tested-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Best regards
---
Kuninori Morimoto
^ permalink raw reply
* [PATCH net-next] net: sh_eth: add support R8A7740
From: Shimoda, Yoshihiro @ 2012-04-05 4:37 UTC (permalink / raw)
To: netdev; +Cc: SH-Linux
The R8A7740 has a Gigabit Ethernet MAC. This patch supports it.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/net/ethernet/renesas/Kconfig | 7 +-
drivers/net/ethernet/renesas/sh_eth.c | 114 ++++++++++++++++++++++++++++++++-
drivers/net/ethernet/renesas/sh_eth.h | 5 +-
3 files changed, 120 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig
index 3fb2355..46df3a0 100644
--- a/drivers/net/ethernet/renesas/Kconfig
+++ b/drivers/net/ethernet/renesas/Kconfig
@@ -4,11 +4,11 @@
config SH_ETH
tristate "Renesas SuperH Ethernet support"
- depends on SUPERH && \
+ depends on (SUPERH || ARCH_SHMOBILE) && \
(CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \
- CPU_SUBTYPE_SH7757)
+ CPU_SUBTYPE_SH7757 || ARCH_R8A7740)
select CRC32
select NET_CORE
select MII
@@ -17,4 +17,5 @@ config SH_ETH
---help---
Renesas SuperH Ethernet device driver.
This driver supporting CPUs are:
- - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763 and SH7757.
+ - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757,
+ and R8A7740.
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index d63e09b..be3c221 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -386,6 +386,114 @@ static void sh_eth_reset_hw_crc(struct net_device *ndev)
sh_eth_write(ndev, 0x0, CSMR);
}
+#elif defined(CONFIG_ARCH_R8A7740)
+#define SH_ETH_HAS_TSU 1
+static void sh_eth_chip_reset(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ unsigned long mii;
+
+ /* reset device */
+ sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR);
+ mdelay(1);
+
+ switch (mdp->phy_interface) {
+ case PHY_INTERFACE_MODE_GMII:
+ mii = 2;
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ mii = 1;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ default:
+ mii = 0;
+ break;
+ }
+ sh_eth_write(ndev, mii, RMII_MII);
+}
+
+static void sh_eth_reset(struct net_device *ndev)
+{
+ int cnt = 100;
+
+ sh_eth_write(ndev, EDSR_ENALL, EDSR);
+ sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR);
+ while (cnt > 0) {
+ if (!(sh_eth_read(ndev, EDMR) & 0x3))
+ break;
+ mdelay(1);
+ cnt--;
+ }
+ if (cnt == 0)
+ printk(KERN_ERR "Device reset fail\n");
+
+ /* Table Init */
+ sh_eth_write(ndev, 0x0, TDLAR);
+ sh_eth_write(ndev, 0x0, TDFAR);
+ sh_eth_write(ndev, 0x0, TDFXR);
+ sh_eth_write(ndev, 0x0, TDFFR);
+ sh_eth_write(ndev, 0x0, RDLAR);
+ sh_eth_write(ndev, 0x0, RDFAR);
+ sh_eth_write(ndev, 0x0, RDFXR);
+ sh_eth_write(ndev, 0x0, RDFFR);
+}
+
+static void sh_eth_set_duplex(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+
+ if (mdp->duplex) /* Full */
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
+ else /* Half */
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
+}
+
+static void sh_eth_set_rate(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+
+ switch (mdp->speed) {
+ case 10: /* 10BASE */
+ sh_eth_write(ndev, GECMR_10, GECMR);
+ break;
+ case 100:/* 100BASE */
+ sh_eth_write(ndev, GECMR_100, GECMR);
+ break;
+ case 1000: /* 1000BASE */
+ sh_eth_write(ndev, GECMR_1000, GECMR);
+ break;
+ default:
+ break;
+ }
+}
+
+/* R8A7740 */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+ .chip_reset = sh_eth_chip_reset,
+ .set_duplex = sh_eth_set_duplex,
+ .set_rate = sh_eth_set_rate,
+
+ .ecsr_value = ECSR_ICD | ECSR_MPD,
+ .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+
+ .tx_check = EESR_TC1 | EESR_FTC,
+ .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
+ EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
+ EESR_ECI,
+ .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
+ EESR_TFE,
+
+ .apr = 1,
+ .mpr = 1,
+ .tpauser = 1,
+ .bculr = 1,
+ .hw_swap = 1,
+ .no_trimd = 1,
+ .no_ade = 1,
+ .tsu = 1,
+};
+
#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
#define SH_ETH_RESET_DEFAULT 1
static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
@@ -443,7 +551,7 @@ static void sh_eth_reset(struct net_device *ndev)
}
#endif
-#if defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
static void sh_eth_set_receive_align(struct sk_buff *skb)
{
int reserve;
@@ -919,6 +1027,10 @@ static int sh_eth_rx(struct net_device *ndev)
desc_status = edmac_to_cpu(mdp, rxdesc->status);
pkt_len = rxdesc->frame_length;
+#if defined(CONFIG_ARCH_R8A7740)
+ desc_status >>= 16;
+#endif
+
if (--boguscnt < 0)
break;
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 0fa14af..57b8e1f 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -372,7 +372,7 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
};
/* Driver's parameters */
-#if defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
#define SH4_SKB_RX_ALIGN 32
#else
#define SH2_SH3_SKB_RX_ALIGN 2
@@ -381,7 +381,8 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
/*
* Register's bits
*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763)
+#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) ||\
+ defined(CONFIG_ARCH_R8A7740)
/* EDSR */
enum EDSR_BIT {
EDSR_ENT = 0x01, EDSR_ENR = 0x02,
--
1.7.1
^ permalink raw reply related
* Re: linux-next: build failure after merge of the final tree (net-next tree related)
From: David Miller @ 2012-04-05 3:59 UTC (permalink / raw)
To: sfr
Cc: netdev, linux-next, linux-kernel, deepak.sikri, shiraz.hashim,
vikas.manocha, peppe.cavallaro
In-Reply-To: <20120405132515.e61465875407a452c1a6f78e@canb.auug.org.au>
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Thu, 5 Apr 2012 13:25:15 +1000
> After merging the final tree, today's linux-next build (powerpc
> allyesconfig) failed like this:
>
> drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c: In function 'stmmac_probe_config_dt':
> drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c:53:7: error: 'struct plat_stmmacenet_data' has no member named 'pbl'
>
> Caused by commit 8327eb65e795 ("stmmac: re-work the internal GMAC DMA
> platf parameters"). Clearly I am missing something, because I can't see
> how that patch is correct since nothing ever assigns to the new dma_cfg
> pointer but it is dereferenced.
>
> I have added this patch to make it build today, but it is obviously not
> correct.
Sorry Stephen.
Giuseppe don't submit patches to me that don't even compile.
Please submit a proper fix to me for this _now_.
^ permalink raw reply
* Re: [PATCH v2] ipv6: fix array index in ip6_mc_add_src()
From: David Miller @ 2012-04-05 4:01 UTC (permalink / raw)
To: roy.qing.li; +Cc: netdev
In-Reply-To: <1333594024-24347-1-git-send-email-roy.qing.li@gmail.com>
From: roy.qing.li@gmail.com
Date: Thu, 5 Apr 2012 10:47:04 +0800
> From: RongQing.Li <roy.qing.li@gmail.com>
>
> Convert array index from the loop bound to the loop index.
>
> And remove the void type conversion to ip6_mc_del1_src() return
> code, seem it is unnecessary, since ip6_mc_del1_src() does not
> use __must_check similar attribute, no compiler will report the
> warning when it is removed.
>
> v2: enrich the commit header
>
> Signed-off-by: RongQing.Li <roy.qing.li@gmail.com>
Applied and queued up for -stable, thank you.
^ permalink raw reply
* linux-next: build failure after merge of the final tree (net-next tree related)
From: Stephen Rothwell @ 2012-04-05 3:25 UTC (permalink / raw)
To: David Miller, netdev
Cc: linux-next, linux-kernel, Deepak SIKRI, Shiraz Hashim,
Vikas Manocha, Giuseppe Cavallaro
[-- Attachment #1: Type: text/plain, Size: 1636 bytes --]
Hi all,
After merging the final tree, today's linux-next build (powerpc
allyesconfig) failed like this:
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c: In function 'stmmac_probe_config_dt':
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c:53:7: error: 'struct plat_stmmacenet_data' has no member named 'pbl'
Caused by commit 8327eb65e795 ("stmmac: re-work the internal GMAC DMA
platf parameters"). Clearly I am missing something, because I can't see
how that patch is correct since nothing ever assigns to the new dma_cfg
pointer but it is dereferenced.
I have added this patch to make it build today, but it is obviously not
correct.
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Thu, 5 Apr 2012 13:19:21 +1000
Subject: [PATCH] stmmac: hack to make it build
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 116529a..1e4d12d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -50,7 +50,7 @@ static int __devinit stmmac_probe_config_dt(struct platform_device *pdev,
* once needed on other platforms.
*/
if (of_device_is_compatible(np, "st,spear600-gmac")) {
- plat->pbl = 8;
+/* plat->pbl = 8; */
plat->has_gmac = 1;
plat->pmt = 1;
}
--
1.7.10.rc3
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply related
* [PATCH v2] ipv6: fix array index in ip6_mc_add_src()
From: roy.qing.li @ 2012-04-05 2:47 UTC (permalink / raw)
To: netdev
From: RongQing.Li <roy.qing.li@gmail.com>
Convert array index from the loop bound to the loop index.
And remove the void type conversion to ip6_mc_del1_src() return
code, seem it is unnecessary, since ip6_mc_del1_src() does not
use __must_check similar attribute, no compiler will report the
warning when it is removed.
v2: enrich the commit header
Signed-off-by: RongQing.Li <roy.qing.li@gmail.com>
---
net/ipv6/mcast.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 16c33e3..c6378de 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2044,7 +2044,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
if (!delta)
pmc->mca_sfcount[sfmode]--;
for (j=0; j<i; j++)
- (void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+ ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]);
} else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
struct ip6_sf_list *psf;
--
1.7.1
^ permalink raw reply related
* Re: 3.3.0, 3.4-rc1 reproducible tun Oops
From: Eric Dumazet @ 2012-04-05 2:41 UTC (permalink / raw)
To: Simon Kirby; +Cc: netdev
In-Reply-To: <20120404220525.GD21505@hostway.ca>
On Wed, 2012-04-04 at 15:05 -0700, Simon Kirby wrote:
> I use an SSH VPN occasionally from home, and since upgrading the
> remote
> kernel to 3.3.0, the it now seems to Oops when I ^C the tunnel with
> sockets still active. If I start the tunnel, log in to a box through
> it
> and run "vmstat 1", ^C the tunnel SSH process, and start it up again,
> I
> get an Oops like this:
>
> BUG: unable to handle kernel NULL pointer dereference at
> 00000000000000ff
> IP: [<ffffffff810ed5fa>] __kmalloc_track_caller+0xaa/0x1b0
> PGD 12d2bc067 PUD 0
> Oops: 0000 [#1] SMP
> CPU 1
> Modules linked in: nf_conntrack_netlink nfnetlink iptable_mangle
> ipt_MASQUERADE xt_state xt_conntrack iptable_nat nf_nat
> nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack hwmon_vid ppp_async
> ppp_generic slhc crc_ccitt tun nvidia(PO) uvcvideo videobuf2_vmalloc
> videobuf2_memops videobuf2_core e100
>
> Pid: 16156, comm: sshd Tainted: P O 3.3.0 #32 System
> manufacturer System Product Name/A8N-VM CSM
Hmm, is it happening if you remove the nvidia module ?
If yes, please try to add slub_debug=FZPU
CONFIG_SLUB_DEBUG=y
CONFIG_SLUB=y
# CONFIG_SLUB_DEBUG_ON is not set
^ permalink raw reply
* Despite of traffic control on host netdevice, is it worth to impose a limit control on qemu emulated net device?
From: Liu ping fan @ 2012-04-05 2:30 UTC (permalink / raw)
To: qemu-devel, netdev
Cc: Eric Dumazet, David S. Miller, Stefan Hajnoczi, Anthony Liguori,
linux-kernel
Hi,
As we know, in order to control the guest OS's TX rate limit, we can
apply rate limit on ingress Qdisc of host's tap device.
But I think skb will be dropped on host's tap ingress Qdisc, which
means that for those protocol lacking of congestion control such as
UDP, it will cost a lot of meaningless time to produce dropped packet
.
What about introducing rate limit on qemu's emulated net device? I
think guest's UDP transaction will be blocked at wait_for_wmem.
Thanks and regards,
pingfan
^ permalink raw reply
* Re: [RFC] net:phy:phylib: phy shares the same interrupt with mac
From: Jason Lin @ 2012-04-05 1:30 UTC (permalink / raw)
To: Florian Fainelli; +Cc: netdev
In-Reply-To: <4F7AB9AC.8000708@openwrt.org>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=GB2312, Size: 5470 bytes --]
But, I need to enable PHY's interrupt by setting PHY's registers.
And after producing a interrupt, there needs a workqueue
to ack the PHY's interrupt.
The phy_start_interrupts() can enable PHY's interrupt.
If I do the following:
1) set phydev->irq = PHY_IGNORE_INTERRUPT;
2) invoke phy_connect();
3) phy_conenct() -> phy_connect_direct() ->
if (phydev->irq > 0)
phy_start_interrupts(phydev);
4) PHY_IGNORE_INTERRUPT = -2, it will not enable PHY's interrupt.
5) phy_start_interrupts() will connect to a callback function
config_intr() of each PHY library.
For example, drivers/net/phy/marvell.c, marvell_config_intr()
Need to set register 0x12 to 0x6400 to enable corresponding interrupts.
Any comments are appreciated.
Thanks.
ÔÚ 2012Äê4ÔÂ3ÈÕÏÂÎç4:49£¬Florian Fainelli <florian@openwrt.org> µÀ£º
> Hi,
>
> Le 04/03/12 04:11, Jason Lin a ¨¦crit :
>
>> 1) Add a new definition PHY_MAC if phy shares the same
>> interrupt with mac.
>> 2) Add do_phy_workqueue(), that mac can invoke this function
>> in its ISR when link status changed or other conditions.
>>
>> Does this seems reasonable?
>
>
> No, I think this is well handled by the PHY_IGNORE_INTERRUPT case
> (documented in Documentation/networking/phy.txt) by doing the following:
>
> - distinguish between MAC and PHY interrupts in your MAC interrupt handler
> (most likely you have separate bits for PHY interrupts)
> - once you see a PHY interrupt, call the appropriate PHY state machine
> callbacks to update the PHY state machine
>
>>
>>
>> ---------------------------
>> drivers/net/phy/phy.c | 27 +++++++++++++++++++++++++++
>> drivers/net/phy/phy_device.c | 4 ++--
>> include/linux/phy.h | 3 +++
>> 3 files changed, 32 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
>> index 7670aac..c8009e9 100644
>> --- a/drivers/net/phy/phy.c
>> +++ b/drivers/net/phy/phy.c
>> @@ -527,6 +527,28 @@ static irqreturn_t phy_interrupt(int irq, void
>> *phy_dat)
>> return IRQ_HANDLED;
>> }
>>
>> +/*
>> + * do_phy_workqueue - PHY interrupt handler used by MAC
>> + * @irq: interrupt line
>> + * @phydev: phy_device pointer
>> + *
>> + * Description: When a PHY use the same interrupt with MAC,
>> + * the handler is invoked by MAC, and schedules a work task
>> + * to clear the PHY's interrupt.
>> + * This handler is invoked only in MAC's ISR.
>> + */
>> +irqreturn_t do_phy_workqueue(int irq, struct phy_device *phydev) {
>> +
>> + BUG_ON(!in_interrupt());
>> +
>> + if (PHY_HALTED == phydev->state)
>> + return IRQ_NONE;
>> +
>> + schedule_work(&phydev->phy_queue);
>> + return IRQ_HANDLED;
>> +}
>> +EXPORT_SYMBOL(do_phy_workqueue);
>> +
>> /**
>> * phy_enable_interrupts - Enable the interrupts from the PHY side
>> * @phydev: target phy_device struct
>> @@ -589,6 +611,11 @@ int phy_start_interrupts(struct phy_device *phydev)
>>
>> INIT_WORK(&phydev->phy_queue, phy_change);
>>
>> + if (phydev->irq == PHY_MAC) {
>> + err = phy_enable_interrupts(phydev);
>> + return err;
>> + }
>> +
>> atomic_set(&phydev->irq_disable, 0);
>> if (request_irq(phydev->irq, phy_interrupt,
>> IRQF_SHARED,
>> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
>> index 993c52c..1857097 100644
>> --- a/drivers/net/phy/phy_device.c
>> +++ b/drivers/net/phy/phy_device.c
>> @@ -345,7 +345,7 @@ int phy_connect_direct(struct net_device *dev,
>> struct phy_device *phydev,
>>
>> phy_prepare_link(phydev, handler);
>> phy_start_machine(phydev, NULL);
>> - if (phydev->irq> 0)
>> + if ((phydev->irq> 0) || (phydev->irq == PHY_MAC))
>> phy_start_interrupts(phydev);
>>
>> return 0;
>> @@ -399,7 +399,7 @@ EXPORT_SYMBOL(phy_connect);
>> */
>> void phy_disconnect(struct phy_device *phydev)
>> {
>> - if (phydev->irq> 0)
>> + if ((phydev->irq> 0) || (phydev->irq == PHY_MAC))
>> phy_stop_interrupts(phydev);
>>
>> phy_stop_machine(phydev);
>> diff --git a/include/linux/phy.h b/include/linux/phy.h
>> index 7da5fa8..155822c 100644
>> --- a/include/linux/phy.h
>> +++ b/include/linux/phy.h
>> @@ -44,9 +44,11 @@
>> * Set phydev->irq to PHY_POLL if interrupts are not supported,
>> * or not desired for this PHY. Set to PHY_IGNORE_INTERRUPT if
>> * the attached driver handles the interrupt
>> + * Set to PHY_MAC if using the same interrupt with MAC
>> */
>> #define PHY_POLL -1
>> #define PHY_IGNORE_INTERRUPT -2
>> +#define PHY_MAC -3
>>
>> #define PHY_HAS_INTERRUPT 0x00000001
>> #define PHY_HAS_MAGICANEG 0x00000002
>> @@ -510,6 +512,7 @@ int phy_ethtool_sset(struct phy_device *phydev,
>> struct ethtool_cmd *cmd);
>> int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
>> int phy_mii_ioctl(struct phy_device *phydev,
>> struct ifreq *ifr, int cmd);
>> +irqreturn_t do_phy_workqueue(int irq, struct phy_device *phydev);
>> int phy_start_interrupts(struct phy_device *phydev);
>> void phy_print_status(struct phy_device *phydev);
>> void phy_device_free(struct phy_device *phydev);
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: bridge: Do not send queries on multicast group leaves
From: David Miller @ 2012-04-05 1:17 UTC (permalink / raw)
To: herbert; +Cc: netdev
In-Reply-To: <20120404110119.GA11576@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.hengli.com.au>
Date: Wed, 4 Apr 2012 19:01:20 +0800
> 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>
Applied and queued up for -stable, thanks Herbert.
^ permalink raw reply
* Re: [PATCH v8 0/2] Ethernet drivers for WIZnet chips
From: David Miller @ 2012-04-05 1:15 UTC (permalink / raw)
To: msink; +Cc: netdev, linux-kernel, broonie, msink
In-Reply-To: <1333540660-30551-1-git-send-email-msink@trikom.ru>
From: Mike Sinkovsky <msink@trikom.ru>
Date: Wed, 4 Apr 2012 17:57:38 +0600
> 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>
I don't see the appropriate changes in your patches to make
sure that drivers/net/ethernet/{Kconfig,Makefile} consider
and traverse down into the wiznet/ subdirectory.
Furthermore, once that is fixed these drivers generate warnings
when built:
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.suspend’) [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.resume’) [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.freeze’) [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.thaw’) [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.poweroff’) [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: initialization from incompatible pointer type [enabled by default]
drivers/net/ethernet/wiznet/w5300.c:708:8: warning: (near initialization for ‘w5300_pm_ops.restore’) [enabled by default]
It seems that the arguments and return types for these operations have
changed since you worked on these patches, but this should be easy
to fix up.
Please cure these two issues and I'll happily put these new drivers
into net-next, and meanwhile you can continue to work with Eric
Dumazet to correct the TX flow control and locking issues.
Thanks.
^ permalink raw reply
* Re: bridge: Do not send queries on multicast group leaves
From: Herbert Xu @ 2012-04-05 0:58 UTC (permalink / raw)
To: Dave Taht; +Cc: David S. Miller, netdev
In-Reply-To: <CAA93jw658iHuuYWSz7QrV3ZHOvn1gL7DxAtFfQ0gos6jZjTKiw@mail.gmail.com>
On Wed, Apr 04, 2012 at 08:52:52AM -0700, Dave Taht wrote:
>
> 1) Has anyone seen linux working as a multicast router of late? because I
> sure haven't.
Linux works as a multicast router. The functionality is in
user-space and has nothing to do with this whatsoever.
> 2) Does this bridge code change break existing applications of IGMP over a
> lonely bridge?
No.
Cheers,
--
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
* Re: [PATCH net-next V6 7/8] net/dcb: Add an optional max rate attribute
From: Dave Taht @ 2012-04-05 0:39 UTC (permalink / raw)
To: John Fastabend
Cc: Amir Vadai, Or Gerlitz, David S. Miller, netdev, Roland Dreier,
Yevgeny Petrilin, Oren Duer, Amir Vadai
In-Reply-To: <4F7CE61E.7060406@intel.com>
(I try not to pay too much attention to the DCB stuff as it gives me nightmares)
It would comfort me to know if or which of:
Is 802.1au being implemented?
802.3bd?
There was some other standard involving active queue management at
this layer that I can't remember the alphabet soup for that must be
dead in the water at this point..
http://www.ieee802.org/1/files/public/docs2009/au-yasuda-10G-QCN-Implementation-1109.pdf
On Wed, Apr 4, 2012 at 5:23 PM, John Fastabend
<john.r.fastabend@intel.com> wrote:
> On 4/4/2012 3:58 AM, Amir Vadai wrote:
>> 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>
>> ---
>
> Or, Amir,
>
> Two more comments inline really just minor nit picks but if your going
> to roll new patch mind as well. I'll ack a patch with these changes.
>
>> 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];
>> };
>>
>
> annotate ieee_maxrate so implementers use it correctly per previous note.
>
>> +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)},
>> +
>
> spurious newline remove it
>
>> };
>>
>> 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);
>
> align sizeof with skb
>
> Thanks,
> John
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Dave Täht
SKYPE: davetaht
US Tel: 1-239-829-5608
http://www.bufferbloat.net
^ permalink raw reply
* Re: [PATCH] mlx4: allocate just enough pages instead of always 4 pages
From: David Miller @ 2012-04-05 0:34 UTC (permalink / raw)
To: cascardo; +Cc: netdev, roland, ogerlitz, yevgenyp, alexg, klebers
In-Reply-To: <1333568440-14494-1-git-send-email-cascardo@linux.vnet.ibm.com>
From: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
Date: Wed, 4 Apr 2012 16:40:40 -0300
> The driver uses a 2-order allocation, which is too much on architectures
> like ppc64, which has a 64KiB page. This particular allocation is used
> for large packet fragments that may have a size of 512, 1024, 4096 or
> fill the whole allocation. So, a minimum size of 16384 is good enough
> and will be the same size that is used in architectures of 4KiB sized
> pages.
>
> This will avoid allocation failures that we see when the system is under
> stress, but still has plenty of memory, like the one below.
>
> This will also allow us to set the interface MTU to higher values like
> 9000, which was not possible on ppc64 without this patch.
...
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
> Signed-off-by: Kleber Sacilotto de Souza <klebers@linux.vnet.ibm.com>
> Tested-by: Kleber Sacilotto de Souza <klebers@linux.vnet.ibm.com>
Applied, thanks a lot.
^ permalink raw reply
* Re: [PATCH net-next] vxge: Convert macro to inline function
From: David Miller @ 2012-04-05 0:33 UTC (permalink / raw)
To: joe; +Cc: jdmason, netdev, linux-kernel
In-Reply-To: <1333579075.23520.19.camel@joe2Laptop>
From: Joe Perches <joe@perches.com>
Date: Wed, 04 Apr 2012 15:37:55 -0700
> On Tue, 2012-04-03 at 18:18 -0400, David Miller wrote:
>> From: Joe Perches <joe@perches.com>
>> Date: Tue, 03 Apr 2012 15:14:31 -0700
>> > Convert the macro to inline function to check the arguments.
>> > Signed-off-by: Joe Perches <joe@perches.com>
>> > ---
>> >> Longer term I'd much rather see this turned into an inline
>> >> function with proper type checking etc.
>> > Something like this?
>> Yep.
>
> I did sign the patch.
> I was intending that you could apply it.
Ok, I see now, applied. Thanks Joe.
^ permalink raw reply
* Re: [patch net-next 2/2] team: add loadbalance mode
From: David Miller @ 2012-04-05 0:31 UTC (permalink / raw)
To: jpirko
Cc: netdev, eric.dumazet, bhutchings, shemminger, raise.sail,
nuno.martins, matt
In-Reply-To: <1333577787-878-2-git-send-email-jpirko@redhat.com>
From: Jiri Pirko <jpirko@redhat.com>
Date: Thu, 5 Apr 2012 00:16:27 +0200
> This patch introduces new team mode. It's TX port is selected by
> user-set BPF hash function.
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Applied, thanks Jiri.
^ permalink raw reply
* Re: [patch net-next 1/2] team: add binary option type
From: David Miller @ 2012-04-05 0:31 UTC (permalink / raw)
To: jpirko
Cc: netdev, eric.dumazet, bhutchings, shemminger, raise.sail,
nuno.martins, matt
In-Reply-To: <1333577787-878-1-git-send-email-jpirko@redhat.com>
From: Jiri Pirko <jpirko@redhat.com>
Date: Thu, 5 Apr 2012 00:16:26 +0200
> For transfering generic binary data (e.g. BPF code), introduce new
> binary option type.
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH V1 1/1] NET: add a bpf jit for Alpha
From: Jan Seiffert @ 2012-04-05 0:24 UTC (permalink / raw)
To: Richard Henderson
Cc: netdev, linux-kernel, Matt Evans, Eric Dumazet, David S. Miller,
linux-arch, linux-alpha
In-Reply-To: <4F7C5A65.7090504@redhat.com>
Richard Henderson schrieb:
Thanks for the review Mr.Henderson. I'm so grateful you taken some of your
valuable time for this.
> On 04/02/2012 03:51 PM, Jan Seiffert wrote:
[snip]
> You will never need NEGLI or SEXTLI, as both results can be had with LDA.
>
Removed
>> +static void load_complex_constant(u32 *image, struct codegen_context *ctx,
>> + unsigned int i, int K, int r)
>> +
>> +{
>> + if (K == 0) {
>> + ALPHA_CLR(r);
>> + return;
>> + }
>> + if (optimize_size == 0 || constant_needs(K) < 2 ||
>> + i > (0x7fff/sizeof(struct sock_filter))) {
>> + add_constant(image, ctx, K, r_zero, r);
>> + } else {
>> + /* load the constant from the filter program */
>> + ALPHA_LDL(r_sf, (i * sizeof(struct sock_filter)) +
>> + offsetof(struct sock_filter, k), r);
>
> Worst case for constant loading is 3. That's the same as the delay for
> loading from memory. Unless you're very concerned about translated size
> of the filter,
I'm unsure. The problem goes like this:
Since constant loading can take so much instructions, the code tends to
get big. This is bad for jump ranges, the icache and pinned kernel mem.
I would not mind about it (it's a RISC, it is meant to be that way), if
the constants weren't right there. We get the original filter program
(which contains the constants) passed as second parameter, on a silver
platter (i was even thinking about moving the second parameter 32k
forward to get the full imm16 range, on the other hand if struct
sock_filter is 8 byte on Alpha, then +32k is good enough for
MAX_BPF_INSN == 4096).
Essentially this is two questions, one for the Alpha µ-arch gurus and
one for the kernel (net-)devs.
µ-Arch Gurus: How bad are mem accesses in contrast to icache for example.
Kernel devs: how important is memory consumption/how much "faster"
the jitted code has to be?
> I'd drop this condition and make your compiler run faster.
>
>
>> + if (optimize_size == 0 || constant_needs(K) < 2 ||
>> + i > (0x7fff/sizeof(struct sock_filter))) {
>> + add_constant(image, ctx, K, r_A, r_t);
>> + ALPHA_SEXTL(r_t, r_t);
>
> OTOH, this test should be simply is_imm8 and use ADDLI,
> else is_imm8(-K) use SUBLI, else load_constant ADDL.
>
add_constant takes care of that, only the entry condition is so
complicated because of the optimize_size case.
[snip - ugly and optimization]
>
> Really?
yes, i was typing as fast as i was thinking: "hmmm, a constant can
look like this or like that or like this...". The optimizations where an
"afterthought", i first broke the operations out into a helper and simply
made it work. Because i knew there are some shenanigans you can do with
zapnot i revisited it at the end. I will now grab a brown paper bag.
> This ought to be as simple as
>
> mask = 0;
> for (j = 0; j < 4; j++) {
> int b = (K >> i*8) & 0xff;
> if (b == 0xff)
> mask |= 1 << i;
> else if (b != 0)
> mask = -1;
> }
> if (mask != -1) {
> ALPHA_ZAPNOTI(r_A, mask, r_t);
> return;
> }
>
Works like a charm, only had to change i for j. Thanks!
[snip - or 0xffffffff]
>
> Really? Think about what you're doing here. LDA(r_A, -1)
>
changed
[snip]
>> + if (off == 0)
>> + ALPHA_ZEXTW(r, r);
>> + else
>> + ALPHA_EXTWLI(r, off, r);
>
> No point in the off==0 special case.
>
I was thinking maybe the zapnot^wzextw is faster, because it does not
have to do the shift and it should be the common case.
But if extw is good enough, thus removed.
>> +static void emit_call(u32 *image, struct codegen_context *ctx,
>> + void *func, int r)
>> +{
>> + ptrdiff_t disp = (char *)func - (char *)&image[ctx->idx + 1];
>> + if (disp >= -2147483648 && disp <= 2147483647) {
>> + if (is_imm_jdisp(disp)) {
>> + ALPHA_BSR(r, disp);
>> + return;
>> + }
>
> Is this known to be calling another BPF function, and not back into C?
> Otherwise you've got an error in PV handling for the calling convention.
>
It is known to either call special bpf helper or __divlu (the kernel
version). The special helper are responsible for setting pv right when
they have to call to C again (which is deemed as the exceptional case).
That was my idea, so i don't have to set pv again after every call,
which would bloat up every filter program.
But i don't know if the helper do the "pv and call and gp"-dance right :(
[snip - div 0 test]
>
> Re-order these to clear r_ret before the cjmp and you don't need
> the branch-around branch.
>
Can't do.
When building the program we are searching for a ret 0 case.
As long as no case is found (or is never found), we have to build one.
Besides, i know it's dirty, r_ret and r_A share the same register.
I was squeezing on the register usage so i may use the register as
storage for the 16 bpf mem[] slots like powerpc, i mean Alpha has
31 like powerpc. But in the end i was to stupid to achieve this.
At least this hack saves a mov at the end.
>> + case BPF_S_ALU_LSH_X: /* A <<= X; */
>> + ctx->seen |= SEEN_XREG;
>> + ALPHA_SLL(r_A, r_X, r_A);
>> + ALPHA_ZEXTL(r_A, r_A);
>
> So... are you attempting to have canonical zero-extended values,
> or canonical sign-extended values? Because at the moment you have
> a mix of both.
>
I know, and i don't know what i want.
> Either drop the canonicalization and consider high-32 bits as
> garbage (and then explicitly extend whereever necessary) or pick
> one and stick with it. Of course, the sign-extending of addl etc
> will force you to choose sign-extend not zero-extend as canonical.
>
The problem is the bpf cpu is inherently unsigned. It does all loads
zero extended, only has logical shifts, does all compares unsigned.
Which sounds like i have to zero extend like crazy. (i took the
Powerpc code as example, it does most things unsigned and on 32 Bit,
but has similar "add is sign extending" things, so i thought it can't
be that bad, otherwise it would have the same Bugs).
I was hoping to let the sign run it's course/sign extend and only
cut at the right point, and i figured that was a point to cut, i should
prop. sign extend.
But if that is not feasible, i could also sprinkle everything with zero
extends.
>> + case BPF_S_ALU_RSH_X: /* A >>= X; */
>> + ctx->seen |= SEEN_XREG;
>> + ALPHA_SRL(r_A, r_X, r_A);
>> + ALPHA_ZEXTL(r_A, r_A);
>> + break;
>
> Like here. You must zero-extend first to avoid shifting in
> garbage. Afterward you can reason that the value is already
> zero-extended.
>
Oh, thanks!
Yes, the shift operations are only logical shifts, so it has to be properly
zero extended.
[snip - bpf_flush_icache]
>
> imb() is all that is needed.
>
Thanks! I guess i will stick to the flush_icache_range, which is defined to
an imb()/smp_imb(), so should do the right thing(TM).
[snip - comment about pases]
>
> I should think you could do this in exactly one pass, given that there's
> absolutely no need for ultra-long branches.
The first pass is called with image == NULL, so all calls have a very long
displacement + we have to make other worst case/wrong assumptions because
addrs is not properly filled and the exit points are unknown.
The second pass with image == NULL will settle some jumps, because addrs is
now mostly properly populated _and_ the exit points are set.
This is done to get a real good estimate when allocating mem, so not to much
is allocated (saw a thread on lkml where Eric was talking with Ingo about
module_realloc, so the memusage is of concern, it is pinned kernel memory
for the user space).
The other passes are only to make things really slick with image != NULL,
and stop if there is no change.
If i knew some kind of base address where module_alloc will allocate, i
could feed that in early...
> If you're going to scan the
> body for SEEN_MEM etc, you might as well look for your A and X initialization
> at the same time and clean up that hack in the prologue.
>
I was working on a patch for that, but it was more complicated, esp. it may
cost some RAM and/or CPU time just to remove one/two instructions, so i left
it out for the moment till i revisit it.
>> +++ b/arch/alpha/net/bpf_jit_helper.S
>
> It would be helpful to use '$' prefixes here for local variables.
>
???
Sorry, i don't understand what you mean. What variables? Or do you mean
register? It uses the same register as the compiler. So to not confuse
things i made the names from the compiler usable in asm. You can change one
define and the compiler and the helper will use another reg.
>
> r~
>
Greetings
Jan
--
Anyone can build a fast processor. The trick is to build a fast system.
(Seymour Cray)
--
To unsubscribe from this list: send the line "unsubscribe linux-alpha" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH net-next V6 7/8] net/dcb: Add an optional max rate attribute
From: John Fastabend @ 2012-04-05 0:23 UTC (permalink / raw)
To: Amir Vadai, Or Gerlitz
Cc: David S. Miller, netdev, Roland Dreier, Yevgeny Petrilin,
Oren Duer, Amir Vadai
In-Reply-To: <1333537084-9186-8-git-send-email-amirv@mellanox.com>
On 4/4/2012 3:58 AM, Amir Vadai wrote:
> 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>
> ---
Or, Amir,
Two more comments inline really just minor nit picks but if your going
to roll new patch mind as well. I'll ack a patch with these changes.
> 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];
> };
>
annotate ieee_maxrate so implementers use it correctly per previous note.
> +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)},
> +
spurious newline remove it
> };
>
> 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);
align sizeof with skb
Thanks,
John
^ permalink raw reply
* Re: [RFC] net/hsr: Add support for IEC 62439-3 High-availability Seamless Redundancy
From: David Miller @ 2012-04-05 0:21 UTC (permalink / raw)
To: shemminger; +Cc: arvid.brodin, netdev, balferreira, arvid.brodin
In-Reply-To: <20120404165559.5223ab95@s6510.linuxnetplumber.net>
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 4 Apr 2012 16:55:59 -0700
> That isn't so bad, doing a memcpy versus a structure copy.
GCC is going to inline the memcpy and thus we'll still do the
unaligned accesses. This change therefore won't fix the problem.
^ permalink raw reply
* Re: [PATCH 3/3] netdma: adding alignment check for NETDMA ops
From: David Miller @ 2012-04-05 0:18 UTC (permalink / raw)
To: dave.jiang; +Cc: dan.j.williams, linux-kernel, netdev
In-Reply-To: <20120404231046.20605.13918.stgit@djiang5-linux.ch.intel.com>
From: Dave Jiang <dave.jiang@intel.com>
Date: Wed, 04 Apr 2012 16:10:46 -0700
> This is the fallout from adding memcpy alignment workaround for certain
> IOATDMA hardware. NetDMA will only use DMA engine that can handle byte align
> ops.
>
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Acked-by: David S. Miller <davem@davemloft.net>
^ 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