Netdev List
 help / color / mirror / Atom feed
* Re: [atl1-devel] [PATCH 2/2] atl1: wrap problematic optimizations in CONFIG_ATL1_EXPERIMENTAL
From: Chris Snook @ 2007-09-08  0:27 UTC (permalink / raw)
  To: Luca; +Cc: Jeff Garzik, atl1-devel, netdev
In-Reply-To: <68676e00709071721g35c07b0by58991c56e17ec442@mail.gmail.com>

Luca wrote:
> On 9/8/07, Chris Snook <csnook@redhat.com> wrote:
>> From: Chris Snook <csnook@redhat.com>
>>
>> Make certain problematic optimizations build-time configurable.
>>
>> Signed-off-by: Chris Snook <csnook@redhat.com>
>> Acked-by: Jay Cliburn <jacliburn@bellsouth.net>
>>
>> --- a/drivers/net/atl1/atl1_main.c      2007-09-04 10:12:38.000000000 -0400
>> +++ b/drivers/net/atl1/atl1_main.c      2007-09-04 11:23:26.000000000 -0400
>> @@ -2203,22 +2203,26 @@ static int __devinit atl1_probe(struct p
>>         struct net_device *netdev;
>>         struct atl1_adapter *adapter;
>>         static int cards_found = 0;
>> -       bool pci_using_64 = true;
>> +       bool pci_using_64 = false;
>>         int err;
>>
>>         err = pci_enable_device(pdev);
>>         if (err)
>>                 return err;
>>
>> +#ifdef CONFIG_ATL1_EXPERIMENTAL
>>         err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
>> +       if (!err) {
>> +               pci_using_64 = true;
>> +               goto dma_ok;
>> +       }
>> +#endif /* CONFIG_ATL1_EXPERIMENTAL */
> 
> This is more like CONFIG_ATL1_PLEASE_KILL_MY_MACHINE; I really don't
> see the problem with just limiting the DMA mask:
> - if you don't have physical mem over the 4GB boundary limiting DMA
> doesn't make any difference
> - if you have more than 4GB of memory the machine won't survive long without it

Atheros is still working on this, and we plan to fix it.  64-bit DMA *should* 
work.  I just resubmitted your patch with the comment Jeff requested.  I still 
may want to revisit CONFIG_ATL1_EXPERIMENTAL soon when I start playing around 
with more features.

	-- Chris

^ permalink raw reply

* [PATCH] [-MM, FIX V3] e1000e: incorporate napi_struct changes from net-2.6.24.git
From: Auke Kok @ 2007-09-08  0:27 UTC (permalink / raw)
  To: akpm, davem; +Cc: jeff, netdev, auke-jan.h.kok

This incorporates the new napi_struct changes into e1000e. Included
bugfix for ifdown hang from Krishna Kumar for e1000.

Disabling polling is no longer needed at init time, so remove
napi_disable() call from _probe().

Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 drivers/net/e1000e/e1000.h  |    2 ++
 drivers/net/e1000e/netdev.c |   39 ++++++++++++++++-----------------------
 2 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index c57e35a..d2499bb 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -187,6 +187,8 @@ struct e1000_adapter {
 	struct e1000_ring *tx_ring /* One per active queue */
 						____cacheline_aligned_in_smp;
 
+	struct napi_struct napi;
+
 	unsigned long tx_queue_len;
 	unsigned int restart_queue;
 	u32 txd_cmd;
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 372da46..f8ec537 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -1149,12 +1149,12 @@ static irqreturn_t e1000_intr_msi(int irq, void *data)
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-	if (netif_rx_schedule_prep(netdev)) {
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev);
+		__netif_rx_schedule(netdev, &adapter->napi);
 	} else {
 		atomic_dec(&adapter->irq_sem);
 	}
@@ -1212,12 +1212,12 @@ static irqreturn_t e1000_intr(int irq, void *data)
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-	if (netif_rx_schedule_prep(netdev)) {
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev);
+		__netif_rx_schedule(netdev, &adapter->napi);
 	} else {
 		atomic_dec(&adapter->irq_sem);
 	}
@@ -1662,10 +1662,10 @@ set_itr_now:
  * e1000_clean - NAPI Rx polling callback
  * @adapter: board private structure
  **/
-static int e1000_clean(struct net_device *poll_dev, int *budget)
+static int e1000_clean(struct napi_struct *napi, int budget)
 {
-	struct e1000_adapter *adapter;
-	int work_to_do = min(*budget, poll_dev->quota);
+	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+	struct net_device *poll_dev = adapter->netdev;
 	int tx_cleaned = 0, work_done = 0;
 
 	/* Must NOT use netdev_priv macro here. */
@@ -1684,25 +1684,20 @@ static int e1000_clean(struct net_device *poll_dev, int *budget)
 		spin_unlock(&adapter->tx_queue_lock);
 	}
 
-	adapter->clean_rx(adapter, &work_done, work_to_do);
-	*budget -= work_done;
-	poll_dev->quota -= work_done;
+	adapter->clean_rx(adapter, &work_done, budget);
 
 	/* If no Tx and not enough Rx work done, exit the polling mode */
-	if ((!tx_cleaned && (work_done == 0)) ||
+	if ((tx_cleaned && (work_done < budget)) ||
 	   !netif_running(poll_dev)) {
 quit_polling:
 		if (adapter->itr_setting & 3)
 			e1000_set_itr(adapter);
-		netif_rx_complete(poll_dev);
-		if (test_bit(__E1000_DOWN, &adapter->state))
-			atomic_dec(&adapter->irq_sem);
-		else
-			e1000_irq_enable(adapter);
+		netif_rx_complete(poll_dev, napi);
+		e1000_irq_enable(adapter);
 		return 0;
 	}
 
-	return 1;
+	return work_done;
 }
 
 static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -2439,7 +2434,7 @@ int e1000e_up(struct e1000_adapter *adapter)
 
 	clear_bit(__E1000_DOWN, &adapter->state);
 
-	netif_poll_enable(adapter->netdev);
+	napi_enable(&adapter->napi);
 	e1000_irq_enable(adapter);
 
 	/* fire a link change interrupt to start the watchdog */
@@ -2472,7 +2467,7 @@ void e1000e_down(struct e1000_adapter *adapter)
 	e1e_flush();
 	msleep(10);
 
-	netif_poll_disable(netdev);
+	napi_disable(&adapter->napi);
 	e1000_irq_disable(adapter);
 
 	del_timer_sync(&adapter->watchdog_timer);
@@ -2605,7 +2600,7 @@ static int e1000_open(struct net_device *netdev)
 	/* From here on the code is the same as e1000e_up() */
 	clear_bit(__E1000_DOWN, &adapter->state);
 
-	netif_poll_enable(netdev);
+	napi_enable(&adapter->napi);
 
 	e1000_irq_enable(adapter);
 
@@ -4090,8 +4085,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 	e1000e_set_ethtool_ops(netdev);
 	netdev->tx_timeout		= &e1000_tx_timeout;
 	netdev->watchdog_timeo		= 5 * HZ;
-	netdev->poll			= &e1000_clean;
-	netdev->weight			= 64;
+	netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
 	netdev->vlan_rx_register	= e1000_vlan_rx_register;
 	netdev->vlan_rx_add_vid		= e1000_vlan_rx_add_vid;
 	netdev->vlan_rx_kill_vid	= e1000_vlan_rx_kill_vid;
@@ -4260,7 +4254,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 	/* tell the stack to leave us alone until e1000_open() is called */
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
-	netif_poll_disable(netdev);
 
 	strcpy(netdev->name, "eth%d");
 	err = register_netdev(netdev);

^ permalink raw reply related

* [PATCH][MIPS][7/7] AR7: ethernet
From: Matteo Croce @ 2007-09-08  0:23 UTC (permalink / raw)
  To: linux-mips
  Cc: Eugene Konev, netdev, davem, kuznet, pekkas, jmorris, yoshfuji,
	kaber, openwrt-devel, Andrew Morton, Jeff Garzik
In-Reply-To: <200709080143.12345.technoboy85@gmail.com>

Driver for the cpmac 100M ethernet driver.
It works fine disabling napi support, enabling it gives a kernel panic
when the first IPv6 packet has to be forwarded.
Other than that works fine.

Signed-off-by: Matteo Croce <technoboy85@gmail.com>
Signed-off-by: Eugene Konev <ejka@imfi.kspu.ru>

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d9b7d9c..6f38a84 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1822,6 +1822,15 @@ config SC92031
 	  To compile this driver as a module, choose M here: the module
 	  will be called sc92031.  This is recommended.
 
+config CPMAC
+	tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
+	depends on NET_ETHERNET && EXPERIMENTAL && AR7
+	select PHYLIB
+	select FIXED_PHY
+	select FIXED_MII_100_FDX
+	help
+	  TI AR7 CPMAC Ethernet support
+
 config NET_POCKET
 	bool "Pocket and portable adapters"
 	depends on PARPORT
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 535d2a0..bb22df9 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -156,6 +156,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o
 obj-$(CONFIG_8139TOO) += 8139too.o
 obj-$(CONFIG_ZNET) += znet.o
 obj-$(CONFIG_LAN_SAA9730) += saa9730.o
