All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jesper Nilsson <jesper.nilsson@axis.com>
To: Andrew Morton <akpm@linux-foundation.org>,
	Mikael Starvik <mikael.starvik@axis.com>,
	Jesper Nilsson <jesper.nilsson@axis.com>,
	linux-kernel@vger.kernel.org, jgarzik@pobox.com
Subject: [PATCH 9/16] CRIS architecture: Correct compile errors
Date: Tue, 30 Oct 2007 10:32:31 +0100	[thread overview]
Message-ID: <20071030093231.GL11960@axis.com> (raw)

New (updated) version of ethernet driver for cris v10.

- First steps to simplify and make the MII code more similar
  between the etrax100 and etraxfs ports.

- Start the transmit queue before enabling tx interrupts
  to avoid race with the first frame.

- Flip the comparition statement to stick to physical addresses
  to avoid phys_to_virt mapping a potential null pointer.
  This was not an error but the change simplifies debugging
  of address-space mappings.

- Made myPrevRxDesc local to e100_rx since it was only used there.
  Fixed out of memory handling in e100_rx.  If dev_alloc_skb() fails
  persistently the system is hosed anyway but at least it won't
  loop in an interrupt handler.

- Correct some code formatting issues.

- Add defines SET_ETH_ENABLE_LEDS, SET_ETH_DISABLE_LEDS
  and SET_ETH_AUTONEG used in new cris v10 ethernet driver.

Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>

---
 drivers/net/cris/eth_v10.c  |  430 ++++++++++++++++++++++++++++----------------
 include/asm-cris/ethernet.h |    3 
 2 files changed, 280 insertions(+), 153 deletions(-)

diff -urBb -X /h/jespern/.exclude_files clean_linux-2.6.23/drivers/net/cris/eth_v10.c linux-2.6.23/drivers/net/cris/eth_v10.c
--- clean_linux-2.6.23/drivers/net/cris/eth_v10.c	2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23/drivers/net/cris/eth_v10.c	2007-10-23 10:44:11.000000000 +0200
@@ -250,6 +39,7 @@
 #include <asm/bitops.h>
 #include <asm/ethernet.h>
 #include <asm/cache.h>
+#include <asm/arch/io_interface_mux.h>
 
 //#define ETHDEBUG
 #define D(x)
@@ -279,6 +69,9 @@
 	 * by this lock as well.
 	 */
 	spinlock_t lock;
+
+	spinlock_t led_lock; /* Protect LED state */
+	spinlock_t transceiver_lock; /* Protect transceiver state. */
 };
 
 typedef struct etrax_eth_descr
@@ -295,8 +88,6 @@
 	void (*check_duplex)(struct net_device* dev);
 };
 
-struct transceiver_ops* transceiver;
-
 /* Duplex settings */
 enum duplex
 {
@@ -307,7 +98,7 @@
 
 /* Dma descriptors etc. */
 
-#define MAX_MEDIA_DATA_SIZE 1518
+#define MAX_MEDIA_DATA_SIZE 1522
 
 #define MIN_PACKET_LEN      46
 #define ETHER_HEAD_LEN      14
@@ -332,8 +123,8 @@
 
 /*Intel LXT972A specific*/
 #define MDIO_INT_STATUS_REG_2			0x0011
-#define MDIO_INT_FULL_DUPLEX_IND		( 1 << 9 )
-#define MDIO_INT_SPEED				( 1 << 14 )
+#define MDIO_INT_FULL_DUPLEX_IND       (1 << 9)
+#define MDIO_INT_SPEED                (1 << 14)
 
 /* Network flash constants */
 #define NET_FLASH_TIME                  (HZ/50) /* 20 ms */
@@ -344,8 +135,8 @@
 #define NO_NETWORK_ACTIVITY 0
 #define NETWORK_ACTIVITY    1
 
-#define NBR_OF_RX_DESC     64
-#define NBR_OF_TX_DESC     256
+#define NBR_OF_RX_DESC     32
+#define NBR_OF_TX_DESC     16
 
 /* Large packets are sent directly to upper layers while small packets are */
 /* copied (to reduce memory waste). The following constant decides the breakpoint */
@@ -367,7 +158,6 @@
 static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
                                           to be processed */
 static etrax_eth_descr *myLastRxDesc;  /* The last processed descriptor */
-static etrax_eth_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
 
 static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32)));
 
@@ -377,7 +167,6 @@
 static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32)));
 
 static unsigned int network_rec_config_shadow = 0;
-static unsigned int mdio_phy_addr; /* Transciever address */
 
 static unsigned int network_tr_ctrl_shadow = 0;
 
@@ -411,7 +200,7 @@
 static void e100_tx_timeout(struct net_device *dev);
 static struct net_device_stats *e100_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
