aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDon Fry <brazilnut@us.ibm.com>2006-06-29 16:55:02 -0400
committerJeff Garzik <jeff@garzik.org>2006-07-05 14:07:15 -0400
commitdf27f4a610e22e8c8c740286368cc13e0600f22c (patch)
tree399422c705273fd6e3f736aec399399de62aea68
parent06c878500893c315795fcf944ecbd85c3d023040 (diff)
[PATCH] pcnet32: Suspend the chip rather than restart when changing multicast/promisc
Suspend the chip if possible rather than stop and discard all tx and rx frames, when changing the mcast list or entering/leaving promiscuous mode. Created common pcnet32_suspend routine. Tested ia32 and ppc64 Signed-off-by: Don Fry <brazilnut@us.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/net/pcnet32.c95
1 files changed, 68 insertions, 27 deletions
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index e79c3b6bee13..fe0558242835 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1062,6 +1062,43 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
1062 return 0; 1062 return 0;
1063} 1063}
1064 1064
1065/*
1066 * lp->lock must be held.
1067 */
1068static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
1069 int can_sleep)
1070{
1071 int csr5;
1072 struct pcnet32_private *lp = dev->priv;
1073 struct pcnet32_access *a = &lp->a;
1074 ulong ioaddr = dev->base_addr;
1075 int ticks;
1076
1077 /* set SUSPEND (SPND) - CSR5 bit 0 */
1078 csr5 = a->read_csr(ioaddr, CSR5);
1079 a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
1080
1081 /* poll waiting for bit to be set */
1082 ticks = 0;
1083 while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
1084 spin_unlock_irqrestore(&lp->lock, *flags);
1085 if (can_sleep)
1086 msleep(1);
1087 else
1088 mdelay(1);
1089 spin_lock_irqsave(&lp->lock, *flags);
1090 ticks++;
1091 if (ticks > 200) {
1092 if (netif_msg_hw(lp))
1093 printk(KERN_DEBUG
1094 "%s: Error getting into suspend!\n",
1095 dev->name);
1096 return 0;
1097 }
1098 }
1099 return 1;
1100}
1101
1065#define PCNET32_REGS_PER_PHY 32 1102#define PCNET32_REGS_PER_PHY 32
1066#define PCNET32_MAX_PHYS 32 1103#define PCNET32_MAX_PHYS 32
1067static int pcnet32_get_regs_len(struct net_device *dev) 1104static int pcnet32_get_regs_len(struct net_device *dev)
@@ -1080,32 +1117,13 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1080 struct pcnet32_private *lp = dev->priv; 1117 struct pcnet32_private *lp = dev->priv;
1081 struct pcnet32_access *a = &lp->a; 1118 struct pcnet32_access *a = &lp->a;
1082 ulong ioaddr = dev->base_addr; 1119 ulong ioaddr = dev->base_addr;
1083 int ticks;
1084 unsigned long flags; 1120 unsigned long flags;
1085 1121
1086 spin_lock_irqsave(&lp->lock, flags); 1122 spin_lock_irqsave(&lp->lock, flags);
1087 1123
1088 csr0 = a->read_csr(ioaddr, 0); 1124 csr0 = a->read_csr(ioaddr, CSR0);
1089 if (!(csr0 & 0x0004)) { /* If not stopped */ 1125 if (!(csr0 & CSR0_STOP)) /* If not stopped */
1090 /* set SUSPEND (SPND) - CSR5 bit 0 */ 1126 pcnet32_suspend(dev, &flags, 1);
1091 a->write_csr(ioaddr, 5, 0x0001);
1092
1093 /* poll waiting for bit to be set */
1094 ticks = 0;
1095 while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
1096 spin_unlock_irqrestore(&lp->lock, flags);
1097 mdelay(1);
1098 spin_lock_irqsave(&lp->lock, flags);
1099 ticks++;
1100 if (ticks > 200) {
1101 if (netif_msg_hw(lp))
1102 printk(KERN_DEBUG
1103 "%s: Error getting into suspend!\n",
1104 dev->name);
1105 break;
1106 }
1107 }
1108 }
1109 1127
1110 /* read address PROM */ 1128 /* read address PROM */
1111 for (i = 0; i < 16; i += 2) 1129 for (i = 0; i < 16; i += 2)
@@ -1142,9 +1160,12 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1142 } 1160 }
1143 } 1161 }
1144 1162
1145 if (!(csr0 & 0x0004)) { /* If not stopped */ 1163 if (!(csr0 & CSR0_STOP)) { /* If not stopped */
1164 int csr5;
1165
1146 /* clear SUSPEND (SPND) - CSR5 bit 0 */ 1166 /* clear SUSPEND (SPND) - CSR5 bit 0 */
1147 a->write_csr(ioaddr, 5, 0x0000); 1167 csr5 = a->read_csr(ioaddr, CSR5);
1168 a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
1148 } 1169 }
1149 1170
1150 spin_unlock_irqrestore(&lp->lock, flags); 1171 spin_unlock_irqrestore(&lp->lock, flags);
@@ -2652,6 +2673,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
2652 volatile struct pcnet32_init_block *ib = &lp->init_block; 2673 volatile struct pcnet32_init_block *ib = &lp->init_block;
2653 volatile u16 *mcast_table = (u16 *) & ib->filter; 2674 volatile u16 *mcast_table = (u16 *) & ib->filter;
2654 struct dev_mc_list *dmi = dev->mc_list; 2675 struct dev_mc_list *dmi = dev->mc_list;
2676 unsigned long ioaddr = dev->base_addr;
2655 char *addrs; 2677 char *addrs;
2656 int i; 2678 int i;
2657 u32 crc; 2679 u32 crc;
@@ -2660,6 +2682,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
2660 if (dev->flags & IFF_ALLMULTI) { 2682 if (dev->flags & IFF_ALLMULTI) {
2661 ib->filter[0] = 0xffffffff; 2683 ib->filter[0] = 0xffffffff;
2662 ib->filter[1] = 0xffffffff; 2684 ib->filter[1] = 0xffffffff;
2685 lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
2686 lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
2687 lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
2688 lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
2663 return; 2689 return;
2664 } 2690 }
2665 /* clear the multicast filter */ 2691 /* clear the multicast filter */
@@ -2681,6 +2707,9 @@ static void pcnet32_load_multicast(struct net_device *dev)
2681 le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) | 2707 le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
2682 (1 << (crc & 0xf))); 2708 (1 << (crc & 0xf)));
2683 } 2709 }
2710 for (i = 0; i < 4; i++)
2711 lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
2712 le16_to_cpu(mcast_table[i]));
2684 return; 2713 return;
2685} 2714}
2686 2715
@@ -2691,8 +2720,11 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
2691{ 2720{
2692 unsigned long ioaddr = dev->base_addr, flags; 2721 unsigned long ioaddr = dev->base_addr, flags;
2693 struct pcnet32_private *lp = dev->priv; 2722 struct pcnet32_private *lp = dev->priv;
2723 int csr15, suspended;
2694 2724
2695 spin_lock_irqsave(&lp->lock, flags); 2725 spin_lock_irqsave(&lp->lock, flags);
2726 suspended = pcnet32_suspend(dev, &flags, 0);
2727 csr15 = lp->a.read_csr(ioaddr, CSR15);
2696 if (dev->flags & IFF_PROMISC) { 2728 if (dev->flags & IFF_PROMISC) {
2697 /* Log any net taps. */ 2729 /* Log any net taps. */
2698 if (netif_msg_hw(lp)) 2730 if (netif_msg_hw(lp))
@@ -2701,15 +2733,24 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
2701 lp->init_block.mode = 2733 lp->init_block.mode =
2702 le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 2734 le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
2703 7); 2735 7);
2736 lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
2704 } else { 2737 } else {
2705 lp->init_block.mode = 2738 lp->init_block.mode =
2706 le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); 2739 le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
2740 lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
2707 pcnet32_load_multicast(dev); 2741 pcnet32_load_multicast(dev);
2708 } 2742 }
2709 2743
2710 lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */ 2744 if (suspended) {
2711 pcnet32_restart(dev, 0x0042); /* Resume normal operation */ 2745 int csr5;
2712 netif_wake_queue(dev); 2746 /* clear SUSPEND (SPND) - CSR5 bit 0 */
2747 csr5 = lp->a.read_csr(ioaddr, CSR5);
2748 lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
2749 } else {
2750 lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
2751 pcnet32_restart(dev, CSR0_NORMAL);
2752 netif_wake_queue(dev);
2753 }
2713 2754
2714 spin_unlock_irqrestore(&lp->lock, flags); 2755 spin_unlock_irqrestore(&lp->lock, flags);
2715} 2756}