+obj-$(CONFIG_CPMAC) += cpmac.o
 obj-$(CONFIG_DEPCA) += depca.o
 obj-$(CONFIG_EWRK3) += ewrk3.o
 obj-$(CONFIG_ATP) += atp.o
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
new file mode 100644
index 0000000..c10ab08
--- /dev/null
+++ b/drivers/net/cpmac.c
@@ -0,0 +1,1194 @@
+/*
+ * Copyright (C) 2006, 2007 Eugene Konev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <asm/ar7/ar7.h>
+#include <gpio.h>
+
+MODULE_AUTHOR("Eugene Konev");
+MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)");
+MODULE_LICENSE("GPL");
+
+static int rx_ring_size = 64;
+static int disable_napi;
+module_param(rx_ring_size, int, 64);
+module_param(disable_napi, int, 0);
+MODULE_PARM_DESC(rx_ring_size, "Size of rx ring (in skbs)");
+MODULE_PARM_DESC(disable_napi, "Disable NAPI polling");
+
+/* Register definitions */
+struct cpmac_control_regs {
+	u32 revision;
+	u32 control;
+	u32 teardown;
+	u32 unused;
+} __attribute__ ((packed));
+
+struct cpmac_int_regs {
+	u32 stat_raw;
+	u32 stat_masked;
+	u32 enable;
+	u32 clear;
+} __attribute__ ((packed));
+
+struct cpmac_stats {
+	u32 good;
+	u32 bcast;
+	u32 mcast;
+	u32 pause;
+	u32 crc_error;
+	u32 align_error;
+	u32 oversized;
+	u32 jabber;
+	u32 undersized;
+	u32 fragment;
+	u32 filtered;
+	u32 qos_filtered;
+	u32 octets;
+} __attribute__ ((packed));
+
+struct cpmac_regs {
+	struct cpmac_control_regs tx_ctrl;
+	struct cpmac_control_regs rx_ctrl;
+	u32 unused1[56];
+	u32 mbp;
+/* MBP bits */
+#define MBP_RXPASSCRC         0x40000000
+#define MBP_RXQOS             0x20000000
+#define MBP_RXNOCHAIN         0x10000000
+#define MBP_RXCMF             0x01000000
+#define MBP_RXSHORT           0x00800000
+#define MBP_RXCEF             0x00400000
+#define MBP_RXPROMISC         0x00200000
+#define MBP_PROMISCCHAN(chan) (((chan) & 0x7) << 16)
+#define MBP_RXBCAST           0x00002000
+#define MBP_BCASTCHAN(chan)   (((chan) & 0x7) << 8)
+#define MBP_RXMCAST           0x00000020
+#define MBP_MCASTCHAN(chan)   ((chan) & 0x7)
+	u32 unicast_enable;
+	u32 unicast_clear;
+	u32 max_len;
+	u32 buffer_offset;
+	u32 filter_flow_threshold;
+	u32 unused2[2];
+	u32 flow_thre[8];
+	u32 free_buffer[8];
+	u32 mac_control;
+#define MAC_TXPTYPE  0x00000200
+#define MAC_TXPACE   0x00000040
+#define MAC_MII      0x00000020
+#define MAC_TXFLOW   0x00000010
+#define MAC_RXFLOW   0x00000008
+#define MAC_MTEST    0x00000004
+#define MAC_LOOPBACK 0x00000002
+#define MAC_FDX      0x00000001
+	u32 mac_status;
+#define MACST_QOS    0x4
+#define MACST_RXFLOW 0x2
+#define MACST_TXFLOW 0x1
+	u32 emc_control;
+	u32 unused3;
+	struct cpmac_int_regs tx_int;
+	u32 mac_int_vector;
+/* Int Status bits */
+#define INTST_STATUS 0x80000
+#define INTST_HOST   0x40000
+#define INTST_RX     0x20000
+#define INTST_TX     0x10000
+	u32 mac_eoi_vector;
+	u32 unused4[2];
+	struct cpmac_int_regs rx_int;
+	u32 mac_int_stat_raw;
+	u32 mac_int_stat_masked;
+	u32 mac_int_enable;
+	u32 mac_int_clear;
+	u32 mac_addr_low[8];
+	u32 mac_addr_mid;
+	u32 mac_addr_high;
+	u32 mac_hash_low;
+	u32 mac_hash_high;
+	u32 boff_test;
+	u32 pac_test;
+	u32 rx_pause;
+	u32 tx_pause;
+	u32 unused5[2];
+	struct cpmac_stats rx_stats;
+	struct cpmac_stats tx_stats;
+	u32 unused6[232];
+	u32 tx_ptr[8];
+	u32 rx_ptr[8];
+	u32 tx_ack[8];
+	u32 rx_ack[8];
+
+} __attribute__ ((packed));
+
+struct cpmac_mdio_regs {
+	u32 version;
+	u32 control;
+#define MDIOC_IDLE        0x80000000
+#define MDIOC_ENABLE      0x40000000
+#define MDIOC_PREAMBLE    0x00100000
+#define MDIOC_FAULT       0x00080000
+#define MDIOC_FAULTDETECT 0x00040000
+#define MDIOC_INTTEST     0x00020000
+#define MDIOC_CLKDIV(div) ((div) & 0xff)
+	u32 alive;
+	u32 link;
+	struct cpmac_int_regs link_int;
+	struct cpmac_int_regs user_int;
+	u32 unused[20];
+	volatile u32 access;
+#define MDIO_BUSY       0x80000000
+#define MDIO_WRITE      0x40000000
+#define MDIO_REG(reg)   (((reg) & 0x1f) << 21)
+#define MDIO_PHY(phy)   (((phy) & 0x1f) << 16)
+#define MDIO_DATA(data) ((data) & 0xffff)
+	u32 physel;
+} __attribute__ ((packed));
+
+/* Descriptor */
+struct cpmac_desc {
+	u32 hw_next;
+	u32 hw_data;
+	u16 buflen;
+	u16 bufflags;
+	u16 datalen;
+	u16 dataflags;
+/* Flags bits */
+#define CPMAC_SOP 0x8000
+#define CPMAC_EOP 0x4000
+#define CPMAC_OWN 0x2000
+#define CPMAC_EOQ 0x1000
+	struct sk_buff *skb;
+	struct cpmac_desc *next;
+} __attribute__ ((packed));
+
+struct cpmac_priv {
+	struct net_device_stats stats;
+	spinlock_t lock; /* irq{save,restore} */
+	struct sk_buff *skb_pool;
+	int free_skbs;
+	struct cpmac_desc *rx_head;
+	int tx_head, tx_tail;
+	struct cpmac_desc *desc_ring;
+	struct cpmac_regs *regs;
+	struct mii_bus *mii_bus;
+	struct phy_device *phy;
+	char phy_name[BUS_ID_SIZE];
+	struct plat_cpmac_data *config;
+	int oldlink, oldspeed, oldduplex;
+	u32 msg_enable;
+	struct net_device *dev;
+	struct work_struct alloc_work;
+};
+
+static irqreturn_t cpmac_irq(int, void *);
+static void cpmac_reset(struct net_device *dev);
+static void cpmac_hw_init(struct net_device *dev);
+static int cpmac_stop(struct net_device *dev);
+static int cpmac_open(struct net_device *dev);
+
+#undef CPMAC_DEBUG
+#define CPMAC_LOW_THRESH 32
+#define CPMAC_ALLOC_SIZE 64
+#define CPMAC_SKB_SIZE 1518
+#define CPMAC_TX_RING_SIZE 8
+
+#ifdef CPMAC_DEBUG
+static void cpmac_dump_regs(u32 *base, int count)
+{
+	int i;
+	for (i = 0; i < (count + 3) / 4; i++) {
+		if (i % 4 == 0) printk(KERN_DEBUG "\nCPMAC[0x%04x]:", i * 4);
+		printk(KERN_DEBUG " 0x%08x", *(base + i));
+	}
+	printk(KERN_DEBUG "\n");
+}
+
+static const char *cpmac_dump_buf(const uint8_t *buf, unsigned size)
+{
+	static char buffer[3 * 25 + 1];
+	char *p = &buffer[0];
+	if (size > 20)
+		size = 20;
+	while (size-- > 0)
+		p += sprintf(p, " %02x", *buf++);
+	return buffer;
+}
+#endif
+
+static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+	struct cpmac_mdio_regs *regs = bus->priv;
+	u32 val;
+
+	while ((val = regs->access) & MDIO_BUSY);
+	regs->access = MDIO_BUSY | MDIO_REG(regnum & 0x1f) |
+		MDIO_PHY(phy_id & 0x1f);
+	while ((val = regs->access) & MDIO_BUSY);
+
+	return val & 0xffff;
+}
+
+static int cpmac_mdio_write(struct mii_bus *bus, int phy_id,
+				int regnum, u16 val)
+{
+	struct cpmac_mdio_regs *regs = bus->priv;
+
+	while (regs->access & MDIO_BUSY);
+	regs->access = MDIO_BUSY | MDIO_WRITE |
+		MDIO_REG(regnum & 0x1f) | MDIO_PHY(phy_id & 0x1f) | val;
+
+	return 0;
+}
+
+static int cpmac_mdio_reset(struct mii_bus *bus)
+{
+	ar7_device_reset(AR7_RESET_BIT_MDIO);
+	((struct cpmac_mdio_regs *)bus->priv)->control = MDIOC_ENABLE |
+		MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1);
+
+	return 0;
+}
+
+static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };
+
+static struct mii_bus cpmac_mii = {
+	.name = "cpmac-mii",
+	.read = cpmac_mdio_read,
+	.write = cpmac_mdio_write,
+	.reset = cpmac_mdio_reset,
+	.irq = mii_irqs,
+};
+
+static int cpmac_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	/* Don't allow changing the I/O address */
+	if (map->base_addr != dev->base_addr)
+		return -EOPNOTSUPP;
+
+	/* ignore other fields */
+	return 0;
+}
+
+static int cpmac_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sa = addr;
+
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+	return 0;
+}
+
+static void cpmac_set_multicast_list(struct net_device *dev)
+{
+	struct dev_mc_list *iter;
+	int i;
+	int hash, tmp;
+	int hashlo = 0, hashhi = 0;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	if (dev->flags & IFF_PROMISC) {
+		priv->regs->mbp &= ~MBP_PROMISCCHAN(0); /* promisc channel 0 */
+		priv->regs->mbp |= MBP_RXPROMISC;
+	} else {
+		priv->regs->mbp &= ~MBP_RXPROMISC;
+		if (dev->flags & IFF_ALLMULTI) {
+			/* enable all multicast mode */
+			priv->regs->mac_hash_low = 0xffffffff;
+			priv->regs->mac_hash_high = 0xffffffff;
+		} else {
+			for (i = 0, iter = dev->mc_list; i < dev->mc_count;
+			    i++, iter = iter->next) {
+				hash = 0;
+				tmp = iter->dmi_addr[0];
+				hash  ^= (tmp >> 2) ^ (tmp << 4);
+				tmp = iter->dmi_addr[1];
+				hash  ^= (tmp >> 4) ^ (tmp << 2);
+				tmp = iter->dmi_addr[2];
+				hash  ^= (tmp >> 6) ^ tmp;
+				tmp = iter->dmi_addr[4];
+				hash  ^= (tmp >> 2) ^ (tmp << 4);
+				tmp = iter->dmi_addr[5];
+				hash  ^= (tmp >> 4) ^ (tmp << 2);
+				tmp = iter->dmi_addr[6];
+				hash  ^= (tmp >> 6) ^ tmp;
+				hash &= 0x3f;
+				if (hash < 32) {
+					hashlo |= 1<<hash;
+				} else {
+					hashhi |= 1<<(hash - 32);
+				}
+			}
+
+			priv->regs->mac_hash_low = hashlo;
+			priv->regs->mac_hash_high = hashhi;
+		}
+	}
+}
+
+static struct sk_buff *cpmac_get_skb(struct net_device *dev)
+{
+	struct sk_buff *skb;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	skb = priv->skb_pool;
+	if (likely(skb))
+		priv->skb_pool = skb->next;
+	else {
+		skb = dev_alloc_skb(CPMAC_SKB_SIZE + 2);
+		if (skb) {
+			skb->next = NULL;
+			skb_reserve(skb, 2);
+			skb->dev = priv->dev;
+		}
+	}
+
+	if (likely(priv->free_skbs))
+		priv->free_skbs--;
+
+	if (priv->free_skbs < CPMAC_LOW_THRESH)
+		schedule_work(&priv->alloc_work);
+
+	return skb;
+}
+
+static struct sk_buff *cpmac_rx_one(struct net_device *dev,
+					   struct cpmac_priv *priv,
+					   struct cpmac_desc *desc)
+{
+	unsigned long flags;
+	char *data;
+	struct sk_buff *skb, *result = NULL;
+
+	priv->regs->rx_ack[0] = virt_to_phys(desc);
+	if (unlikely(!desc->datalen)) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING "%s: rx: spurious interrupt\n",
+			       dev->name);
+		priv->stats.rx_errors++;
+		return NULL;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	skb = cpmac_get_skb(dev);
+	if (likely(skb)) {
+		data = (char *)phys_to_virt(desc->hw_data);
+		dma_cache_inv((u32)data, desc->datalen);
+		skb_put(desc->skb, desc->datalen);
+		desc->skb->protocol = eth_type_trans(desc->skb, dev);
+		desc->skb->ip_summed = CHECKSUM_NONE;
+		priv->stats.rx_packets++;
+		priv->stats.rx_bytes += desc->datalen;
+		result = desc->skb;
+		desc->skb = skb;
+	} else {
+#ifdef CPMAC_DEBUG
+		if (printk_ratelimit())
+			printk(KERN_NOTICE "%s: low on skbs, dropping packet\n",
+			       dev->name);
+#endif
+		priv->stats.rx_dropped++;
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	desc->hw_data = virt_to_phys(desc->skb->data);
+	desc->buflen = CPMAC_SKB_SIZE;
+	desc->dataflags = CPMAC_OWN;
+	dma_cache_wback((u32)desc, 16);
+
+	return result;
+}
+
+static void cpmac_rx(struct net_device *dev)
+{
+	struct sk_buff *skb;
+	struct cpmac_desc *desc;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	spin_lock(&priv->lock);
+	if (unlikely(!priv->rx_head)) {
+		spin_unlock(&priv->lock);
+		return;
+	}
+
+	desc = priv->rx_head;
+	dma_cache_inv((u32)desc, 16);
+#ifdef CPMAC_DEBUG
+	printk(KERN_DEBUG "%s: len=%d, %s\n", __func__, pkt->datalen,
+		cpmac_dump_buf(data, pkt->datalen));
+#endif
+
+	while ((desc->dataflags & CPMAC_OWN) == 0) {
+		skb = cpmac_rx_one(dev, priv, desc);
+		if (likely(skb))
+			netif_rx(skb);
+		desc = desc->next;
+		dma_cache_inv((u32)desc, 16);
+	}
+
+	priv->rx_head = desc;
+	priv->regs->rx_ptr[0] = virt_to_phys(desc);
+	spin_unlock(&priv->lock);
+}
+
+static int cpmac_poll(struct net_device *dev, int *budget)
+{
+	struct sk_buff *skb;
+	struct cpmac_desc *desc;
+	int received = 0, quota = min(dev->quota, *budget);
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	if (unlikely(!priv->rx_head)) {
+		if (printk_ratelimit())
+			printk(KERN_NOTICE "%s: rx: polling, but no queue\n",
+			       dev->name);
+		netif_rx_complete(dev);
+		return 0;
+	}
+
+	desc = priv->rx_head;
+	dma_cache_inv((u32)desc, 16);
+
+	while ((received < quota) && ((desc->dataflags & CPMAC_OWN) == 0)) {
+		skb = cpmac_rx_one(dev, priv, desc);
+		if (likely(skb)) {
+			netif_receive_skb(skb);
+			received++;
+		}
+		desc = desc->next;
+		priv->rx_head = desc;
+		dma_cache_inv((u32)desc, 16);
+	}
+
+	*budget -= received;
+	dev->quota -= received;
+#ifdef CPMAC_DEBUG
+	printk(KERN_DEBUG "%s: processed %d packets\n", dev->name, received);
+#endif
+	if (desc->dataflags & CPMAC_OWN) {
+		priv->regs->rx_ptr[0] = virt_to_phys(desc);
+		netif_rx_complete(dev);
+		priv->regs->rx_int.enable = 0x1;
+		priv->regs->rx_int.clear = 0xfe;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+cpmac_alloc_skbs(struct work_struct *work)
+{
+	struct cpmac_priv *priv = container_of(work, struct cpmac_priv,
+			alloc_work);
+	unsigned long flags;
+	int i, num_skbs = 0;
+	struct sk_buff *skb, *skbs = NULL;
+
+	for (i = 0; i < CPMAC_ALLOC_SIZE; i++) {
+		skb = alloc_skb(CPMAC_SKB_SIZE + 2, GFP_KERNEL);
+		if (!skb)
+			break;
+		skb->next = skbs;
+		skb_reserve(skb, 2);
+		skb->dev = priv->dev;
+		num_skbs++;
+		skbs = skb;
+	}
+
+	if (skbs) {
+		spin_lock_irqsave(&priv->lock, flags);
+		for (skb = priv->skb_pool; skb && skb->next; skb = skb->next);
+		if (!skb)
+			priv->skb_pool = skbs;
+		else
+			skb->next = skbs;
+		priv->free_skbs += num_skbs;
+		spin_unlock_irqrestore(&priv->lock, flags);
+#ifdef CPMAC_DEBUG
+		printk(KERN_DEBUG "%s: allocated %d skbs\n",
+			priv->dev->name, num_skbs);
+#endif
+	}
+}
+
+static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned long flags;
+	int len, chan;
+	struct cpmac_desc *desc;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	len = skb->len;
+#ifdef CPMAC_DEBUG
+	printk(KERN_DEBUG "%s: len=%d\n", __func__, len);
+	/* cpmac_dump_buf(const uint8_t * buf, unsigned size) */
+#endif
+	if (unlikely(len < ETH_ZLEN)) {
+		if (unlikely(skb_padto(skb, ETH_ZLEN))) {
+			if (printk_ratelimit())
+				printk(KERN_NOTICE
+					"%s: padding failed, dropping\n",
+								dev->name);
+			spin_lock_irqsave(&priv->lock, flags);
+			priv->stats.tx_dropped++;
+			spin_unlock_irqrestore(&priv->lock, flags);
+			return -ENOMEM;
+		}
+		len = ETH_ZLEN;
+	}
+	spin_lock_irqsave(&priv->lock, flags);
+	chan = priv->tx_tail++;
+	priv->tx_tail %= 8;
+	if (priv->tx_tail == priv->tx_head)
+		netif_stop_queue(dev);
+
+	desc = &priv->desc_ring[chan];
+	dma_cache_inv((u32)desc, 16);
+	if (desc->dataflags & CPMAC_OWN) {
+		printk(KERN_NOTICE "%s: tx dma ring full, dropping\n",
+								dev->name);
+		priv->stats.tx_dropped++;
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return -ENOMEM;
+	}
+
+	dev->trans_start = jiffies;
+	desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN;
+	desc->skb = skb;
+	desc->hw_data = virt_to_phys(skb->data);
+	dma_cache_wback((u32)skb->data, len);
+	desc->buflen = len;
+	desc->datalen = len;
+	desc->hw_next = 0;
+	dma_cache_wback((u32)desc, 16);
+	priv->regs->tx_ptr[chan] = virt_to_phys(desc);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static void cpmac_end_xmit(struct net_device *dev, int channel)
+{
+	struct cpmac_desc *desc;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	spin_lock(&priv->lock);
+	desc = &priv->desc_ring[channel];
+	priv->regs->tx_ack[channel] = virt_to_phys(desc);
+	if (likely(desc->skb)) {
+		priv->stats.tx_packets++;
+		priv->stats.tx_bytes += desc->skb->len;
+		dev_kfree_skb_irq(desc->skb);
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+	} else
+		if (printk_ratelimit())
+			printk(KERN_NOTICE "%s: end_xmit: spurious interrupt\n",
+			       dev->name);
+	spin_unlock(&priv->lock);
+}
+
+static void cpmac_reset(struct net_device *dev)
+{
+	int i;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	ar7_device_reset(priv->config->reset_bit);
+	priv->regs->rx_ctrl.control &= ~1;
+	priv->regs->tx_ctrl.control &= ~1;
+	for (i = 0; i < 8; i++) {
+		priv->regs->tx_ptr[i] = 0;
+		priv->regs->rx_ptr[i] = 0;
+	}
+	priv->regs->mac_control &= ~MAC_MII; /* disable mii */
+}
+
+static inline void cpmac_free_rx_ring(struct net_device *dev)
+{
+	struct cpmac_desc *desc;
+	int i;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	if (unlikely(!priv->rx_head))
+		return;
+
+	desc = priv->rx_head;
+	dma_cache_inv((u32)desc, 16);
+
+	for (i = 0; i < rx_ring_size; i++) {
+		desc->buflen = CPMAC_SKB_SIZE;
+		if ((desc->dataflags & CPMAC_OWN) == 0) {
+			desc->dataflags = CPMAC_OWN;
+			priv->stats.rx_dropped++;
+		}
+		dma_cache_wback((u32)desc, 16);
+		desc = desc->next;
+		dma_cache_inv((u32)desc, 16);
+	}
+}
+
+static irqreturn_t cpmac_irq(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct cpmac_priv *priv = netdev_priv(dev);
+	u32 status;
+
+	if (!dev)
+		return IRQ_NONE;
+
+	status = priv->regs->mac_int_vector;
+
+	if (status & INTST_TX)
+		cpmac_end_xmit(dev, (status & 7));
+
+	if (status & INTST_RX) {
+		if (disable_napi)
+			cpmac_rx(dev);
+		else {
+			priv->regs->rx_int.enable = 0;
+			priv->regs->rx_int.clear = 0xff;
+			netif_rx_schedule(dev);
+		}
+	}
+
+	priv->regs->mac_eoi_vector = 0;
+
+	if (unlikely(status & (INTST_HOST | INTST_STATUS))) {
+		if (printk_ratelimit())
+			printk(KERN_ERR "%s: hw error, resetting...\n",
+								dev->name);
+		spin_lock(&priv->lock);
+		phy_stop(priv->phy);
+		cpmac_reset(dev);
+		cpmac_free_rx_ring(dev);
+		cpmac_hw_init(dev);
+		spin_unlock(&priv->lock);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void cpmac_tx_timeout(struct net_device *dev)
+{
+	struct cpmac_priv *priv = netdev_priv(dev);
+	struct cpmac_desc *desc;
+
+	priv->stats.tx_errors++;
+	desc = &priv->desc_ring[priv->tx_head++];
+	priv->tx_head %= 8;
+	printk(KERN_NOTICE "%s: transmit timeout\n", dev->name);
+	if (desc->skb)
+		dev_kfree_skb(desc->skb);
+	netif_wake_queue(dev);
+}
+
+static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct cpmac_priv *priv = netdev_priv(dev);
+	if (!(netif_running(dev)))
+		return -EINVAL;
+	if (!priv->phy)
+		return -EINVAL;
+	if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) ||
+	    (cmd == SIOCSMIIREG))
+		return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd);
+
+	return -EINVAL;
+}
+
+static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	if (priv->phy)
+		return phy_ethtool_gset(priv->phy, cmd);
+
+	return -EINVAL;
+}
+
+static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (priv->phy)
+		return phy_ethtool_sset(priv->phy, cmd);
+
+	return -EINVAL;
+}
+
+static void cpmac_get_drvinfo(struct net_device *dev,
+			      struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, "cpmac");
+	strcpy(info->version, "0.0.3");
+	info->fw_version[0] = '\0';
+	sprintf(info->bus_info, "%s", "cpmac");
+	info->regdump_len = 0;
+}
+
+static const struct ethtool_ops cpmac_ethtool_ops = {
+	.get_settings = cpmac_get_settings,
+	.set_settings = cpmac_set_settings,
+	.get_drvinfo = cpmac_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
+
+static struct net_device_stats *cpmac_stats(struct net_device *dev)
+{
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	if (netif_device_present(dev))
+		return &priv->stats;
+
+	return NULL;
+}
+
+static int cpmac_change_mtu(struct net_device *dev, int mtu)
+{
+	unsigned long flags;
+	struct cpmac_priv *priv = netdev_priv(dev);
+	spinlock_t *lock = &priv->lock;
+
+	if ((mtu < 68) || (mtu > 1500))
+		return -EINVAL;
+
+	spin_lock_irqsave(lock, flags);
+	dev->mtu = mtu;
+	spin_unlock_irqrestore(lock, flags);
+
+	return 0;
+}
+
+static void cpmac_adjust_link(struct net_device *dev)
+{
+	struct cpmac_priv *priv = netdev_priv(dev);
+	unsigned long flags;
+	int new_state = 0;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->phy->link) {
+		if (priv->phy->duplex != priv->oldduplex) {
+			new_state = 1;
+			priv->oldduplex = priv->phy->duplex;
+		}
+
+		if (priv->phy->speed != priv->oldspeed) {
+			new_state = 1;
+			priv->oldspeed = priv->phy->speed;
+		}
+
+		if (!priv->oldlink) {
+			new_state = 1;
+			priv->oldlink = 1;
+			netif_schedule(dev);
+		}
+	} else if (priv->oldlink) {
+		new_state = 1;
+		priv->oldlink = 0;
+		priv->oldspeed = 0;
+		priv->oldduplex = -1;
+	}
+
+	if (new_state)
+		phy_print_status(priv->phy);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void cpmac_hw_init(struct net_device *dev)
+{
+	int i;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	for (i = 0; i < 8; i++)
+		priv->regs->tx_ptr[i] = 0;
+	priv->regs->rx_ptr[0] = virt_to_phys(priv->rx_head);
+
+	priv->regs->mbp = MBP_RXSHORT | MBP_RXBCAST | MBP_RXMCAST;
+	priv->regs->unicast_enable = 0x1;
+	priv->regs->unicast_clear = 0xfe;
+	priv->regs->buffer_offset = 0;
+	for (i = 0; i < 8; i++)
+		priv->regs->mac_addr_low[i] = dev->dev_addr[5];
+	priv->regs->mac_addr_mid = dev->dev_addr[4];
+	priv->regs->mac_addr_high = dev->dev_addr[0] | (dev->dev_addr[1] << 8)
+		| (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
+	priv->regs->max_len = CPMAC_SKB_SIZE;
+	priv->regs->rx_int.enable = 0x1;
+	priv->regs->rx_int.clear = 0xfe;
+	priv->regs->tx_int.enable = 0xff;
+	priv->regs->tx_int.clear = 0;
+	priv->regs->mac_int_enable = 3;
+	priv->regs->mac_int_clear = 0xfc;
+
+	priv->regs->rx_ctrl.control |= 1;
+	priv->regs->tx_ctrl.control |= 1;
+	priv->regs->mac_control |= MAC_MII | MAC_FDX;
+
+	priv->phy->state = PHY_CHANGELINK;
+	phy_start(priv->phy);
+}
+
+static int cpmac_open(struct net_device *dev)
+{
+	int i, size, res;
+	struct cpmac_priv *priv = netdev_priv(dev);
+	struct cpmac_desc *desc;
+	struct sk_buff *skb;
+
+	priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link,
+				0, PHY_INTERFACE_MODE_MII);
+	if (IS_ERR(priv->phy)) {
+		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(priv->phy);
+	}
+
+	if (!request_mem_region(dev->mem_start, dev->mem_end -
+				dev->mem_start, dev->name)) {
+		printk(KERN_ERR "%s: failed to request registers\n",
+		       dev->name);
+		res = -ENXIO;
+		goto fail_reserve;
+	}
+
+	priv->regs = ioremap_nocache(dev->mem_start, dev->mem_end -
+				     dev->mem_start);
+	if (!priv->regs) {
+		printk(KERN_ERR "%s: failed to remap registers\n", dev->name);
+		res = -ENXIO;
+		goto fail_remap;
+	}
+
+	priv->rx_head = NULL;
+	size = sizeof(struct cpmac_desc) * (rx_ring_size +
+					    CPMAC_TX_RING_SIZE);
+	priv->desc_ring = (struct cpmac_desc *)kmalloc(size, GFP_KERNEL);
+	if (!priv->desc_ring) {
+		res = -ENOMEM;
+		goto fail_alloc;
+	}
+
+	memset((char *)priv->desc_ring, 0, size);
+
+	priv->skb_pool = NULL;
+	priv->free_skbs = 0;
+	priv->rx_head = &priv->desc_ring[CPMAC_TX_RING_SIZE];
+
+	INIT_WORK(&priv->alloc_work, cpmac_alloc_skbs);
+	schedule_work(&priv->alloc_work);
+	flush_scheduled_work();
+
+	for (i = 0; i < rx_ring_size; i++) {
+		desc = &priv->rx_head[i];
+		skb = cpmac_get_skb(dev);
+		if (!skb) {
+			res = -ENOMEM;
+			goto fail_desc;
+		}
+		desc->skb = skb;
+		desc->hw_data = virt_to_phys(skb->data);
+		desc->buflen = CPMAC_SKB_SIZE;
+		desc->dataflags = CPMAC_OWN;
+		desc->next = &priv->rx_head[(i + 1) % rx_ring_size];
+		desc->hw_next = virt_to_phys(desc->next);
+		dma_cache_wback((u32)desc, 16);
+	}
+
+	if ((res = request_irq(dev->irq, cpmac_irq, SA_INTERRUPT,
+			      dev->name, dev))) {
+		printk(KERN_ERR "%s: failed to obtain irq\n", dev->name);
+		goto fail_irq;
+	}
+
+	cpmac_reset(dev);
+	cpmac_hw_init(dev);
+
+	netif_start_queue(dev);
+	return 0;
+
+fail_irq:
+fail_desc:
+	for (i = 0; i < rx_ring_size; i++)
+		if (priv->rx_head[i].skb)
+			kfree_skb(priv->rx_head[i].skb);
+fail_alloc:
+	kfree(priv->desc_ring);
+
+	for (skb = priv->skb_pool; skb; skb = priv->skb_pool) {
+		priv->skb_pool = skb->next;
+		kfree_skb(skb);
+	}
+
+	iounmap(priv->regs);
+
+fail_remap:
+	release_mem_region(dev->mem_start, dev->mem_end -
+			   dev->mem_start);
+
+fail_reserve:
+	phy_disconnect(priv->phy);
+
+	return res;
+}
+
+static int cpmac_stop(struct net_device *dev)
+{
+	int i;
+	struct sk_buff *skb;
+	struct cpmac_priv *priv = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+
+	phy_stop(priv->phy);
+	phy_disconnect(priv->phy);
+	priv->phy = NULL;
+
+	cpmac_reset(dev);
+
+	for (i = 0; i < 8; i++) {
+		priv->regs->rx_ptr[i] = 0;
+		priv->regs->tx_ptr[i] = 0;
+		priv->regs->mbp = 0;
+	}
+
+	free_irq(dev->irq, dev);
+	release_mem_region(dev->mem_start, dev->mem_end -
+			   dev->mem_start);
+
+	cancel_delayed_work(&priv->alloc_work);
+	flush_scheduled_work();
+
+	priv->rx_head = &priv->desc_ring[CPMAC_TX_RING_SIZE];
+	for (i = 0; i < rx_ring_size; i++)
+		if (priv->rx_head[i].skb)
+			kfree_skb(priv->rx_head[i].skb);
+
+	kfree(priv->desc_ring);
+
+	for (skb = priv->skb_pool; skb; skb = priv->skb_pool) {
+		priv->skb_pool = skb->next;
+		kfree_skb(skb);
+	}
+
+	return 0;
+}
+
+static int external_switch;
+
+static int __devinit cpmac_probe(struct platform_device *pdev)
+{
+	int i, rc, phy_id;
+	struct resource *res;
+	struct cpmac_priv *priv;
+	struct net_device *dev;
+	struct plat_cpmac_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+
+	for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
+		if (!(pdata->phy_mask & (1 << phy_id)))
+			continue;
+		if (!cpmac_mii.phy_map[phy_id])
+			continue;
+		break;
+	}
+
+	if (phy_id == PHY_MAX_ADDR) {
+		if (external_switch)
+			phy_id = 0;
+		else {
+			printk(KERN_ERR "cpmac: no PHY present\n");
+			return -ENODEV;
+		}
+	}
+
+	dev = alloc_etherdev(sizeof(struct cpmac_priv));
+
+	if (!dev) {
+		printk(KERN_ERR
+			"cpmac: Unable to allocate net_device structure!\n");
+		return -ENOMEM;
+	}
+
+	SET_MODULE_OWNER(dev);
+	platform_set_drvdata(pdev, dev);
+	priv = netdev_priv(dev);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	if (!res) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	dev->mem_start = res->start;
+	dev->mem_end = res->end;
+	dev->irq = platform_get_irq_byname(pdev, "irq");
+
+	dev->mtu                = 1500;
+	dev->open               = cpmac_open;
+	dev->stop               = cpmac_stop;
+	dev->set_config         = cpmac_config;
+	dev->hard_start_xmit    = cpmac_start_xmit;
+	dev->do_ioctl           = cpmac_ioctl;
+	dev->get_stats          = cpmac_stats;
+	dev->change_mtu         = cpmac_change_mtu;
+	dev->set_mac_address    = cpmac_set_mac_address;
+	dev->set_multicast_list = cpmac_set_multicast_list;
+	dev->tx_timeout         = cpmac_tx_timeout;
+	dev->ethtool_ops        = &cpmac_ethtool_ops;
+	if (!disable_napi) {
+		dev->poll = cpmac_poll;
+		dev->weight = min(rx_ring_size, 64);
+	}
+
+	memset(priv, 0, sizeof(struct cpmac_priv));
+	spin_lock_init(&priv->lock);
+	priv->msg_enable = netif_msg_init(NETIF_MSG_WOL, 0x3fff);
+	priv->config = pdata;
+	priv->dev = dev;
+	memcpy(dev->dev_addr, priv->config->dev_addr, sizeof(dev->dev_addr));
+	if (phy_id == 31)
+		snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT,
+			 cpmac_mii.id, phy_id);
+	else
+		snprintf(priv->phy_name, BUS_ID_SIZE, "fixed@%d:%d", 100, 1);
+
+	if ((rc = register_netdev(dev))) {
+		printk(KERN_ERR "cpmac: error %i registering device %s\n",
+		       rc, dev->name);
+		goto fail;
+	}
+
+	printk(KERN_INFO "cpmac: device %s (regs: %p, irq: %d, phy: %s, mac: ",
+	       dev->name, (u32 *)dev->mem_start, dev->irq,
+	       priv->phy_name);
+	for (i = 0; i < 6; i++)
+		printk("%02x%s", dev->dev_addr[i], i < 5 ? ":" : ")\n");
+
+	return 0;
+
+fail:
+	free_netdev(dev);
+	return rc;
+}
+
+static int __devexit cpmac_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	unregister_netdev(dev);
+	free_netdev(dev);
+	return 0;
+}
+
+static struct platform_driver cpmac_driver = {
+	.driver.name = "cpmac",
+	.probe = cpmac_probe,
+	.remove = cpmac_remove,
+};
+
+int __devinit cpmac_init(void)
+{
+	u32 mask;
+	int i, res;
+	cpmac_mii.priv =
+		ioremap_nocache(AR7_REGS_MDIO, sizeof(struct cpmac_mdio_regs));
+
+	if (!cpmac_mii.priv) {
+		printk(KERN_ERR "Can't ioremap mdio registers\n");
+		return -ENXIO;
+	}
+
+#warning FIXME: unhardcode gpio&reset bits
+	ar7_gpio_disable(26);
+	ar7_gpio_disable(27);
+	ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);
+	ar7_device_reset(AR7_RESET_BIT_CPMAC_HI);
+	ar7_device_reset(AR7_RESET_BIT_EPHY);
+
+	cpmac_mii.reset(&cpmac_mii);
+
+	for (i = 0; i < 300000; i++) {
+		mask = ((struct cpmac_mdio_regs *)cpmac_mii.priv)->alive;
+		if (mask)
+			break;
+	}
+
+/*	mask &= 0x7fffffff;
+	if (mask & (mask - 1)) {*/
+		external_switch = 1;
+		mask = 0;
+/*	}*/
+
+	cpmac_mii.phy_mask = ~(mask | 0x80000000);
+
+	res = mdiobus_register(&cpmac_mii);
+	if (res)
+		goto fail_mii;
+
+	res = platform_driver_register(&cpmac_driver);
+	if (res)
+		goto fail_cpmac;
+
+	return 0;
+
+fail_cpmac:
+	mdiobus_unregister(&cpmac_mii);
+
+fail_mii:
+	iounmap(cpmac_mii.priv);
+
+	return res;
+}
+
+void __devexit cpmac_exit(void)
+{
+	platform_driver_unregister(&cpmac_driver);
+	mdiobus_unregister(&cpmac_mii);
+}
+
+module_init(cpmac_init);
+module_exit(cpmac_exit);

