aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/arm/am79c961a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/arm/am79c961a.c')
-rw-r--r--drivers/net/arm/am79c961a.c126
1 files changed, 65 insertions, 61 deletions
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 0c9217f48b72..7b3e23f38913 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -50,7 +50,7 @@ static const char version[] =
50#ifdef __arm__ 50#ifdef __arm__
51static void write_rreg(u_long base, u_int reg, u_int val) 51static void write_rreg(u_long base, u_int reg, u_int val)
52{ 52{
53 __asm__( 53 asm volatile(
54 "str%?h %1, [%2] @ NET_RAP\n\t" 54 "str%?h %1, [%2] @ NET_RAP\n\t"
55 "str%?h %0, [%2, #-4] @ NET_RDP" 55 "str%?h %0, [%2, #-4] @ NET_RDP"
56 : 56 :
@@ -60,7 +60,7 @@ static void write_rreg(u_long base, u_int reg, u_int val)
60static inline unsigned short read_rreg(u_long base_addr, u_int reg) 60static inline unsigned short read_rreg(u_long base_addr, u_int reg)
61{ 61{
62 unsigned short v; 62 unsigned short v;
63 __asm__( 63 asm volatile(
64 "str%?h %1, [%2] @ NET_RAP\n\t" 64 "str%?h %1, [%2] @ NET_RAP\n\t"
65 "ldr%?h %0, [%2, #-4] @ NET_RDP" 65 "ldr%?h %0, [%2, #-4] @ NET_RDP"
66 : "=r" (v) 66 : "=r" (v)
@@ -70,7 +70,7 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)
70 70
71static inline void write_ireg(u_long base, u_int reg, u_int val) 71static inline void write_ireg(u_long base, u_int reg, u_int val)
72{ 72{
73 __asm__( 73 asm volatile(
74 "str%?h %1, [%2] @ NET_RAP\n\t" 74 "str%?h %1, [%2] @ NET_RAP\n\t"
75 "str%?h %0, [%2, #8] @ NET_IDP" 75 "str%?h %0, [%2, #8] @ NET_IDP"
76 : 76 :
@@ -80,7 +80,7 @@ static inline void write_ireg(u_long base, u_int reg, u_int val)
80static inline unsigned short read_ireg(u_long base_addr, u_int reg) 80static inline unsigned short read_ireg(u_long base_addr, u_int reg)
81{ 81{
82 u_short v; 82 u_short v;
83 __asm__( 83 asm volatile(
84 "str%?h %1, [%2] @ NAT_RAP\n\t" 84 "str%?h %1, [%2] @ NAT_RAP\n\t"
85 "ldr%?h %0, [%2, #8] @ NET_IDP\n\t" 85 "ldr%?h %0, [%2, #8] @ NET_IDP\n\t"
86 : "=r" (v) 86 : "=r" (v)
@@ -91,47 +91,48 @@ static inline unsigned short read_ireg(u_long base_addr, u_int reg)
91#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1)) 91#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
92#define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1)) 92#define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1))
93 93
94static inline void 94static void
95am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) 95am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
96{ 96{
97 offset = ISAMEM_BASE + (offset << 1); 97 offset = ISAMEM_BASE + (offset << 1);
98 length = (length + 1) & ~1; 98 length = (length + 1) & ~1;
99 if ((int)buf & 2) { 99 if ((int)buf & 2) {
100 __asm__ __volatile__("str%?h %2, [%0], #4" 100 asm volatile("str%?h %2, [%0], #4"
101 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); 101 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
102 buf += 2; 102 buf += 2;
103 length -= 2; 103 length -= 2;
104 } 104 }
105 while (length > 8) { 105 while (length > 8) {
106 unsigned int tmp, tmp2; 106 register unsigned int tmp asm("r2"), tmp2 asm("r3");
107 __asm__ __volatile__( 107 asm volatile(
108 "ldm%?ia %1!, {%2, %3}\n\t" 108 "ldm%?ia %0!, {%1, %2}"
109 : "+r" (buf), "=&r" (tmp), "=&r" (tmp2));
110 length -= 8;
111 asm volatile(
112 "str%?h %1, [%0], #4\n\t"
113 "mov%? %1, %1, lsr #16\n\t"
114 "str%?h %1, [%0], #4\n\t"
109 "str%?h %2, [%0], #4\n\t" 115 "str%?h %2, [%0], #4\n\t"
110 "mov%? %2, %2, lsr #16\n\t" 116 "mov%? %2, %2, lsr #16\n\t"
111 "str%?h %2, [%0], #4\n\t" 117 "str%?h %2, [%0], #4"
112 "str%?h %3, [%0], #4\n\t" 118 : "+r" (offset), "=&r" (tmp), "=&r" (tmp2));
113 "mov%? %3, %3, lsr #16\n\t"
114 "str%?h %3, [%0], #4"
115 : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
116 : "0" (offset), "1" (buf));
117 length -= 8;
118 } 119 }
119 while (length > 0) { 120 while (length > 0) {
120 __asm__ __volatile__("str%?h %2, [%0], #4" 121 asm volatile("str%?h %2, [%0], #4"
121 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); 122 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
122 buf += 2; 123 buf += 2;
123 length -= 2; 124 length -= 2;
124 } 125 }
125} 126}
126 127
127static inline void 128static void
128am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) 129am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
129{ 130{
130 offset = ISAMEM_BASE + (offset << 1); 131 offset = ISAMEM_BASE + (offset << 1);
131 length = (length + 1) & ~1; 132 length = (length + 1) & ~1;
132 if ((int)buf & 2) { 133 if ((int)buf & 2) {
133 unsigned int tmp; 134 unsigned int tmp;
134 __asm__ __volatile__( 135 asm volatile(
135 "ldr%?h %2, [%0], #4\n\t" 136 "ldr%?h %2, [%0], #4\n\t"
136 "str%?b %2, [%1], #1\n\t" 137 "str%?b %2, [%1], #1\n\t"
137 "mov%? %2, %2, lsr #8\n\t" 138 "mov%? %2, %2, lsr #8\n\t"
@@ -140,12 +141,12 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
140 length -= 2; 141 length -= 2;
141 } 142 }
142 while (length > 8) { 143 while (length > 8) {
143 unsigned int tmp, tmp2, tmp3; 144 register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3;
144 __asm__ __volatile__( 145 asm volatile(
145 "ldr%?h %2, [%0], #4\n\t" 146 "ldr%?h %2, [%0], #4\n\t"
147 "ldr%?h %4, [%0], #4\n\t"
146 "ldr%?h %3, [%0], #4\n\t" 148 "ldr%?h %3, [%0], #4\n\t"
147 "orr%? %2, %2, %3, lsl #16\n\t" 149 "orr%? %2, %2, %4, lsl #16\n\t"
148 "ldr%?h %3, [%0], #4\n\t"
149 "ldr%?h %4, [%0], #4\n\t" 150 "ldr%?h %4, [%0], #4\n\t"
150 "orr%? %3, %3, %4, lsl #16\n\t" 151 "orr%? %3, %3, %4, lsl #16\n\t"
151 "stm%?ia %1!, {%2, %3}" 152 "stm%?ia %1!, {%2, %3}"
@@ -155,7 +156,7 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
155 } 156 }
156 while (length > 0) { 157 while (length > 0) {
157 unsigned int tmp; 158 unsigned int tmp;
158 __asm__ __volatile__( 159 asm volatile(
159 "ldr%?h %2, [%0], #4\n\t" 160 "ldr%?h %2, [%0], #4\n\t"
160 "str%?b %2, [%1], #1\n\t" 161 "str%?b %2, [%1], #1\n\t"
161 "mov%? %2, %2, lsr #8\n\t" 162 "mov%? %2, %2, lsr #8\n\t"
@@ -196,6 +197,42 @@ am79c961_ramtest(struct net_device *dev, unsigned int val)
196 return errorcount; 197 return errorcount;
197} 198}
198 199
200static void am79c961_mc_hash(char *addr, u16 *hash)
201{
202 if (addr[0] & 0x01) {
203 int idx, bit;
204 u32 crc;
205
206 crc = ether_crc_le(ETH_ALEN, addr);
207
208 idx = crc >> 30;
209 bit = (crc >> 26) & 15;
210
211 hash[idx] |= 1 << bit;
212 }
213}
214
215static unsigned int am79c961_get_rx_mode(struct net_device *dev, u16 *hash)
216{
217 unsigned int mode = MODE_PORT_10BT;
218
219 if (dev->flags & IFF_PROMISC) {
220 mode |= MODE_PROMISC;
221 memset(hash, 0xff, 4 * sizeof(*hash));
222 } else if (dev->flags & IFF_ALLMULTI) {
223 memset(hash, 0xff, 4 * sizeof(*hash));
224 } else {
225 struct netdev_hw_addr *ha;
226
227 memset(hash, 0, 4 * sizeof(*hash));
228
229 netdev_for_each_mc_addr(ha, dev)
230 am79c961_mc_hash(ha->addr, hash);
231 }
232
233 return mode;
234}
235
199static void 236static void
200am79c961_init_for_open(struct net_device *dev) 237am79c961_init_for_open(struct net_device *dev)
201{ 238{
@@ -203,6 +240,7 @@ am79c961_init_for_open(struct net_device *dev)
203 unsigned long flags; 240 unsigned long flags;
204 unsigned char *p; 241 unsigned char *p;
205 u_int hdr_addr, first_free_addr; 242 u_int hdr_addr, first_free_addr;
243 u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
206 int i; 244 int i;
207 245
208 /* 246 /*
@@ -218,16 +256,12 @@ am79c961_init_for_open(struct net_device *dev)
218 write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */ 256 write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
219 257
220 for (i = LADRL; i <= LADRH; i++) 258 for (i = LADRL; i <= LADRH; i++)
221 write_rreg (dev->base_addr, i, 0); 259 write_rreg (dev->base_addr, i, multi_hash[i - LADRL]);
222 260
223 for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) 261 for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
224 write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); 262 write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
225 263
226 i = MODE_PORT_10BT; 264 write_rreg (dev->base_addr, MODE, mode);
227 if (dev->flags & IFF_PROMISC)
228 i |= MODE_PROMISC;
229
230 write_rreg (dev->base_addr, MODE, i);
231 write_rreg (dev->base_addr, POLLINT, 0); 265 write_rreg (dev->base_addr, POLLINT, 0);
232 write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); 266 write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
233 write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); 267 write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
@@ -340,21 +374,6 @@ am79c961_close(struct net_device *dev)
340 return 0; 374 return 0;
341} 375}
342 376
343static void am79c961_mc_hash(char *addr, unsigned short *hash)
344{
345 if (addr[0] & 0x01) {
346 int idx, bit;
347 u32 crc;
348
349 crc = ether_crc_le(ETH_ALEN, addr);
350
351 idx = crc >> 30;
352 bit = (crc >> 26) & 15;
353
354 hash[idx] |= 1 << bit;
355 }
356}
357
358/* 377/*
359 * Set or clear promiscuous/multicast mode filter for this adapter. 378 * Set or clear promiscuous/multicast mode filter for this adapter.
360 */ 379 */
@@ -362,24 +381,9 @@ static void am79c961_setmulticastlist (struct net_device *dev)
362{ 381{
363 struct dev_priv *priv = netdev_priv(dev); 382 struct dev_priv *priv = netdev_priv(dev);
364 unsigned long flags; 383 unsigned long flags;
365 unsigned short multi_hash[4], mode; 384 u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash);
366 int i, stopped; 385 int i, stopped;
367 386
368 mode = MODE_PORT_10BT;
369
370 if (dev->flags & IFF_PROMISC) {
371 mode |= MODE_PROMISC;
372 } else if (dev->flags & IFF_ALLMULTI) {
373 memset(multi_hash, 0xff, sizeof(multi_hash));
374 } else {
375 struct netdev_hw_addr *ha;
376
377 memset(multi_hash, 0x00, sizeof(multi_hash));
378
379 netdev_for_each_mc_addr(ha, dev)
380 am79c961_mc_hash(ha->addr, multi_hash);
381 }
382
383 spin_lock_irqsave(&priv->chip_lock, flags); 387 spin_lock_irqsave(&priv->chip_lock, flags);
384 388
385 stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; 389 stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;