-static void e100_hardware_send_packet(char *buf, int length);
+static void e100_hardware_send_packet(struct net_local* np, char *buf, int length);
 static void update_rx_stats(struct net_device_stats *);
 static void update_tx_stats(struct net_device_stats *);
 static int e100_probe_transceiver(struct net_device* dev);
@@ -434,7 +223,10 @@
 static void e100_set_network_leds(int active);
 
 static const struct ethtool_ops e100_ethtool_ops;
-
+#if defined(CONFIG_ETRAX_NO_PHY)
+static void dummy_check_speed(struct net_device* dev);
+static void dummy_check_duplex(struct net_device* dev);
+#else
 static void broadcom_check_speed(struct net_device* dev);
 static void broadcom_check_duplex(struct net_device* dev);
 static void tdk_check_speed(struct net_device* dev);
@@ -443,16 +235,28 @@
 static void intel_check_duplex(struct net_device* dev);
 static void generic_check_speed(struct net_device* dev);
 static void generic_check_duplex(struct net_device* dev);
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void e100_netpoll(struct net_device* dev);
+#endif
+
+static int autoneg_normal = 1;
 
 struct transceiver_ops transceivers[] =
 {
+#if defined(CONFIG_ETRAX_NO_PHY)
+	{0x0000, dummy_check_speed, dummy_check_duplex}        /* Dummy */
+#else
 	{0x1018, broadcom_check_speed, broadcom_check_duplex},  /* Broadcom */
 	{0xC039, tdk_check_speed, tdk_check_duplex},            /* TDK 2120 */
 	{0x039C, tdk_check_speed, tdk_check_duplex},            /* TDK 2120C */
         {0x04de, intel_check_speed, intel_check_duplex},     	/* Intel LXT972A*/
 	{0x0000, generic_check_speed, generic_check_duplex}     /* Generic, must be last */
+#endif
 };
 
+struct transceiver_ops* transceiver = &transceivers[0];
+
 #define tx_done(dev) (*R_DMA_CH0_CMD == 0)
 
 /*
@@ -471,14 +275,22 @@
 	int i, err;
 
 	printk(KERN_INFO
-	       "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n");
+	       "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 1998-2007 Axis Communications AB\n");
 
-	dev = alloc_etherdev(sizeof(struct net_local));
-	np = dev->priv;
+	if (cris_request_io_interface(if_eth, cardname)) {
+		printk(KERN_CRIT "etrax_ethernet_init failed to get IO interface\n");
+		return -EBUSY;
+	}
 
+	dev = alloc_etherdev(sizeof(struct net_local));
 	if (!dev)
 		return -ENOMEM;
 
+	np = netdev_priv(dev);
+
+	/* we do our own locking */
+	dev->features |= NETIF_F_LLTX;
+		
 	dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */
 
 	/* now setup our etrax specific stuff */
@@ -498,14 +310,22 @@
 	dev->do_ioctl           = e100_ioctl;
 	dev->set_config		= e100_set_config;
 	dev->tx_timeout         = e100_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = e100_netpoll;
+#endif
+
+	spin_lock_init(&np->lock);
+	spin_lock_init(&np->led_lock);
+	spin_lock_init(&np->transceiver_lock);
 
 	/* Initialise the list of Etrax DMA-descriptors */
 
 	/* Initialise receive descriptors */
 
 	for (i = 0; i < NBR_OF_RX_DESC; i++) {
-		/* Allocate two extra cachelines to make sure that buffer used by DMA
-		 * does not share cacheline with any other data (to avoid cache bug)
+		/* Allocate two extra cachelines to make sure that buffer used
+		 * by DMA does not share cacheline with any other data (to
+		 * avoid cache bug)
 		 */
 		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
 		if (!RxDescList[i].skb)
@@ -541,7 +362,6 @@
 
 	myNextRxDesc  = &RxDescList[0];
 	myLastRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
-	myPrevRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
 	myFirstTxDesc = &TxDescList[0];
 	myNextTxDesc  = &TxDescList[0];
 	myLastTxDesc  = &TxDescList[NBR_OF_TX_DESC - 1];
@@ -562,10 +382,11 @@
 	current_speed = 10;
 	current_speed_selection = 0; /* Auto */
 	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
-        duplex_timer.data = (unsigned long)dev;
+	speed_timer.data = (unsigned long)dev;
 	speed_timer.function = e100_check_speed;
 
 	clear_led_timer.function = e100_clear_network_leds;
+	clear_led_timer.data = (unsigned long)dev;
 
 	full_duplex = 0;
 	current_duplex = autoneg;
@@ -574,7 +395,6 @@
 	duplex_timer.function = e100_check_duplex;
 
         /* Initialize mii interface */
-	np->mii_if.phy_id = mdio_phy_addr;
 	np->mii_if.phy_id_mask = 0x1f;
 	np->mii_if.reg_num_mask = 0x1f;
 	np->mii_if.dev = dev;
@@ -585,6 +405,9 @@
 	/* unwanted addresses are matched */
 	*R_NETWORK_GA_0 = 0x00000000;
 	*R_NETWORK_GA_1 = 0x00000000;
+
+	/* Initialize next time the led can flash */
+	led_next_time = jiffies;
 	return 0;
 }
 