^ permalink raw reply related

* Re: [atl1-devel] [PATCH 2/2] atl1: wrap problematic optimizations in CONFIG_ATL1_EXPERIMENTAL
From: Luca @ 2007-09-08  0:21 UTC (permalink / raw)
  To: Chris Snook; +Cc: Jeff Garzik, atl1-devel, netdev
In-Reply-To: <20070907235209.GB12055@shell.boston.redhat.com>

On 9/8/07, Chris Snook <csnook@redhat.com> wrote:
> From: Chris Snook <csnook@redhat.com>
>
> Make certain problematic optimizations build-time configurable.
>
> Signed-off-by: Chris Snook <csnook@redhat.com>
> Acked-by: Jay Cliburn <jacliburn@bellsouth.net>
>
> --- a/drivers/net/atl1/atl1_main.c      2007-09-04 10:12:38.000000000 -0400
> +++ b/drivers/net/atl1/atl1_main.c      2007-09-04 11:23:26.000000000 -0400
> @@ -2203,22 +2203,26 @@ static int __devinit atl1_probe(struct p
>         struct net_device *netdev;
>         struct atl1_adapter *adapter;
>         static int cards_found = 0;
> -       bool pci_using_64 = true;
> +       bool pci_using_64 = false;
>         int err;
>
>         err = pci_enable_device(pdev);
>         if (err)
>                 return err;
>
> +#ifdef CONFIG_ATL1_EXPERIMENTAL
>         err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
> +       if (!err) {
> +               pci_using_64 = true;
> +               goto dma_ok;
> +       }
> +#endif /* CONFIG_ATL1_EXPERIMENTAL */

This is more like CONFIG_ATL1_PLEASE_KILL_MY_MACHINE; I really don't
see the problem with just limiting the DMA mask:
- if you don't have physical mem over the 4GB boundary limiting DMA
doesn't make any difference
- if you have more than 4GB of memory the machine won't survive long without it

Luca

^ permalink raw reply

* Re: [PATCH 0/2] atl1: Introduce CONFIG_ATL1_EXPERIMENTAL
From: Chris Snook @ 2007-09-08  0:06 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: atl1-devel, Jay Cliburn, netdev
In-Reply-To: <46E1E4BD.4000004@garzik.org>

Jeff Garzik wrote:
> Chris Snook wrote:
>> The atl1 driver is currently marked EXPERIMENTAL, because a few 
>> supposedly performance-enhancing features still have problems.  When 
>> these features are disabled, the driver is completely stable, fully 
>> functional, and performs well.
>>
>> Patch 1/2 Creates the kconfig option CONFIG_ATL1_EXPERIMENTAL, and 
>> removes the EXPERIMENTAL designation from CONFIG_ATL1
>>
>> Patch 2/2 Wraps some currently-disabled features in #ifdef 
>> CONFIG_ATL1_EXPERIMENTAL, so developers and testers can play with 
>> these features more easily, and distributions will still get a fast, 
>> stable driver with existing .config files.
>>
>> We'll also be using this to wrap around various new features we'll be 
>> experimenting with in coming months.  Instead of using a half dozen 
>> different kconfig options for each of them, like some drivers do, 
>> we'll just use this, and make sure things are safe for everyone before 
>> we take them out of the experimental wrapper.
> 
> Well, I haven't received patch #2 yet, but in general a runtime switch 
> (module option?) is greatly preferred.
> 
>     Jeff

Okay, I'll think about how we want to parameterize this.  I don't want users 
expecting development options to be around forever.  I'll resubmit something 
once I have more of these experimental features ready to submit.

	-- Chris

^ permalink raw reply

* Re: [PATCH 0/2] atl1: Introduce CONFIG_ATL1_EXPERIMENTAL
From: Jeff Garzik @ 2007-09-07 23:54 UTC (permalink / raw)
  To: Chris Snook; +Cc: atl1-devel, Jay Cliburn, netdev
In-Reply-To: <46E1E1AC.5030801@redhat.com>

Chris Snook wrote:
> The atl1 driver is currently marked EXPERIMENTAL, because a few 
> supposedly performance-enhancing features still have problems.  When 
> these features are disabled, the driver is completely stable, fully 
> functional, and performs well.
> 
> Patch 1/2 Creates the kconfig option CONFIG_ATL1_EXPERIMENTAL, and 
> removes the EXPERIMENTAL designation from CONFIG_ATL1
> 
> Patch 2/2 Wraps some currently-disabled features in #ifdef 
> CONFIG_ATL1_EXPERIMENTAL, so developers and testers can play with these 
> features more easily, and distributions will still get a fast, stable 
> driver with existing .config files.
> 
> We'll also be using this to wrap around various new features we'll be 
> experimenting with in coming months.  Instead of using a half dozen 
> different kconfig options for each of them, like some drivers do, we'll 
> just use this, and make sure things are safe for everyone before we take 
> them out of the experimental wrapper.

Well, I haven't received patch #2 yet, but in general a runtime switch 
(module option?) is greatly preferred.

	Jeff




^ permalink raw reply

* Re: 2.6.23-rc4-mm1: e1000e napi lockup
From: Kok, Auke @ 2007-09-07 23:52 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: David Miller, jirislaby, akpm, netdev, e1000-devel
In-Reply-To: <46E1E391.7090907@garzik.org>

Jeff Garzik wrote:
> Kok, Auke wrote:
>> Jeff Garzik wrote:
>>> Kok, Auke wrote:
>>>> David Miller wrote:
>>>>> From: Jiri Slaby <jirislaby@gmail.com>
>>>>> Date: Fri, 07 Sep 2007 09:19:30 +0200
>>>>>
>>>>>> I found a regression in 2.6.23-rc4-mm1 (since -rc3-mm1) in e1000e 
>>>>>> driver.
>>>>>> napi_disable(&adapter->napi) in e1000_probe freezes the kernel on 
>>>>>> boot.
>>>>> Yes, the semantics changed slightly in the net-2.6.24 tree the
>>>>> other week and someone needs to fix it up.
>>>>>
>>>>> The netif_napi_add() implicitly does a napi_disable() call.  Device
>>>>> open must explicitly napi_enable() and device close must explicitly
>>>>> napi_disable(), and if done elsewhere these calls must be strictly
>>>>> balanced.
>>>> I'll fix it... it's my patch that adds the new napi code to it and I 
>>>> need to get it ready for the merge window anyway.
>>> well....  since its close to the merge window opening, we could see 
>>> what happens if DaveM pulls branch 'upstream' of 
>>> git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
>>>
>>> That should make this class of pre-merge-window annoyance go away.
>> If I do that now I get a big merge conflict:
> 
> oh you are _guaranteed_ conflicts.  most of that is NAPI-area code that 
> got changed by both.


actually that's the only thing it was, and fixing it up was trivial (took me 
about 3 minutes). it was 3x the napi code and once a struct indent change...

