[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>

authored by Don Fry and committed by Jeff Garzik df27f4a6 06c87850

+68 -27
+68 -27
drivers/net/pcnet32.c
··· 1062 1062 return 0; 1063 1063 } 1064 1064 1065 + /* 1066 + * lp->lock must be held. 1067 + */ 1068 + static 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 1102 #define PCNET32_REGS_PER_PHY 32 1066 1103 #define PCNET32_MAX_PHYS 32 1067 1104 static int pcnet32_get_regs_len(struct net_device *dev) ··· 1117 1080 struct pcnet32_private *lp = dev->priv; 1118 1081 struct pcnet32_access *a = &lp->a; 1119 1082 ulong ioaddr = dev->base_addr; 1120 - int ticks; 1121 1083 unsigned long flags; 1122 1084 1123 1085 spin_lock_irqsave(&lp->lock, flags); 1124 1086 1125 - csr0 = a->read_csr(ioaddr, 0); 1126 - if (!(csr0 & 0x0004)) { /* If not stopped */ 1127 - /* set SUSPEND (SPND) - CSR5 bit 0 */ 1128 - a->write_csr(ioaddr, 5, 0x0001); 1129 - 1130 - /* poll waiting for bit to be set */ 1131 - ticks = 0; 1132 - while (!(a->read_csr(ioaddr, 5) & 0x0001)) { 1133 - spin_unlock_irqrestore(&lp->lock, flags); 1134 - mdelay(1); 1135 - spin_lock_irqsave(&lp->lock, flags); 1136 - ticks++; 1137 - if (ticks > 200) { 1138 - if (netif_msg_hw(lp)) 1139 - printk(KERN_DEBUG 1140 - "%s: Error getting into suspend!\n", 1141 - dev->name); 1142 - break; 1143 - } 1144 - } 1145 - } 1087 + csr0 = a->read_csr(ioaddr, CSR0); 1088 + if (!(csr0 & CSR0_STOP)) /* If not stopped */ 1089 + pcnet32_suspend(dev, &flags, 1); 1146 1090 1147 1091 /* read address PROM */ 1148 1092 for (i = 0; i < 16; i += 2) ··· 1160 1142 } 1161 1143 } 1162 1144 1163 - if (!(csr0 & 0x0004)) { /* If not stopped */ 1145 + if (!(csr0 & CSR0_STOP)) { /* If not stopped */ 1146 + int csr5; 1147 + 1164 1148 /* clear SUSPEND (SPND) - CSR5 bit 0 */ 1165 - a->write_csr(ioaddr, 5, 0x0000); 1149 + csr5 = a->read_csr(ioaddr, CSR5); 1150 + a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND)); 1166 1151 } 1167 1152 1168 1153 spin_unlock_irqrestore(&lp->lock, flags); ··· 2673 2652 volatile struct pcnet32_init_block *ib = &lp->init_block; 2674 2653 volatile u16 *mcast_table = (u16 *) & ib->filter; 2675 2654 struct dev_mc_list *dmi = dev->mc_list; 2655 + unsigned long ioaddr = dev->base_addr; 2676 2656 char *addrs; 2677 2657 int i; 2678 2658 u32 crc; ··· 2682 2660 if (dev->flags & IFF_ALLMULTI) { 2683 2661 ib->filter[0] = 0xffffffff; 2684 2662 ib->filter[1] = 0xffffffff; 2663 + lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff); 2664 + lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff); 2665 + lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff); 2666 + lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff); 2685 2667 return; 2686 2668 } 2687 2669 /* clear the multicast filter */ ··· 2707 2681 le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) | 2708 2682 (1 << (crc & 0xf))); 2709 2683 } 2684 + for (i = 0; i < 4; i++) 2685 + lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i, 2686 + le16_to_cpu(mcast_table[i])); 2710 2687 return; 2711 2688 } 2712 2689 ··· 2720 2691 { 2721 2692 unsigned long ioaddr = dev->base_addr, flags; 2722 2693 struct pcnet32_private *lp = dev->priv; 2694 + int csr15, suspended; 2723 2695 2724 2696 spin_lock_irqsave(&lp->lock, flags); 2697 + suspended = pcnet32_suspend(dev, &flags, 0); 2698 + csr15 = lp->a.read_csr(ioaddr, CSR15); 2725 2699 if (dev->flags & IFF_PROMISC) { 2726 2700 /* Log any net taps. */ 2727 2701 if (netif_msg_hw(lp)) ··· 2733 2701 lp->init_block.mode = 2734 2702 le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 2735 2703 7); 2704 + lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000); 2736 2705 } else { 2737 2706 lp->init_block.mode = 2738 2707 le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); 2708 + lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff); 2739 2709 pcnet32_load_multicast(dev); 2740 2710 } 2741 2711 2742 - lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */ 2743 - pcnet32_restart(dev, 0x0042); /* Resume normal operation */ 2744 - netif_wake_queue(dev); 2712 + if (suspended) { 2713 + int csr5; 2714 + /* clear SUSPEND (SPND) - CSR5 bit 0 */ 2715 + csr5 = lp->a.read_csr(ioaddr, CSR5); 2716 + lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND)); 2717 + } else { 2718 + lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); 2719 + pcnet32_restart(dev, CSR0_NORMAL); 2720 + netif_wake_queue(dev); 2721 + } 2745 2722 2746 2723 spin_unlock_irqrestore(&lp->lock, flags); 2747 2724 }