@@ -595,7 +418,7 @@
 static int
 e100_set_mac_address(struct net_device *dev, void *p)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	struct sockaddr *addr = p;
 	int i;
 
@@ -690,6 +513,25 @@
 		goto grace_exit2;
 	}
 
+	/*
+	 * Always allocate the DMA channels after the IRQ,
+	 * and clean up on failure.
+	 */
+
+	if (cris_request_dma(NETWORK_TX_DMA_NBR,
+	                     cardname,
+	                     DMA_VERBOSE_ON_ERROR,
+	                     dma_eth)) {
+		goto grace_exit3;
+        }
+
+	if (cris_request_dma(NETWORK_RX_DMA_NBR,
+	                     cardname,
+	                     DMA_VERBOSE_ON_ERROR,
+	                     dma_eth)) {
+		goto grace_exit4;
+        }
+
 	/* give the HW an idea of what MAC address we want */
 
 	*R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
@@ -704,6 +546,7 @@
 
 	*R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
 #else
+	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, max_size, size1522);
 	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive);
 	SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable);
 	SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
@@ -723,8 +566,7 @@
 	SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable);
 	*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 
 	/* enable the irq's for ethernet DMA */
 
@@ -756,12 +598,13 @@
 
 	*R_DMA_CH0_FIRST = 0;
 	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
+	netif_start_queue(dev);
 
-	restore_flags(flags);
+	local_irq_restore(flags);
 
 	/* Probe for transceiver */
 	if (e100_probe_transceiver(dev))
-		goto grace_exit3;
+		goto grace_exit5;
 
 	/* Start duplex/speed timers */
 	add_timer(&speed_timer);
@@ -770,10 +613,14 @@
 	/* We are now ready to accept transmit requeusts from
 	 * the queueing layer of the networking.
 	 */
-	netif_start_queue(dev);
+	netif_carrier_on(dev);
 
 	return 0;
 
+grace_exit5:
+	cris_free_dma(NETWORK_RX_DMA_NBR, cardname);
+grace_exit4:
+	cris_free_dma(NETWORK_TX_DMA_NBR, cardname);
 grace_exit3:
 	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
 grace_exit2:
@@ -784,12 +631,20 @@
 	return -EAGAIN;
 }
 
-
+#if defined(CONFIG_ETRAX_NO_PHY)
+static void
+dummy_check_speed(struct net_device* dev)
+{
+	current_speed = 100;
+}
+#else
 static void
 generic_check_speed(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE);
 	if ((data & ADVERTISE_100FULL) ||
 	    (data & ADVERTISE_100HALF))
 		current_speed = 100;
@@ -801,7 +656,10 @@
 tdk_check_speed(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+				 MDIO_TDK_DIAGNOSTIC_REG);
 	current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);
 }
 
@@ -809,7 +667,10 @@
 broadcom_check_speed(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+				 MDIO_AUX_CTRL_STATUS_REG);
 	current_speed = (data & MDIO_BC_SPEED ? 100 : 10);
 }
 
@@ -817,46 +678,62 @@
 intel_check_speed(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+				 MDIO_INT_STATUS_REG_2);
 	current_speed = (data & MDIO_INT_SPEED ? 100 : 10);
 }
-
+#endif
 static void
 e100_check_speed(unsigned long priv)
 {
 	struct net_device* dev = (struct net_device*)priv;
+	struct net_local *np = netdev_priv(dev);
 	static int led_initiated = 0;
 	unsigned long data;
 	int old_speed = current_speed;
 
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR);
+	spin_lock(&np->transceiver_lock);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMSR);
 	if (!(data & BMSR_LSTATUS)) {
 		current_speed = 0;
 	} else {
 		transceiver->check_speed(dev);
 	}
 
+	spin_lock(&np->led_lock);
 	if ((old_speed != current_speed) || !led_initiated) {
 		led_initiated = 1;
 		e100_set_network_leds(NO_NETWORK_ACTIVITY);
+		if (current_speed)
+			netif_carrier_on(dev);
+		else
+			netif_carrier_off(dev);
 	}
+	spin_unlock(&np->led_lock);
 
 	/* Reinitialize the timer. */
 	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
 	add_timer(&speed_timer);