I'll have a new e1000e napi patch for andrew in a sec.

Auke

^ permalink raw reply

* [PATCH 2/2] atl1: wrap problematic optimizations in CONFIG_ATL1_EXPERIMENTAL
From: Chris Snook @ 2007-09-07 23:52 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: atl1-devel, Jay Cliburn, netdev
In-Reply-To: <46E1E1AC.5030801@redhat.com>

From: Chris Snook <csnook@redhat.com>

Make certain problematic optimizations build-time configurable.

Signed-off-by: Chris Snook <csnook@redhat.com>
Acked-by: Jay Cliburn <jacliburn@bellsouth.net>

--- a/drivers/net/atl1/atl1_main.c	2007-09-04 10:12:38.000000000 -0400
+++ b/drivers/net/atl1/atl1_main.c	2007-09-04 11:23:26.000000000 -0400
@@ -2203,22 +2203,26 @@ static int __devinit atl1_probe(struct p
 	struct net_device *netdev;
 	struct atl1_adapter *adapter;
 	static int cards_found = 0;
-	bool pci_using_64 = true;
+	bool pci_using_64 = false;
 	int err;
 
 	err = pci_enable_device(pdev);
 	if (err)
 		return err;
 
+#ifdef CONFIG_ATL1_EXPERIMENTAL
 	err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+	if (!err) {
+		pci_using_64 = true;
+		goto dma_ok;
+	}
+#endif /* CONFIG_ATL1_EXPERIMENTAL */
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 	if (err) {
-		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-		if (err) {
-			dev_err(&pdev->dev, "no usable DMA configuration\n");
-			goto err_dma;
-		}
-		pci_using_64 = false;
+		dev_err(&pdev->dev, "no usable DMA configuration\n");
+		goto err_dma;
 	}
+dma_ok:
 	/* Mark all PCI regions associated with PCI device
 	 * pdev as being reserved by owner atl1_driver_name
 	 */
@@ -2294,11 +2298,13 @@ static int __devinit atl1_probe(struct p
 	netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
 
 	/*
-	 * FIXME - Until tso performance gets fixed, disable the feature.
+	 * TSO currently has performance problems,
+	 * so let's disable it by default.
 	 * Enable it with ethtool -K if desired.
 	 */
-	/* netdev->features |= NETIF_F_TSO; */
-
+#ifdef CONFIG_ATL1_EXPERIMENTAL
+	netdev->features |= NETIF_F_TSO;
+#endif
 	if (pci_using_64)
 		netdev->features |= NETIF_F_HIGHDMA;
 

^ permalink raw reply

* Re: 2.6.23-rc4-mm1: e1000e napi lockup
From: Jeff Garzik @ 2007-09-07 23:49 UTC (permalink / raw)
  To: Kok, Auke; +Cc: e1000-devel, netdev, akpm, David Miller, jirislaby
In-Reply-To: <46E1E15E.7080406@intel.com>

Kok, Auke wrote:
> Jeff Garzik wrote:
>> Kok, Auke wrote:
>>> David Miller wrote:
>>>> From: Jiri Slaby <jirislaby@gmail.com>
>>>> Date: Fri, 07 Sep 2007 09:19:30 +0200
>>>>
>>>>> I found a regression in 2.6.23-rc4-mm1 (since -rc3-mm1) in e1000e 
>>>>> driver.
>>>>> napi_disable(&adapter->napi) in e1000_probe freezes the kernel on 
>>>>> boot.
>>>> Yes, the semantics changed slightly in the net-2.6.24 tree the
>>>> other week and someone needs to fix it up.
>>>>
>>>> The netif_napi_add() implicitly does a napi_disable() call.  Device
>>>> open must explicitly napi_enable() and device close must explicitly
>>>> napi_disable(), and if done elsewhere these calls must be strictly
>>>> balanced.
>>> I'll fix it... it's my patch that adds the new napi code to it and I 
>>> need to get it ready for the merge window anyway.
>>
>> well....  since its close to the merge window opening, we could see 
>> what happens if DaveM pulls branch 'upstream' of 
>> git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
>>
>> That should make this class of pre-merge-window annoyance go away.
> 
> If I do that now I get a big merge conflict:

oh you are _guaranteed_ conflicts.  most of that is NAPI-area code that 
got changed by both.



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply

* Re: BUG: unable to handle kernel NULL pointer dereference<1>
From: Michal Piotrowski @ 2007-09-07 23:48 UTC (permalink / raw)
  To: Mark Nipper; +Cc: linux-kernel, Netdev
In-Reply-To: <20070907052720.GA3122@king.bitgnome.net>

Hi Mark,

[Adding netdev to CC]

On 07/09/2007, Mark Nipper <nipsy@bitgnome.net> wrote:
>         I've received two oopses now from my kernel while running
> the 2.6.22 series.  The first was with 2.6.22.1 back in July and
> the second which happened just within the last day is 2.6.22.5.
> They both appear to be the same bug and I don't think it's
> hardware related.  I'm attaching the entries from logcheck which
> I received when they happened.
>
>         I'm not subscribed to the mailing list, so please make
> sure to copy me directly on any replies.  And let me know if
> anyone needs any additional information to try to track this
> down.  Thanks for reading...

Regards,
Michal

-- 
LOG
http://www.stardust.webpages.pl/log/

^ permalink raw reply

* [PATCH 1/2] atl1: add CONFIG_ATL1_EXPERIMENTAL to kconfig
From: Chris Snook @ 2007-09-07 23:47 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: atl1-devel, Jay Cliburn, netdev
In-Reply-To: <46E1E1AC.5030801@redhat.com>

From: Chris Snook <csnook@redhat.com>

Introduce Kconfig ATL1_EXPERIMENTAL to separate mature code from less mature
code in the atl1 driver, and remove EXPERIMENTAL designation for ATL1.

Signed-off-by: Chris Snook <csnook@redhat.com>
Acked-by: Jay Cliburn <jacliburn@bellsouth.net>

--- a/drivers/net/Kconfig	2007-09-04 10:12:38.000000000 -0400
+++ b/drivers/net/Kconfig	2007-09-04 10:37:34.000000000 -0400
@@ -2329,8 +2329,8 @@ config QLA3XXX
 	  will be called qla3xxx.
 
 config ATL1
-	tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
-	depends on PCI && EXPERIMENTAL
+	tristate "Attansic L1 Gigabit Ethernet support"
+	depends on PCI
 	select CRC32
 	select MII
 	help
@@ -2339,6 +2339,16 @@ config ATL1
 	  To compile this driver as a module, choose M here.  The module
 	  will be called atl1.
 
+config ATL1_EXPERIMENTAL
+	bool "atl1 experimental features"
+	depends on ATL1 && EXPERIMENTAL
+	help
+	  This option enables various features that have not yet reached
+	  the maturity of the rest of the atl1 driver.  The driver will
+	  still work fine without this option enabled.
+
+	  If unsure, say N.
+
 endif # NETDEV_1000
 
 #

^ permalink raw reply

* Re: error(s) in 2.6.23-rc5 bonding.txt ?
From: Rick Jones @ 2007-09-07 23:46 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: Linux Network Development list
In-Reply-To: <32121.1189207861@death>

> 	That said, it's certainly plausible that, for a given set of N
> ethernets all enslaved to a single bonding balance-rr, the individual
> ethernets could get out of sync, as it were (e.g., one running a fuller
> tx ring, and thus running "behind" the others). 

That is the scenario of which I was thinking.

> If bonding is the only feeder of the devices, then for a continuous
> flow of traffic, all the slaves will generally receive packets (from
> the kernel, for transmission) at pretty much the same rate, and so
> they won't tend to get ahead or behind.

I could see that if there was just one TCP connection going doing bulk 
or something, but if there were a bulk transmitter coupled with an 
occasional request/response (ie netperf TCP_STREAM and a TCP_RR) i'd 
think the tx rings would no longer remain balanced.

> 	I haven't investigated into this deeply for a few years, but
> this is my recollection of what happened with the tests I did then.  I
> did testing with multiple 100Mb devices feeding either other sets of
> 100Mb devices or single gigabit devices.  I'm willing to believe that
> things have changed, and an N feeding into one configuration can
> reorder, but I haven't seen it (or really looked for it; balance-rr
> isn't much the rage these days).

Are you OK with that block of text simply being yanked?

rick

^ permalink raw reply

* Re: request for information about the "ath5k" licensing
From: Jeff Garzik @ 2007-09-07 23:42 UTC (permalink / raw)
  To: Reyk Floeter
  Cc: Luis R. Rodriguez, linux-kernel, linux-wireless, netdev,
	jirislaby, moglen
In-Reply-To: <20070907064730.GA15001@slim.vantronix.net>

Reyk Floeter wrote:
> I'm still waiting for an answer. Your process is taking too long.


Speaking as a person through which these changes flow upstream into the 
official kernel (ath5k maintainers -> linville -> me -> linus)...


The most important thing for today is that no ath5k stuff has been 
committed (nor has it ever been).


I would rather take it slow and make sure everybody is happy.  There is 
nothing upstream, and so, there is no need to rush and correct something.

Collectively, this is just growing pains.  Everyone is breaking new 
ground, trying to figure out how to best support atheros stuff on Linux. 
  There are new tools to deal with (svn? git? flavor of the day?:)), new 
licenses with new ramifications to consider, a new wireless stack to 
deal with.

What you are witnessing is but a small part of the chaos as everyone 
tackles these chores simultaneously.

	Jeff

^ permalink raw reply

* [PATCH 0/2] atl1: Introduce CONFIG_ATL1_EXPERIMENTAL
From: Chris Snook @ 2007-09-07 23:41 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: atl1-devel, Jay Cliburn, Chris Snook, netdev

The atl1 driver is currently marked EXPERIMENTAL, because a few supposedly 
performance-enhancing features still have problems.  When these features are 
disabled, the driver is completely stable, fully functional, and performs well.

Patch 1/2 Creates the kconfig option CONFIG_ATL1_EXPERIMENTAL, and removes the 
EXPERIMENTAL designation from CONFIG_ATL1

Patch 2/2 Wraps some currently-disabled features in #ifdef 
CONFIG_ATL1_EXPERIMENTAL, so developers and testers can play with these features 
more easily, and distributions will still get a fast, stable driver with 
existing .config files.

We'll also be using this to wrap around various new features we'll be 
experimenting with in coming months.  Instead of using a half dozen different 
kconfig options for each of them, like some drivers do, we'll just use this, and 
make sure things are safe for everyone before we take them out of the 
experimental wrapper.

	-- Chris

^ permalink raw reply

* Re: 2.6.23-rc4-mm1: e1000e napi lockup
From: Kok, Auke @ 2007-09-07 23:40 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: e1000-devel, netdev, akpm, David Miller, jirislaby
In-Reply-To: <46E1DF6E.6050801@garzik.org>

Jeff Garzik wrote:
> Kok, Auke wrote:
>> David Miller wrote:
>>> From: Jiri Slaby <jirislaby@gmail.com>
>>> Date: Fri, 07 Sep 2007 09:19:30 +0200
>>>
>>>> I found a regression in 2.6.23-rc4-mm1 (since -rc3-mm1) in e1000e 
>>>> driver.
>>>> napi_disable(&adapter->napi) in e1000_probe freezes the kernel on boot.
>>> Yes, the semantics changed slightly in the net-2.6.24 tree the
>>> other week and someone needs to fix it up.
>>>
>>> The netif_napi_add() implicitly does a napi_disable() call.  Device
>>> open must explicitly napi_enable() and device close must explicitly
>>> napi_disable(), and if done elsewhere these calls must be strictly
>>> balanced.
>> I'll fix it... it's my patch that adds the new napi code to it and I 
>> need to get it ready for the merge window anyway.
> 
> well....  since its close to the merge window opening, we could see what 
> happens if DaveM pulls branch 'upstream' of 
> git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
> 
> That should make this class of pre-merge-window annoyance go away.

If I do that now I get a big merge conflict:

$ git-pull . net-2.6.24
  100% (22583/22583) done
Removed Documentation/networking/NAPI_HOWTO.txt
Auto-merged drivers/net/8139cp.c
Auto-merged drivers/net/8139too.c
CONFLICT (content): Merge conflict in drivers/net/8139too.c
Auto-merged drivers/net/Kconfig
Auto-merged drivers/net/Makefile
Auto-merged drivers/net/cxgb3/cxgb3_main.c
Auto-merged drivers/net/cxgb3/sge.c
Auto-merged drivers/net/fs_enet/fs_enet-main.c
Auto-merged drivers/net/gianfar.h
Auto-merged drivers/net/ibmveth.c
CONFLICT (content): Merge conflict in drivers/net/ibmveth.c
Auto-merged drivers/net/ibmveth.h
Auto-merged drivers/net/myri10ge/myri10ge.c
Auto-merged drivers/net/netxen/netxen_nic_main.c
Auto-merged drivers/net/pasemi_mac.c
CONFLICT (content): Merge conflict in drivers/net/pasemi_mac.c
Auto-merged drivers/net/pasemi_mac.h
Auto-merged drivers/net/pcnet32.c
Auto-merged drivers/net/ps3_gelic_net.c
Auto-merged drivers/net/qla3xxx.c
Auto-merged drivers/net/s2io.c
CONFLICT (content): Merge conflict in drivers/net/s2io.c
Auto-merged drivers/net/s2io.h
Auto-merged drivers/net/sb1250-mac.c
Auto-merged drivers/net/sky2.c
Auto-merged drivers/net/sky2.h
Auto-merged drivers/net/tsi108_eth.c
Auto-merged drivers/net/wireless/rtl8187_dev.c
Auto-merged drivers/net/xen-netfront.c
Removed include/net/tcp_ecn.h
Automatic merge failed; fix conflicts and then commit the result.


for e1000e the fixup is just a 1-line change from the previous -mm napi fixup 
patch, so I don't really care (it's peanuts), but people might want to start 
looking into the above conflicts ;)

