diff options
Diffstat (limited to 'drivers/net/pcnet32.c')
| -rw-r--r-- | drivers/net/pcnet32.c | 95 |
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 | */ | ||
| 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 | #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 |
| 1067 | static int pcnet32_get_regs_len(struct net_device *dev) | 1104 | static 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 | } |