+
+	spin_unlock(&np->transceiver_lock);
 }
 
 static void
 e100_negotiate(struct net_device* dev)
 {
-	unsigned short data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+	struct net_local *np = netdev_priv(dev);
+	unsigned short data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+						MII_ADVERTISE);
 
 	/* Discard old speed and duplex settings */
 	data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL |
 	          ADVERTISE_10HALF | ADVERTISE_10FULL);
 
 	switch (current_speed_selection) {
-		case 10 :
+		case 10:
 			if (current_duplex == full)
 				data |= ADVERTISE_10FULL;
 			else if (current_duplex == half)
@@ -865,7 +742,7 @@
 				data |= ADVERTISE_10HALF | ADVERTISE_10FULL;
 			break;
 
-		case 100 :
+		case 100:
 			 if (current_duplex == full)
 				data |= ADVERTISE_100FULL;
 			else if (current_duplex == half)
@@ -874,7 +751,7 @@
 				data |= ADVERTISE_100HALF | ADVERTISE_100FULL;
 			break;
 
-		case 0 : /* Auto */
+		case 0: /* Auto */
 			 if (current_duplex == full)
 				data |= ADVERTISE_100FULL | ADVERTISE_10FULL;
 			else if (current_duplex == half)
@@ -884,35 +761,44 @@
 				  ADVERTISE_100HALF | ADVERTISE_100FULL;
 			break;
 
-		default : /* assume autoneg speed and duplex */
+		default: /* assume autoneg speed and duplex */
 			data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
 				  ADVERTISE_100HALF | ADVERTISE_100FULL;
+			break;
 	}
 
-	e100_set_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE, data);
+	e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE, data);
 
 	/* Renegotiate with link partner */
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+	if (autoneg_normal) {
+	  data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR);
 	data |= BMCR_ANENABLE | BMCR_ANRESTART;
-
-	e100_set_mdio_reg(dev, mdio_phy_addr, MII_BMCR, data);
+	}
+	e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR, data);
 }
 
 static void
 e100_set_speed(struct net_device* dev, unsigned long speed)
 {
+	struct net_local *np = netdev_priv(dev);
+
+	spin_lock(&np->transceiver_lock);
 	if (speed != current_speed_selection) {
 		current_speed_selection = speed;
 		e100_negotiate(dev);
 	}
+	spin_unlock(&np->transceiver_lock);
 }
 
 static void
 e100_check_duplex(unsigned long priv)
 {
 	struct net_device *dev = (struct net_device *)priv;
-	struct net_local *np = (struct net_local *)dev->priv;
-	int old_duplex = full_duplex;
+	struct net_local *np = netdev_priv(dev);
+	int old_duplex;
+
+	spin_lock(&np->transceiver_lock);
+	old_duplex = full_duplex;
 	transceiver->check_duplex(dev);
 	if (old_duplex != full_duplex) {
 		/* Duplex changed */
@@ -924,13 +810,22 @@
 	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
 	add_timer(&duplex_timer);
 	np->mii_if.full_duplex = full_duplex;
+	spin_unlock(&np->transceiver_lock);
 }
-
+#if defined(CONFIG_ETRAX_NO_PHY)
+static void
+dummy_check_duplex(struct net_device* dev)
+{
+	full_duplex = 1;
+}
+#else
 static void
 generic_check_duplex(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE);
 	if ((data & ADVERTISE_10FULL) ||
 	    (data & ADVERTISE_100FULL))
 		full_duplex = 1;
@@ -942,7 +837,10 @@
 tdk_check_duplex(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+				 MDIO_TDK_DIAGNOSTIC_REG);
 	full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;
 }
 
@@ -950,7 +848,10 @@
 broadcom_check_duplex(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+				 MDIO_AUX_CTRL_STATUS_REG);
 	full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;
 }
 
@@ -958,38 +859,51 @@
 intel_check_duplex(struct net_device* dev)
 {
 	unsigned long data;
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+	struct net_local *np = netdev_priv(dev);
+
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+				 MDIO_INT_STATUS_REG_2);
 	full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;
 }
