From b1dd9ca177bd2ff5260376dd024dd43eb4631dc7 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Thu, 1 Sep 2005 09:59:23 -0700 Subject: [PATCH] mv643xx: fix skb memory leak This patch fixes an skb memory leak under heavy receive load (whenever the more packets have been received than the NAPI budget allows to be processed). Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index fb6b232069d6..ab74d4583c41 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -412,15 +412,13 @@ static int mv643xx_eth_receive_queue(struct net_device *dev) struct pkt_info pkt_info; #ifdef MV643XX_NAPI - while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) { + while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) { #else while (eth_port_receive(mp, &pkt_info) == ETH_OK) { #endif mp->rx_ring_skbs--; received_packets++; -#ifdef MV643XX_NAPI - budget--; -#endif + /* Update statistics. Note byte count includes 4 byte CRC count */ stats->rx_packets++; stats->rx_bytes += pkt_info.byte_cnt; -- cgit v1.2.1 From b111ceb68ac4c44d1a6fa697c55f267fa09b1058 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 2 Sep 2005 10:25:24 -0700 Subject: [PATCH] mv643xx: fix outstanding tx skb counter This patch corrects the accounting of outstanding tx skbs. It fixes a bug that causes "Error on Queue Full" messages seen since scatter-gather was enabled by using the hardware tcp/udp checksum generator. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index ab74d4583c41..8ea004714648 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -369,15 +369,6 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev, dev_kfree_skb_irq(pkt_info.return_info); released = 0; - - /* - * Decrement the number of outstanding skbs counter on - * the TX queue. - */ - if (mp->tx_ring_skbs == 0) - panic("ERROR - TX outstanding SKBs" - " counter is corrupted"); - mp->tx_ring_skbs--; } else dma_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt, DMA_TO_DEVICE); @@ -1042,9 +1033,6 @@ static void mv643xx_tx(struct net_device *dev) DMA_TO_DEVICE); dev_kfree_skb_irq(pkt_info.return_info); - - if (mp->tx_ring_skbs) - mp->tx_ring_skbs--; } else dma_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt, DMA_TO_DEVICE); @@ -1187,7 +1175,6 @@ linear: pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); pkt_info.return_info = skb; - mp->tx_ring_skbs++; status = eth_port_send(mp, &pkt_info); if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) printk(KERN_ERR "%s: Error on transmitting packet\n", @@ -1272,7 +1259,6 @@ linear: pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT | ETH_TX_LAST_DESC; pkt_info.return_info = skb; - mp->tx_ring_skbs++; } else { pkt_info.return_info = 0; } @@ -1309,7 +1295,6 @@ linear: pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); pkt_info.return_info = skb; - mp->tx_ring_skbs++; status = eth_port_send(mp, &pkt_info); if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) printk(KERN_ERR "%s: Error on transmitting packet\n", @@ -2526,6 +2511,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, return ETH_ERROR; } + mp->tx_ring_skbs++; + BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size); + /* Get the Tx Desc ring indexes */ tx_desc_curr = mp->tx_curr_desc_q; tx_desc_used = mp->tx_used_desc_q; @@ -2592,6 +2580,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, if (mp->tx_resource_err) return ETH_QUEUE_FULL; + mp->tx_ring_skbs++; + BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size); + /* Get the Tx Desc ring indexes */ tx_desc_curr = mp->tx_curr_desc_q; tx_desc_used = mp->tx_used_desc_q; @@ -2692,6 +2683,9 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, /* Any Tx return cancels the Tx resource error status */ mp->tx_resource_err = 0; + BUG_ON(mp->tx_ring_skbs == 0); + mp->tx_ring_skbs--; + return ETH_OK; } -- cgit v1.2.1 From 8f543718ea1c20795853bf065f1dcb510f210465 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 2 Sep 2005 12:34:35 -0700 Subject: [PATCH] mv643xx: Disable per port bandwidth limits The mv643xx chips support per port bandwith limits. This patch disables the bandwidth limits by clearing the MTU register. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 8ea004714648..25a094c44f39 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1866,6 +1866,9 @@ static void eth_port_start(struct mv643xx_private *mp) /* Enable port Rx. */ mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), mp->port_rx_queue_command); + + /* Disable port bandwidth limits by clearing MTU register */ + mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0); } /* -- cgit v1.2.1 From 7342cd810cfd73120687d5323846e5c114cb23bb Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 2 Sep 2005 12:36:48 -0700 Subject: [PATCH] mv643xx: Fix promiscuous mode handling mv643xx_eth_get_config_reg() was reading the wrong register. mv643xx_eth_set_config_reg() was or'ing instead of setting the register. These functions are trivial and both are called only from mv643xx_eth_set_rx_mode() when changing to/from promiscuous mode. Remove both functions and do the operations directly in mv643xx_eth_set_rx_mode(). Also, maintain promiscuous mode setting across port resets. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 62 +++-------------------------------------------- 1 file changed, 4 insertions(+), 58 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 25a094c44f39..bb230e6c197b 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -259,14 +259,13 @@ static void mv643xx_eth_update_mac_address(struct net_device *dev) static void mv643xx_eth_set_rx_mode(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); - u32 config_reg; - config_reg = ethernet_get_config_reg(mp->port_num); if (dev->flags & IFF_PROMISC) - config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; + mp->port_config |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; else - config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; - ethernet_set_config_reg(mp->port_num, config_reg); + mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; + + mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config); } /* @@ -2278,34 +2277,6 @@ static void eth_port_reset(unsigned int port_num) mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data); } -/* - * ethernet_set_config_reg - Set specified bits in configuration register. - * - * DESCRIPTION: - * This function sets specified bits in the given ethernet - * configuration register. - * - * INPUT: - * unsigned int eth_port_num Ethernet Port number. - * unsigned int value 32 bit value. - * - * OUTPUT: - * The set bits in the value parameter are set in the configuration - * register. - * - * RETURN: - * None. - * - */ -static void ethernet_set_config_reg(unsigned int eth_port_num, - unsigned int value) -{ - unsigned int eth_config_reg; - - eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num)); - eth_config_reg |= value; - mv_write(MV643XX_ETH_PORT_CONFIG_REG(eth_port_num), eth_config_reg); -} static int eth_port_autoneg_supported(unsigned int eth_port_num) { @@ -2331,31 +2302,6 @@ static int eth_port_link_is_up(unsigned int eth_port_num) return 0; } -/* - * ethernet_get_config_reg - Get the port configuration register - * - * DESCRIPTION: - * This function returns the configuration register value of the given - * ethernet port. - * - * INPUT: - * unsigned int eth_port_num Ethernet Port number. - * - * OUTPUT: - * None. - * - * RETURN: - * Port configuration register value. - */ -static unsigned int ethernet_get_config_reg(unsigned int eth_port_num) -{ - unsigned int eth_config_reg; - - eth_config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_EXTEND_REG - (eth_port_num)); - return eth_config_reg; -} - /* * eth_port_read_smi_reg - Read PHY registers * -- cgit v1.2.1 From 63c9e549148fb95c11befb4f255c84ded9277f89 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 2 Sep 2005 13:49:10 -0700 Subject: [PATCH] mv643xx: add netpoll api support Add support for the netpoll api for use by netconsole, kgdb, etc. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index bb230e6c197b..7c9dbc8c9423 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -58,11 +58,10 @@ #define INT_CAUSE_UNMASK_ALL 0x0007ffff #define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff -#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK #define INT_CAUSE_MASK_ALL 0x00000000 +#define INT_CAUSE_MASK_ALL_EXT 0x00000000 #define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL #define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT -#endif #ifdef MV643XX_CHECKSUM_OFFLOAD_TX #define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1) @@ -1338,6 +1337,43 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) return &mp->stats; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static inline void mv643xx_enable_irq(struct mv643xx_private *mp) +{ + int port_num = mp->port_num; + unsigned long flags; + + spin_lock_irqsave(&mp->lock, flags); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + spin_unlock_irqrestore(&mp->lock, flags); +} + +static inline void mv643xx_disable_irq(struct mv643xx_private *mp) +{ + int port_num = mp->port_num; + unsigned long flags; + + spin_lock_irqsave(&mp->lock, flags); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_MASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_MASK_ALL_EXT); + spin_unlock_irqrestore(&mp->lock, flags); +} + +static void mv643xx_netpoll(struct net_device *netdev) +{ + struct mv643xx_private *mp = netdev_priv(netdev); + + mv643xx_disable_irq(mp); + mv643xx_eth_int_handler(netdev->irq, netdev, NULL); + mv643xx_enable_irq(mp); +} +#endif + /*/ * mv643xx_eth_probe * @@ -1388,6 +1424,10 @@ static int mv643xx_eth_probe(struct device *ddev) dev->weight = 64; #endif +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = mv643xx_netpoll; +#endif + dev->watchdog_timeo = 2 * HZ; dev->tx_queue_len = mp->tx_ring_size; dev->base_addr = 0; -- cgit v1.2.1 From a9f6a0dd54efea2a5d57a27e6c232f9197c25154 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 9 Sep 2005 13:10:41 -0700 Subject: [PATCH] more SPIN_LOCK_UNLOCKED -> DEFINE_SPINLOCK conversions This converts the final 20 DEFINE_SPINLOCK holdouts. (another 580 places are already using DEFINE_SPINLOCK). Build tested on x86. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7c9dbc8c9423..25c9a99c377b 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -94,7 +94,7 @@ static char mv643xx_driver_version[] = "1.0"; static void __iomem *mv643xx_eth_shared_base; /* used to protect MV643XX_ETH_SMI_REG, which is shared across ports */ -static spinlock_t mv643xx_eth_phy_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(mv643xx_eth_phy_lock); static inline u32 mv_read(int offset) { -- cgit v1.2.1