Cheers,

Auke

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply

* Re: 2.6.23-rc4-mm1: e1000e napi lockup
From: Jeff Garzik @ 2007-09-07 23:31 UTC (permalink / raw)
  To: David Miller; +Cc: e1000-devel, netdev, Kok,  Auke, jirislaby, akpm
In-Reply-To: <46E17B41.4060200@intel.com>

Kok, Auke wrote:
> David Miller wrote:
>> From: Jiri Slaby <jirislaby@gmail.com>
>> Date: Fri, 07 Sep 2007 09:19:30 +0200
>>
>>> I found a regression in 2.6.23-rc4-mm1 (since -rc3-mm1) in e1000e 
>>> driver.
>>> napi_disable(&adapter->napi) in e1000_probe freezes the kernel on boot.
>>
>> Yes, the semantics changed slightly in the net-2.6.24 tree the
>> other week and someone needs to fix it up.
>>
>> The netif_napi_add() implicitly does a napi_disable() call.  Device
>> open must explicitly napi_enable() and device close must explicitly
>> napi_disable(), and if done elsewhere these calls must be strictly
>> balanced.
> 
> I'll fix it... it's my patch that adds the new napi code to it and I 
> need to get it ready for the merge window anyway.

well....  since its close to the merge window opening, we could see what 
happens if DaveM pulls branch 'upstream' of 
git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git