-
+#endif
 static void
 e100_set_duplex(struct net_device* dev, enum duplex new_duplex)
 {
+	struct net_local *np = netdev_priv(dev);
+
+	spin_lock(&np->transceiver_lock);
 	if (new_duplex != current_duplex) {
 		current_duplex = new_duplex;
 		e100_negotiate(dev);
 	}
+	spin_unlock(&np->transceiver_lock);
 }
 
 static int
 e100_probe_transceiver(struct net_device* dev)
 {
+#if !defined(CONFIG_ETRAX_NO_PHY)
 	unsigned int phyid_high;
 	unsigned int phyid_low;
 	unsigned int oui;
 	struct transceiver_ops* ops = NULL;
+	struct net_local *np = netdev_priv(dev);
+
+	spin_lock(&np->transceiver_lock);
 
 	/* Probe MDIO physical address */
-	for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {
-		if (e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR) != 0xffff)
+	for (np->mii_if.phy_id = 0; np->mii_if.phy_id <= 31; 
+	     np->mii_if.phy_id++) {
+		if (e100_get_mdio_reg(dev, 
+				      np->mii_if.phy_id, MII_BMSR) != 0xffff)
 			break;
 	}
-	if (mdio_phy_addr == 32)
+	if (np->mii_if.phy_id == 32)
 		 return -ENODEV;
 
 	/* Get manufacturer */
-	phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1);
-	phyid_low = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID2);
+	phyid_high = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID1);
+	phyid_low = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID2);
 	oui = (phyid_high << 6) | (phyid_low >> 10);
 
 	for (ops = &transceivers[0]; ops->oui; ops++) {
@@ -998,6 +912,8 @@
 	}
 	transceiver = ops;
 
+	spin_unlock(&np->transceiver_lock);
+#endif
 	return 0;
 }
 
@@ -1092,13 +1009,14 @@
 static void
 e100_reset_transceiver(struct net_device* dev)
 {
+	struct net_local *np = netdev_priv(dev);
 	unsigned short cmd;
 	unsigned short data;
 	int bitCounter;
 
-	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+	data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR);
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MII_BMCR << 2);
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (np->mii_if.phy_id << 7) | (MII_BMCR << 2);
 
 	e100_send_mdio_cmd(cmd, 1);
 
@@ -1116,7 +1034,7 @@
 static void
 e100_tx_timeout(struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&np->lock, flags);
@@ -1138,8 +1056,7 @@
 	e100_reset_transceiver(dev);
 
 	/* and get rid of the packets that never got an interrupt */
-	while (myFirstTxDesc != myNextTxDesc)
-	{
+	while (myFirstTxDesc != myNextTxDesc) {
 		dev_kfree_skb(myFirstTxDesc->skb);
 		myFirstTxDesc->skb = 0;
 		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
@@ -1165,7 +1082,7 @@
 static int
 e100_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	unsigned char *buf = skb->data;
 	unsigned long flags;
 
@@ -1178,7 +1095,7 @@
 
 	dev->trans_start = jiffies;
 
-	e100_hardware_send_packet(buf, skb->len);
+	e100_hardware_send_packet(np, buf, skb->len);
 
 	myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
 
@@ -1201,13 +1118,15 @@
 e100rxtx_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct net_local *np = (struct net_local *)dev->priv;
-	unsigned long irqbits = *R_IRQ_MASK2_RD;
+	struct net_local *np = netdev_priv(dev);
+	unsigned long irqbits;
 
-	/* Disable RX/TX IRQs to avoid reentrancy */
-	*R_IRQ_MASK2_CLR =
-	  IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
-	  IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+	/* 
+	 * Note that both rx and tx interrupts are blocked at this point, 
+	 * regardless of which got us here.
+	 */
+	
+	irqbits = *R_IRQ_MASK2_RD;
 
 	/* Handle received packets */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
@@ -1223,7 +1142,7 @@
 			 * allocate a new buffer to put a packet in.
 			 */
 			e100_rx(dev);
-			((struct net_local *)dev->priv)->stats.rx_packets++;
+			np->stats.rx_packets++;
 			/* restart/continue on the channel, for safety */
 			*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);
 			/* clear dma channel 1 eop/descr irq bits */
@@ -1237,9 +1156,8 @@
 	}
 
 	/* Report any packets that have been sent */
-	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-	       myFirstTxDesc != myNextTxDesc)
-	{
+	while (virt_to_phys(myFirstTxDesc) != *R_DMA_CH0_FIRST &&
+	       (netif_queue_stopped(dev) || myFirstTxDesc != myNextTxDesc)) {
 		np->stats.tx_bytes += myFirstTxDesc->skb->len;
 		np->stats.tx_packets++;
 
@@ -1248,19 +1166,15 @@
 		dev_kfree_skb_irq(myFirstTxDesc->skb);
 		myFirstTxDesc->skb = 0;
 		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+                /* Wake up queue. */
+		netif_wake_queue(dev);
 	}
 
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
-		/* acknowledge the eop interrupt and wake up queue */
+		/* acknowledge the eop interrupt. */
 		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
-		netif_wake_queue(dev);
 	}
 
-	/* Enable RX/TX IRQs again */
-	*R_IRQ_MASK2_SET =
-	  IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
-
 	return IRQ_HANDLED;
 }
 
@@ -1268,7 +1182,7 @@
 e100nw_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	unsigned long irqbits = *R_IRQ_MASK0_RD;
 
 	/* check for underrun irq */
@@ -1290,7 +1204,6 @@
 		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
 		*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
 		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
-		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
 		np->stats.tx_errors++;
 		D(printk("ethernet excessive collisions!\n"));
 	}
@@ -1303,12 +1216,13 @@
 {
 	struct sk_buff *skb;
 	int length = 0;
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 	unsigned char *skb_data_ptr;
 #ifdef ETHDEBUG
 	int i;
 #endif
-
+	etrax_eth_descr *prevRxDesc;  /* The descriptor right before myNextRxDesc */
+	spin_lock(&np->led_lock);
 	if (!led_active && time_after(jiffies, led_next_time)) {
 		/* light the network leds depending on the current speed. */
 		e100_set_network_leds(NETWORK_ACTIVITY);
@@ -1318,9 +1232,10 @@
 		led_active = 1;
 		mod_timer(&clear_led_timer, jiffies + HZ/10);
 	}
+	spin_unlock(&np->led_lock);
 
 	length = myNextRxDesc->descr.hw_len - 4;
-	((struct net_local *)dev->priv)->stats.rx_bytes += length;
+	np->stats.rx_bytes += length;
 
 #ifdef ETHDEBUG
 	printk("Got a packet of length %d:\n", length);
@@ -1340,7 +1255,7 @@
 		if (!skb) {
 			np->stats.rx_errors++;
 			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-			return;
+			goto update_nextrxdesc;
 		}
 
 		skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
@@ -1358,15 +1273,15 @@
 	else {
 		/* Large packet, send directly to upper layers and allocate new
 		 * memory (aligned to cache line boundary to avoid bug).
-		 * Before sending the skb to upper layers we must make sure that
-		 * skb->data points to the aligned start of the packet.
+		 * Before sending the skb to upper layers we must make sure
+		 * that skb->data points to the aligned start of the packet.
 		 */
 		int align;
 		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
 		if (!new_skb) {
 			np->stats.rx_errors++;
 			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-			return;
+			goto update_nextrxdesc;
 		}
 		skb = myNextRxDesc->skb;
 		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;
@@ -1381,9 +1296,10 @@
 	/* Send the packet to the upper layers */
 	netif_rx(skb);
 
+  update_nextrxdesc:
 	/* Prepare for next packet */
 	myNextRxDesc->descr.status = 0;
-	myPrevRxDesc = myNextRxDesc;
+	prevRxDesc = myNextRxDesc;
 	myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next);
 
 	rx_queue_len++;
@@ -1391,9 +1307,9 @@
 	/* Check if descriptors should be returned */
 	if (rx_queue_len == RX_QUEUE_THRESHOLD) {
 		flush_etrax_cache();
-		myPrevRxDesc->descr.ctrl |= d_eol;
+		prevRxDesc->descr.ctrl |= d_eol;
 		myLastRxDesc->descr.ctrl &= ~d_eol;
-		myLastRxDesc = myPrevRxDesc;
+		myLastRxDesc = prevRxDesc;
 		rx_queue_len = 0;
 	}
 }
@@ -1402,7 +1318,7 @@
 static int
 e100_close(struct net_device *dev)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
 
 	printk(KERN_INFO "Closing %s.\n", dev->name);
 
@@ -1430,6 +1346,9 @@
 	free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
 	free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
 
+	cris_free_dma(NETWORK_TX_DMA_NBR, cardname);
+	cris_free_dma(NETWORK_RX_DMA_NBR, cardname);
+
 	/* Update the statistics here. */
 
 	update_rx_stats(&np->stats);