That should make this class of pre-merge-window annoyance go away.

	Jeff



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply

* Re: error(s) in 2.6.23-rc5 bonding.txt ?
From: Jay Vosburgh @ 2007-09-07 23:31 UTC (permalink / raw)
  To: Rick Jones; +Cc: Linux Network Development list
In-Reply-To: <46E1CA81.6050808@hp.com>

Rick Jones <rick.jones2@hp.com> wrote:
[...]
>>         Note that this out of order delivery occurs when both the
>>         sending and receiving systems are utilizing a multiple
>>         interface bond.  Consider a configuration in which a
>>         balance-rr bond feeds into a single higher capacity network
>>         channel (e.g., multiple 100Mb/sec ethernets feeding a single
>>         gigabit ethernet via an etherchannel capable switch).  In this
>>         configuration, traffic sent from the multiple 100Mb devices to
>>         a destination connected to the gigabit device will not see
>>         packets out of order.  
>
>My first reaction was that this was incorrect - it didn't matter if the
>receiver was using a single link or not because the packets flowing across
>the multiple 100Mb links could hit the intermediate device out of order
>and so stay that way across the GbE link.

	Usually it does matter, at least at the time I tested this.

	Usually, the even striping of traffic from the balance-rr mode
will deliver in-order to a single higher speed link (e.g., N 100Mb
feeding a single 1Gb).  I say "usually" because, although I don't see it
happen with the equipment I have, I'm willing to believe that there are
gizmos that would "bundle" packets arriving on the switch ports.

	The reordering (usually) occurs when packet coalescing stuff