@@ -1447,18 +1366,11 @@
 {
 	struct mii_ioctl_data *data = if_mii(ifr);
 	struct net_local *np = netdev_priv(dev);
+	int rc = 0;
+        int old_autoneg;
 
 	spin_lock(&np->lock); /* Preempt protection */
 	switch (cmd) {
-		case SIOCGMIIPHY: /* Get PHY address */
-			data->phy_id = mdio_phy_addr;
-			break;
-		case SIOCGMIIREG: /* Read MII register */
-			data->val_out = e100_get_mdio_reg(dev, mdio_phy_addr, data->reg_num);
-			break;
-		case SIOCSMIIREG: /* Write MII register */
-			e100_set_mdio_reg(dev, mdio_phy_addr, data->reg_num, data->val_in);
-			break;
 		/* The ioctls below should be considered obsolete but are */
 		/* still present for compatability with old scripts/apps  */
 		case SET_ETH_SPEED_10:                  /* 10 Mbps */
@@ -1467,60 +1379,47 @@
 		case SET_ETH_SPEED_100:                /* 100 Mbps */
 			e100_set_speed(dev, 100);
 			break;
-		case SET_ETH_SPEED_AUTO:              /* Auto negotiate speed */
+		case SET_ETH_SPEED_AUTO:        /* Auto-negotiate speed */
 			e100_set_speed(dev, 0);
 			break;
-		case SET_ETH_DUPLEX_HALF:              /* Half duplex. */
+		case SET_ETH_DUPLEX_HALF:       /* Half duplex */
 			e100_set_duplex(dev, half);
 			break;
-		case SET_ETH_DUPLEX_FULL:              /* Full duplex. */
+		case SET_ETH_DUPLEX_FULL:       /* Full duplex */
 			e100_set_duplex(dev, full);
 			break;
-		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
+		case SET_ETH_DUPLEX_AUTO:       /* Auto-negotiate duplex */
 			e100_set_duplex(dev, autoneg);
 			break;
+	        case SET_ETH_AUTONEG:
+			old_autoneg = autoneg_normal;
+		        autoneg_normal = *(int*)data;
+			if (autoneg_normal != old_autoneg)
+				e100_negotiate(dev);
+			break;
 		default:
-			return -EINVAL;
+			rc = generic_mii_ioctl(&np->mii_if, if_mii(ifr),
+						cmd, NULL);
+			break;
 	}
 	spin_unlock(&np->lock);
-	return 0;
+	return rc;
 }
 
-static int e100_set_settings(struct net_device *dev,
-			     struct ethtool_cmd *ecmd)
+static int e100_get_settings(struct net_device *dev,
+			     struct ethtool_cmd *cmd)
 {
-	ecmd->supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
-			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
-			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
-	ecmd->port = PORT_TP;
-	ecmd->transceiver = XCVR_EXTERNAL;
-	ecmd->phy_address = mdio_phy_addr;
-	ecmd->speed = current_speed;
-	ecmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-	ecmd->advertising = ADVERTISED_TP;
-
-	if (current_duplex == autoneg && current_speed_selection == 0)
-		ecmd->advertising |= ADVERTISED_Autoneg;
-	else {
-		ecmd->advertising |=
-			ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
-			ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
-		if (current_speed_selection == 10)
-			ecmd->advertising &= ~(ADVERTISED_100baseT_Half |
-					       ADVERTISED_100baseT_Full);
-		else if (current_speed_selection == 100)
-			ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
-					       ADVERTISED_10baseT_Full);
-		if (current_duplex == half)
-			ecmd->advertising &= ~(ADVERTISED_10baseT_Full |
-					       ADVERTISED_100baseT_Full);
-		else if (current_duplex == full)
-			ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
-					       ADVERTISED_100baseT_Half);
-	}
+	struct net_local *np = netdev_priv(dev);
+	int err;
 
-	ecmd->autoneg = AUTONEG_ENABLE;
-	return 0;
+	spin_lock_irq(&np->lock);
+	err = mii_ethtool_gset(&np->mii_if, cmd);
+	spin_unlock_irq(&np->lock);
+
+	/* The PHY may support 1000baseT, but the Etrax100 does not.  */
+	cmd->supported &= ~(SUPPORTED_1000baseT_Half 
+			    | SUPPORTED_1000baseT_Full);
+	return err;
 }
 
 static int e100_set_settings(struct net_device *dev,
@@ -1564,7 +1463,8 @@
 static int
 e100_set_config(struct net_device *dev, struct ifmap *map)
 {
-	struct net_local *np = (struct net_local *)dev->priv;
+	struct net_local *np = netdev_priv(dev);
+
 	spin_lock(&np->lock); /* Preempt protection */
 
 	switch(map->port) {
@@ -1616,7 +1522,6 @@
 	es->collisions +=
 		IO_EXTRACT(R_TR_COUNTERS, single_col, r) +
 		IO_EXTRACT(R_TR_COUNTERS, multiple_col, r);
-	es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r);
 }
 
 /*
@@ -1626,8 +1531,9 @@
 static struct net_device_stats *
 e100_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	unsigned long flags;
+
 	spin_lock_irqsave(&lp->lock, flags);
 
 	update_rx_stats(&lp->stats);
@@ -1647,7 +1553,7 @@
 static void
 set_multicast_list(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = netdev_priv(dev);
 	int num_addr = dev->mc_count;
 	unsigned long int lo_bits;
 	unsigned long int hi_bits;
@@ -1651,9 +1557,9 @@
 	int num_addr = dev->mc_count;
 	unsigned long int lo_bits;
 	unsigned long int hi_bits;
+
 	spin_lock(&lp->lock);
-	if (dev->flags & IFF_PROMISC)
-	{
+	if (dev->flags & IFF_PROMISC) {
 		/* promiscuous mode */
 		lo_bits = 0xfffffffful;
 		hi_bits = 0xfffffffful;
@@ -1683,9 +1589,10 @@
 		struct dev_mc_list *dmi = dev->mc_list;
 		int i;
 		char *baddr;
+
 		lo_bits = 0x00000000ul;
 		hi_bits = 0x00000000ul;
-		for (i=0; i<num_addr; i++) {
+		for (i = 0; i < num_addr; i++) {
 			/* Calculate the hash index for the GA registers */
 
 			hash_ix = 0;
@@ -1712,8 +1619,7 @@
 
 			if (hash_ix >= 32) {
 				hi_bits |= (1 << (hash_ix-32));
-			}
-			else {
+			} else {
 				lo_bits |= (1 << hash_ix);
 			}
 			dmi = dmi->next;
@@ -1728,10 +1634,11 @@
 }
 
 void
-e100_hardware_send_packet(char *buf, int length)
+e100_hardware_send_packet(struct net_local *np, char *buf, int length)
 {
 	D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
 
+	spin_lock(&np->led_lock);
 	if (!led_active && time_after(jiffies, led_next_time)) {
 		/* light the network leds depending on the current speed. */
 		e100_set_network_leds(NETWORK_ACTIVITY);
@@ -1741,6 +1648,7 @@
 		led_active = 1;
 		mod_timer(&clear_led_timer, jiffies + HZ/10);
 	}
+	spin_unlock(&np->led_lock);
 
 	/* configure the tx dma descriptor */
 	myNextTxDesc->descr.sw_len = length;
@@ -1758,6 +1666,11 @@
 static void
 e100_clear_network_leds(unsigned long dummy)
 {
+	struct net_device *dev = (struct net_device *)dummy;
+	struct net_local *np = netdev_priv(dev);
+
+	spin_lock(&np->led_lock);
+
 	if (led_active && time_after(jiffies, led_next_time)) {
 		e100_set_network_leds(NO_NETWORK_ACTIVITY);
 
@@ -1765,6 +1678,8 @@
 		led_next_time = jiffies + NET_FLASH_PAUSE;
 		led_active = 0;
 	}
+
+	spin_unlock(&np->led_lock);
 }
 
 static void
@@ -1785,19 +1700,25 @@
 #else
 		LED_NETWORK_SET(LED_OFF);
 #endif
-	}
-	else if (light_leds) {
+	} else if (light_leds) {
 		if (current_speed == 10) {
 			LED_NETWORK_SET(LED_ORANGE);
 		} else {
 			LED_NETWORK_SET(LED_GREEN);
 		}
-	}
-	else {
+	} else {
 		LED_NETWORK_SET(LED_OFF);
 	}
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+e100_netpoll(struct net_device* netdev)
+{
+	e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
+}
+#endif
+
 static int
 etrax_init_module(void)
 {
diff -urBb -X /h/jespern/.exclude_files clean_linux-2.6.23/include/asm-cris/ethernet.h linux-2.6.23/include/asm-cris/ethernet.h
--- clean_linux-2.6.23/include/asm-cris/ethernet.h	2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23/include/asm-cris/ethernet.h	2007-10-23 10:47:08.000000000 +0200
@@ -15,4 +15,7 @@
 #define SET_ETH_DUPLEX_AUTO     SIOCDEVPRIVATE+3        /* Auto neg duplex */
 #define SET_ETH_DUPLEX_HALF     SIOCDEVPRIVATE+4        /* Full duplex */
 #define SET_ETH_DUPLEX_FULL     SIOCDEVPRIVATE+5        /* Half duplex */
+#define SET_ETH_ENABLE_LEDS     SIOCDEVPRIVATE+6        /* Enable net LEDs */
+#define SET_ETH_DISABLE_LEDS    SIOCDEVPRIVATE+7        /* Disable net LEDs */
+#define SET_ETH_AUTONEG         SIOCDEVPRIVATE+8
 #endif /* _CRIS_ETHERNET_H */

/^JN - Jesper Nilsson
--
               Jesper Nilsson -- jesper.nilsson@axis.com

             reply	other threads:[~2007-10-30  9:33 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-30  9:32 Jesper Nilsson [this message]
2007-10-30 15:32 ` [PATCH 9/16] CRIS architecture: Correct compile errors Roel Kluin
2007-11-02  9:47   ` Jesper Nilsson
2007-10-30 22:14 ` Andrew Morton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20071030093231.GL11960@axis.com \
    --to=jesper.nilsson@axis.com \
    --cc=akpm@linux-foundation.org \
    --cc=jgarzik@pobox.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mikael.starvik@axis.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.