(either interrupt mitigation on the device, or NAPI) happens at the
receiver end, after the packets are striped evenly into the interfaces,
e.g.,

	eth0	eth1	eth2
	P1	P2	P3
	P4	P5	P6
	P7	P8	P9

	and then eth0 goes and grabs a bunch of its packets, then eth1,
and eth2 do the same afterwards, so the received order ends up something
like P1, P4, P7, P2, P5, P8, P3, P6, P9.  In Ye Olde Dayes Of Yore, with
one packet per interrupt at 10 Mb/sec, this type of configuration
wouldn't reorder (or at least not as badly).

	The text probably is lacking in some detail, though.  The real
key is that the last sender before getting to the destination system has
to do the round-robin striping.  Most switches that I'm familiar with
(again, never seen one, but willing to believe there is one) don't have
round-robin as a load balance option for etherchannel, and thus won't
evenly stripe traffic, but instead do some math on the packets so that a
given "connection" isn't split across ports.

	That said, it's certainly plausible that, for a given set of N
ethernets all enslaved to a single bonding balance-rr, the individual
ethernets could get out of sync, as it were (e.g., one running a fuller
tx ring, and thus running "behind" the others).  If bonding is the only
feeder of the devices, then for a continuous flow of traffic, all the
slaves will generally receive packets (from the kernel, for
transmission) at pretty much the same rate, and so they won't tend to
get ahead or behind.

	I haven't investigated into this deeply for a few years, but
this is my recollection of what happened with the tests I did then.  I
did testing with multiple 100Mb devices feeding either other sets of
100Mb devices or single gigabit devices.  I'm willing to believe that
things have changed, and an N feeding into one configuration can
reorder, but I haven't seen it (or really looked for it; balance-rr
isn't much the rage these days).

	-J

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com

^ permalink raw reply

* Re: [PATCH] Fix e100 on systems that have cache incoherent DMA
From: Jeff Garzik @ 2007-09-07 23:24 UTC (permalink / raw)
  To: David Acker
  Cc: Kok, Auke, John Ronciak, Jesse Brandeburg, Jeff Kirsher,
	Milton Miller, netdev, e1000-devel, Scott Feldman
In-Reply-To: <46E1B75C.6090208@roinet.com>

David Acker wrote:
> Let me know if there is any other information I can provide you.  I will 
> look through the code to see what could be going on with your machine.  
> I will also look into reproducing these results with a newer kernel.  
> This may be tricky since compulab's patches are pretty stale and don't 
> always apply easily.


pktgen outputs for the various cases modified/unmodified[/others?] would 
be nice, if you have a spot of time.

	Jeff



^ permalink raw reply

* Re: [patch 02/18] sundance: PHY address form 0, only for device I D 0x0200 (IP100A) (20070605)
From: Jeff Garzik @ 2007-09-07 23:23 UTC (permalink / raw)
  To: 黃建興-Jesse; +Cc: akpm, netdev
In-Reply-To: <AA68EB0EBA29BA40A06B700C33343EEF018686DF@fileserver.icplus.com.tw>

Just so I understand you correctly,

	1) IP100A support requires modified sundance.c

	2) IP1000A support requires new driver

Is this correct?

If so, please resend the IP1000A driver, I don't have it in my email.

	Jeff




^ permalink raw reply

* Re: [CORRECTION][PATCH] Fix a potential NULL pointer dereference in uli526x_interrupt() in drivers/net/tulip/uli526x.c
From: Jeff Garzik @ 2007-09-07 23:20 UTC (permalink / raw)
  To: Micah Gruber; +Cc: linux-kernel, netdev
In-Reply-To: <46DD13CE.6010905@gmail.com>

Micah Gruber wrote:
> This patch fixes a potential null dereference bug where we dereference dev before a null check. This patch simply moves the dereferencing after the null check.
> 
> Signed-off-by: Micah Gruber <micah.gruber@gmail.com>
> ---
> 
> --- a/drivers/net/tulip/uli526x.c
> +++ b/drivers/net/tulip/uli526x.c
> @@ -663,7 +663,7 @@
>  {
>  	struct net_device *dev = dev_id;
>  	struct uli526x_board_info *db = netdev_priv(dev);
> -	unsigned long ioaddr = dev->base_addr;
> +	unsigned long ioaddr;
>  	unsigned long flags;
>  
>  	if (!dev) {
> @@ -671,6 +671,8 @@
>  		return IRQ_NONE;
>  	}
>  
> +	ioaddr = dev->base_addr;
> +

as satyam noted, just remove the !dev test



^ permalink raw reply

* Re: [PATCH][MIPS][7/7] AR7: ethernet
From: Jeff Garzik @ 2007-09-07 23:04 UTC (permalink / raw)
  To: Matteo Croce
  Cc: Andrew Morton, linux-mips, ejka, netdev, davem, kuznet, pekkas,
	jmorris, yoshfuji, kaber
In-Reply-To: <200709070121.42629.technoboy85@gmail.com>

Matteo Croce wrote:
> Il Friday 07 September 2007 00:30:25 Andrew Morton ha scritto:
>>> On Thu, 6 Sep 2007 17:34:10 +0200 Matteo Croce <technoboy85@gmail.com> wrote:
>>> Driver for the cpmac 100M ethernet driver.
>>> It works fine disabling napi support, enabling it gives a kernel panic
>>> when the first IPv6 packet has to be forwarded.
>>> Other than that works fine.
>>>
>> I'm not too sure why I got cc'ed on this (and not on patches 1-6?) but
>> whatever.
> 
> I mailed every maintainer in the respective section in the file MAINTAINERS
> and you were in the "NETWORK DEVICE DRIVERS" section
> 
>> This patch introduces quite a number of basic coding-style mistakes. 
>> Please run it through scripts/checkpatch.pl and review the output.
> 
> Already done. I'm collecting other suggestions before committing

cool, I'll wait for the resend before reviewing, then.

As an author I understand that fixing up coding style / cosmetic stuff 
rather than "meat" is annoying.

But it is important to emphasize that a "clean" driver is what makes a 
good, thorough, effective review possible.

	Jeff



^ permalink raw reply

* [PATCH] DOC: Update networking/multiqueue.txt with correct information.
From: PJ Waskiewicz @ 2007-09-07 22:50 UTC (permalink / raw)
  To: davem; +Cc: netdev, kaber

Updated the multiqueue.txt document to call out the correct kernel options
to select to enable multiqueue.

Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---

 Documentation/networking/multiqueue.txt |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/Documentation/networking/multiqueue.txt b/Documentation/networking/multiqueue.txt
index 00b60cc..ea5a42e 100644
--- a/Documentation/networking/multiqueue.txt
+++ b/Documentation/networking/multiqueue.txt
@@ -58,9 +58,13 @@ software, so it's a straight round-robin qdisc.  It uses the same syntax and
 classification priomap that sch_prio uses, so it should be intuitive to
 configure for people who've used sch_prio.
 
-The PRIO qdisc naturally plugs into a multiqueue device.  If PRIO has been
-built with NET_SCH_PRIO_MQ, then upon load, it will make sure the number of
-bands requested is equal to the number of queues on the hardware.  If they
+In order to utilitize the multiqueue features of the qdiscs, the network
+device layer needs to enable multiple queue support.  This can be done by
+selecting NETDEVICES_MULTIQUEUE under Drivers.
+
+The PRIO qdisc naturally plugs into a multiqueue device.  If
+NETDEVICES_MULTIQUEUE is selected, then on qdisc load, the number of
+bands requested is compared to the number of queues on the hardware.  If they
 are equal, it sets a one-to-one mapping up between the queues and bands.  If
 they're not equal, it will not load the qdisc.  This is the same behavior
 for RR.  Once the association is made, any skb that is classified will have

^ permalink raw reply related

* Re: [PATCH v3 2/2][BNX2]: Add iSCSI support to BNX2 devices.
From: Mike Christie @ 2007-09-07 22:36 UTC (permalink / raw)
  To: open-iscsi; +Cc: davem, mchristi, netdev, anilgv, talm, lusinsky, uri
In-Reply-To: <1188599815.5176.12.camel@dell>

Some quick comments that got cut out of the original mail.


> +
> +/*
> + * map single buffer
> + */
> +static int bnx2i_map_single_buf(struct bnx2i_hba *hba,
> +				       struct bnx2i_cmd *cmd)
> +{
> +	struct scsi_cmnd *sc = cmd->scsi_cmd;
> +	struct iscsi_bd *bd = cmd->bd_tbl->bd_tbl;
> +	int byte_count;
> +	int bd_count;
> +	u64 addr;
> +
> +	byte_count = sc->request_bufflen;
> +	sc->SCp.dma_handle =
> +		pci_map_single(hba->pci_dev, sc->request_buffer,
> +			       sc->request_bufflen, sc->sc_data_direction);
> +	addr = sc->SCp.dma_handle;
> +
> +	if (byte_count > MAX_BD_LENGTH) {
> +		bd_count = bnx2i_split_bd(cmd, addr, byte_count, 0);
> +	} else {
> +		bd_count = 1;
> +		bd[0].buffer_addr_lo = addr & 0xffffffff;
> +		bd[0].buffer_addr_hi = addr >> 32;
> +		bd[0].buffer_length = sc->request_bufflen;
> +		bd[0].flags = ISCSI_BD_FIRST_IN_BD_CHAIN |
> +			      ISCSI_BD_LAST_IN_BD_CHAIN;
> +	}
> +	bd[bd_count - 1].flags |= ISCSI_BD_LAST_IN_BD_CHAIN;
> +
> +	return bd_count;
> +}

I think you should always be getting use_sg greater than zero now, so 
the map single path is not needed.


> +
> +
> +/*
> + * map SG list
> + */
> +static int bnx2i_map_sg(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
> +{
> +	struct scsi_cmnd *sc = cmd->scsi_cmd;
> +	struct iscsi_bd *bd = cmd->bd_tbl->bd_tbl;
> +	struct scatterlist *sg;
> +	int byte_count = 0;
> +	int sg_frags;
> +	int bd_count = 0;
> +	int sg_count;
> +	int sg_len;
> +	u64 addr;
> +	int i;
> +
> +	sg = sc->request_buffer;
> +	sg_count = pci_map_sg(hba->pci_dev, sg, sc->use_sg,
> +			      sc->sc_data_direction);
> +
> +	for (i = 0; i < sg_count; i++) {
> +		sg_len = sg_dma_len(sg);
> +		addr = sg_dma_address(sg);
> +		if (sg_len > MAX_BD_LENGTH)
> +			sg_frags = bnx2i_split_bd(cmd, addr, sg_len,
> +						  bd_count);


If you call blk_queue_max_segment_size() in the slave_configure callout 
you can limit the size of the segments that the block layer builds so 
they are smaller than MAX_BD_LENGTH. However, I am not sure how useful 
that is. I think DMA-API.txt states that the mapping code is ok to 
merged mutliple sglists entries into one so I think that means that we 
can still end up with an entry that is larger than MAX_BD_LENGTH. Not 
sure if there is way to tell the pci/dma map_sg code to limit this too.

^ permalink raw reply

* Re: [PATCH] ixgbe: driver for Intel(R) 82598 PCI-Express 10GbE adapters (v4)
From: Jeff Garzik @ 2007-09-07 22:36 UTC (permalink / raw)
  To: David Miller
  Cc: auke-jan.h.kok, netdev, ayyappan.veeraiyan, akpm, arjan, hch,
	billfink, shemminger, rick.jones2, inaky, mb, nhorman
In-Reply-To: <20070906.124422.71092816.davem@davemloft.net>

David Miller wrote:
> From: "Kok, Auke" <auke-jan.h.kok@intel.com>
> Date: Thu, 06 Sep 2007 11:31:47 -0700
> 
>> Also available through git:// and http:// here:
>>
>>    http://foo-projects.org/~sofar/ixgbe-20070905-submission.patch
>>    http://foo-projects.org/~sofar/ixgbe-20070905-submission.patch.bz2
>>    (git-am formatted!)
>>
>>    git://lost.foo-projects.org/~ahkok/linux-2.6 ixgbe-20070905-submission
> 
> To be honest I have absolutely no problems with this driver and we
> should just cut the crap and merge it in now.
> 
> Any objections anyone makes at this point is frankly nit picking crap
> which we can cure with followon cleanups and corrections.

Are you responding to a strawman or something?

AFAICS nobody objected to it, and Auke cleaned it up a la e1000e, which 
got queued during KS.

	Jeff




^ permalink raw reply

* Re: [PATCH v3 2/2][BNX2]: Add iSCSI support to BNX2 devices.
From: Mike Christie @ 2007-09-07 22:23 UTC (permalink / raw)
  To: Anil Veerabhadrappa
  Cc: Mike Christie, Michael Chan, davem, netdev, open-iscsi, talm,
	lusinsky, uri, SCSI Mailing List
In-Reply-To: <1189027622.19638.42.camel@dhcp-10-13-106-205.broadcom.com>

Anil Veerabhadrappa wrote:
>>
>>> +
>>> +/* iSCSI stages */
>>> +#define ISCSI_STAGE_SECURITY_NEGOTIATION (0)
>>> +#define ISCSI_STAGE_LOGIN_OPERATIONAL_NEGOTIATION (1)
>>> +#define ISCSI_STAGE_FULL_FEATURE_PHASE (3)
>>> +/* Logout response codes */
>>> +#define ISCSI_LOGOUT_RESPONSE_CONNECTION_CLOSED (0)
>>> +#define ISCSI_LOGOUT_RESPONSE_CID_NOT_FOUND (1)
>>> +#define ISCSI_LOGOUT_RESPONSE_CLEANUP_FAILED (3)
>>> +
>>> +/* iSCSI task types */
>>> +#define ISCSI_TASK_TYPE_READ    (0)
>>> +#define ISCSI_TASK_TYPE_WRITE   (1)
>>> +#define ISCSI_TASK_TYPE_MPATH   (2)
>>
>>
>>
>> All of these iscsi code shoulds be in iscsi_proto.h or should be added 
>> there.
> This is a very tricky proposal as this header file is automatically
> generated by a well defined process and is shared between various driver
> supporting multiple platform/OS and the firmware. If it is not of a big
> issue I would like to keep it the way it is.

The values that are iscsi RFC values should come from the iscsi_proto.h 
file and not be duplicated for each driver.


>>> +/*
>>> + * hardware reset
>>> + */
>>> +int bnx2i_reset(struct scsi_cmnd *sc)
>>> +{
>>> +	return 0;
>>> +}
>>
>> So what is up with this one? It seems like if there is a way to reset 
>> hardware then you would want it as the scsi eh host reset callout 
>> instead of dropping the session. We could add some transport level 
>> recovery callouts for the iscsi specifics.
> 
> We may not be able to support HBA cold reset as bnx2 driver is the
> primary owner of chip reset and initialization. This is the drawback of
> sharing network interface with the NIC driver. If there is a need for
> administrator to reset the iSCSI port same can be achieved by running
> 'ifdown eth#' and 'ifup eth#'.
> Current driver even allows ethernet interface reset when there are
> active iSCSI connection, all active iscsi sessions will be reinstated
> when the network link comes back live
>  
> 

If you cannot support it or it does not make sense just remove the stub 
then. I say it is not a big deal now, but hopefully we do not hit fun 
like with qla3xxx and qla4xxx :)

>>> +
>>> +void bnx2i_sysfs_cleanup(void)
>>> +{
>>> +	class_device_unregister(&port_class_dev);
>>> +	class_unregister(&bnx2i_class);
>>> +}
>> The sysfs bits related to the hba should be use one of the scsi sysfs 
>> facilities or if they are related to iscsi bits and are generic then 
>> through the iscsi hba
> 
> bnx2i needs 2 sysfs entries -
> 1. QP size info - this is used to size per connection shared data
> structures to issue work requests to chip (login, scsi cmd, tmf, nopin)
> and get completions from the chip (scsi completions, async messages,
> etc'). This is a iSCSI HBA attribute
> 2. port mapper - we can be more flexible on classifying this as either
> iSCSI HBA attribute or bnx2i driver global attribute
> Can hooks be added to iSCSI transport class to include these?
> 

Which ones were they exactly? I think JamesB wanted only common 
transport values in the transport class. If it is driver specific then 
it should go on the host or target or device with the scsi_host_template 
attrs.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox