1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/drivers/acorn/net/etherh.c |
4 | * |
5 | * Copyright (C) 2000-2002 Russell King |
6 | * |
7 | * NS8390 I-cubed EtherH and ANT EtherM specific driver |
8 | * Thanks to I-Cubed for information on their cards. |
9 | * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton |
10 | * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan) |
11 | * EtherM integration re-engineered by Russell King. |
12 | * |
13 | * Changelog: |
14 | * 08-12-1996 RMK 1.00 Created |
15 | * RMK 1.03 Added support for EtherLan500 cards |
16 | * 23-11-1997 RMK 1.04 Added media autodetection |
17 | * 16-04-1998 RMK 1.05 Improved media autodetection |
18 | * 10-02-2000 RMK 1.06 Updated for 2.3.43 |
19 | * 13-05-2000 RMK 1.07 Updated for 2.3.99-pre8 |
20 | * 12-10-1999 CK/TEW EtherM driver first release |
21 | * 21-12-2000 TTC EtherH/EtherM integration |
22 | * 25-12-2000 RMK 1.08 Clean integration of EtherM into this driver. |
23 | * 03-01-2002 RMK 1.09 Always enable IRQs if we're in the nic slot. |
24 | */ |
25 | |
26 | #include <linux/module.h> |
27 | #include <linux/kernel.h> |
28 | #include <linux/types.h> |
29 | #include <linux/fcntl.h> |
30 | #include <linux/interrupt.h> |
31 | #include <linux/ioport.h> |
32 | #include <linux/in.h> |
33 | #include <linux/string.h> |
34 | #include <linux/errno.h> |
35 | #include <linux/netdevice.h> |
36 | #include <linux/etherdevice.h> |
37 | #include <linux/ethtool.h> |
38 | #include <linux/skbuff.h> |
39 | #include <linux/delay.h> |
40 | #include <linux/device.h> |
41 | #include <linux/init.h> |
42 | #include <linux/bitops.h> |
43 | #include <linux/jiffies.h> |
44 | |
45 | #include <asm/ecard.h> |
46 | #include <asm/io.h> |
47 | #include <asm/system_info.h> |
48 | |
49 | #define EI_SHIFT(x) (ei_local->reg_offset[x]) |
50 | |
51 | #define ei_inb(_p) readb((void __iomem *)_p) |
52 | #define ei_outb(_v,_p) writeb(_v,(void __iomem *)_p) |
53 | #define ei_inb_p(_p) readb((void __iomem *)_p) |
54 | #define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p) |
55 | |
56 | #define DRV_NAME "etherh" |
57 | #define DRV_VERSION "1.11" |
58 | |
59 | static char version[] = |
60 | "EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n" ; |
61 | |
62 | #include "lib8390.c" |
63 | |
64 | struct etherh_priv { |
65 | void __iomem *ioc_fast; |
66 | void __iomem *memc; |
67 | void __iomem *dma_base; |
68 | unsigned int id; |
69 | void __iomem *ctrl_port; |
70 | unsigned char ctrl; |
71 | u32 supported; |
72 | }; |
73 | |
74 | struct etherh_data { |
75 | unsigned long ns8390_offset; |
76 | unsigned long dataport_offset; |
77 | unsigned long ctrlport_offset; |
78 | int ctrl_ioc; |
79 | const char name[16]; |
80 | u32 supported; |
81 | unsigned char tx_start_page; |
82 | unsigned char stop_page; |
83 | }; |
84 | |
85 | MODULE_AUTHOR("Russell King" ); |
86 | MODULE_DESCRIPTION("EtherH/EtherM driver" ); |
87 | MODULE_LICENSE("GPL" ); |
88 | |
89 | #define ETHERH500_DATAPORT 0x800 /* MEMC */ |
90 | #define ETHERH500_NS8390 0x000 /* MEMC */ |
91 | #define ETHERH500_CTRLPORT 0x800 /* IOC */ |
92 | |
93 | #define ETHERH600_DATAPORT 0x040 /* MEMC */ |
94 | #define ETHERH600_NS8390 0x800 /* MEMC */ |
95 | #define ETHERH600_CTRLPORT 0x200 /* MEMC */ |
96 | |
97 | #define ETHERH_CP_IE 1 |
98 | #define ETHERH_CP_IF 2 |
99 | #define ETHERH_CP_HEARTBEAT 2 |
100 | |
101 | #define ETHERH_TX_START_PAGE 1 |
102 | #define ETHERH_STOP_PAGE 127 |
103 | |
104 | /* |
105 | * These came from CK/TEW |
106 | */ |
107 | #define ETHERM_DATAPORT 0x200 /* MEMC */ |
108 | #define ETHERM_NS8390 0x800 /* MEMC */ |
109 | #define ETHERM_CTRLPORT 0x23c /* MEMC */ |
110 | |
111 | #define ETHERM_TX_START_PAGE 64 |
112 | #define ETHERM_STOP_PAGE 127 |
113 | |
114 | /* ------------------------------------------------------------------------ */ |
115 | |
116 | #define etherh_priv(dev) \ |
117 | ((struct etherh_priv *)(((char *)netdev_priv(dev)) + sizeof(struct ei_device))) |
118 | |
119 | static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned char mask) |
120 | { |
121 | unsigned char ctrl = eh->ctrl | mask; |
122 | eh->ctrl = ctrl; |
123 | writeb(val: ctrl, addr: eh->ctrl_port); |
124 | } |
125 | |
126 | static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned char mask) |
127 | { |
128 | unsigned char ctrl = eh->ctrl & ~mask; |
129 | eh->ctrl = ctrl; |
130 | writeb(val: ctrl, addr: eh->ctrl_port); |
131 | } |
132 | |
133 | static inline unsigned int etherh_get_stat(struct etherh_priv *eh) |
134 | { |
135 | return readb(addr: eh->ctrl_port); |
136 | } |
137 | |
138 | |
139 | |
140 | |
141 | static void etherh_irq_enable(ecard_t *ec, int irqnr) |
142 | { |
143 | struct etherh_priv *eh = ec->irq_data; |
144 | |
145 | etherh_set_ctrl(eh, ETHERH_CP_IE); |
146 | } |
147 | |
148 | static void etherh_irq_disable(ecard_t *ec, int irqnr) |
149 | { |
150 | struct etherh_priv *eh = ec->irq_data; |
151 | |
152 | etherh_clr_ctrl(eh, ETHERH_CP_IE); |
153 | } |
154 | |
155 | static expansioncard_ops_t etherh_ops = { |
156 | .irqenable = etherh_irq_enable, |
157 | .irqdisable = etherh_irq_disable, |
158 | }; |
159 | |
160 | |
161 | |
162 | |
163 | static void |
164 | etherh_setif(struct net_device *dev) |
165 | { |
166 | struct ei_device *ei_local = netdev_priv(dev); |
167 | unsigned long flags; |
168 | void __iomem *addr; |
169 | |
170 | local_irq_save(flags); |
171 | |
172 | /* set the interface type */ |
173 | switch (etherh_priv(dev)->id) { |
174 | case PROD_I3_ETHERLAN600: |
175 | case PROD_I3_ETHERLAN600A: |
176 | addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; |
177 | |
178 | switch (dev->if_port) { |
179 | case IF_PORT_10BASE2: |
180 | writeb(val: (readb(addr) & 0xf8) | 1, addr); |
181 | break; |
182 | case IF_PORT_10BASET: |
183 | writeb(val: (readb(addr) & 0xf8), addr); |
184 | break; |
185 | } |
186 | break; |
187 | |
188 | case PROD_I3_ETHERLAN500: |
189 | switch (dev->if_port) { |
190 | case IF_PORT_10BASE2: |
191 | etherh_clr_ctrl(etherh_priv(dev), ETHERH_CP_IF); |
192 | break; |
193 | |
194 | case IF_PORT_10BASET: |
195 | etherh_set_ctrl(etherh_priv(dev), ETHERH_CP_IF); |
196 | break; |
197 | } |
198 | break; |
199 | |
200 | default: |
201 | break; |
202 | } |
203 | |
204 | local_irq_restore(flags); |
205 | } |
206 | |
207 | static int |
208 | etherh_getifstat(struct net_device *dev) |
209 | { |
210 | struct ei_device *ei_local = netdev_priv(dev); |
211 | void __iomem *addr; |
212 | int stat = 0; |
213 | |
214 | switch (etherh_priv(dev)->id) { |
215 | case PROD_I3_ETHERLAN600: |
216 | case PROD_I3_ETHERLAN600A: |
217 | addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; |
218 | switch (dev->if_port) { |
219 | case IF_PORT_10BASE2: |
220 | stat = 1; |
221 | break; |
222 | case IF_PORT_10BASET: |
223 | stat = readb(addr) & 4; |
224 | break; |
225 | } |
226 | break; |
227 | |
228 | case PROD_I3_ETHERLAN500: |
229 | switch (dev->if_port) { |
230 | case IF_PORT_10BASE2: |
231 | stat = 1; |
232 | break; |
233 | case IF_PORT_10BASET: |
234 | stat = etherh_get_stat(etherh_priv(dev)) & ETHERH_CP_HEARTBEAT; |
235 | break; |
236 | } |
237 | break; |
238 | |
239 | default: |
240 | stat = 0; |
241 | break; |
242 | } |
243 | |
244 | return stat != 0; |
245 | } |
246 | |
247 | /* |
248 | * Configure the interface. Note that we ignore the other |
249 | * parts of ifmap, since its mostly meaningless for this driver. |
250 | */ |
251 | static int etherh_set_config(struct net_device *dev, struct ifmap *map) |
252 | { |
253 | switch (map->port) { |
254 | case IF_PORT_10BASE2: |
255 | case IF_PORT_10BASET: |
256 | /* |
257 | * If the user explicitly sets the interface |
258 | * media type, turn off automedia detection. |
259 | */ |
260 | dev->flags &= ~IFF_AUTOMEDIA; |
261 | dev->if_port = map->port; |
262 | break; |
263 | |
264 | default: |
265 | return -EINVAL; |
266 | } |
267 | |
268 | etherh_setif(dev); |
269 | |
270 | return 0; |
271 | } |
272 | |
273 | /* |
274 | * Reset the 8390 (hard reset). Note that we can't actually do this. |
275 | */ |
276 | static void |
277 | etherh_reset(struct net_device *dev) |
278 | { |
279 | struct ei_device *ei_local = netdev_priv(dev); |
280 | void __iomem *addr = (void __iomem *)dev->base_addr; |
281 | |
282 | writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr); |
283 | |
284 | /* |
285 | * See if we need to change the interface type. |
286 | * Note that we use 'interface_num' as a flag |
287 | * to indicate that we need to change the media. |
288 | */ |
289 | if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) { |
290 | ei_local->interface_num = 0; |
291 | |
292 | if (dev->if_port == IF_PORT_10BASET) |
293 | dev->if_port = IF_PORT_10BASE2; |
294 | else |
295 | dev->if_port = IF_PORT_10BASET; |
296 | |
297 | etherh_setif(dev); |
298 | } |
299 | } |
300 | |
301 | /* |
302 | * Write a block of data out to the 8390 |
303 | */ |
304 | static void |
305 | etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page) |
306 | { |
307 | struct ei_device *ei_local = netdev_priv(dev); |
308 | unsigned long dma_start; |
309 | void __iomem *dma_base, *addr; |
310 | |
311 | if (ei_local->dmaing) { |
312 | netdev_err(dev, format: "DMAing conflict in etherh_block_input: " |
313 | " DMAstat %d irqlock %d\n" , |
314 | ei_local->dmaing, ei_local->irqlock); |
315 | return; |
316 | } |
317 | |
318 | /* |
319 | * Make sure we have a round number of bytes if we're in word mode. |
320 | */ |
321 | if (count & 1 && ei_local->word16) |
322 | count++; |
323 | |
324 | ei_local->dmaing = 1; |
325 | |
326 | addr = (void __iomem *)dev->base_addr; |
327 | dma_base = etherh_priv(dev)->dma_base; |
328 | |
329 | count = (count + 1) & ~1; |
330 | writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr: addr + E8390_CMD); |
331 | |
332 | writeb (val: 0x42, addr: addr + EN0_RCNTLO); |
333 | writeb (val: 0x00, addr: addr + EN0_RCNTHI); |
334 | writeb (val: 0x42, addr: addr + EN0_RSARLO); |
335 | writeb (val: 0x00, addr: addr + EN0_RSARHI); |
336 | writeb (E8390_RREAD | E8390_START, addr: addr + E8390_CMD); |
337 | |
338 | udelay (1); |
339 | |
340 | writeb (ENISR_RDC, addr: addr + EN0_ISR); |
341 | writeb (val: count, addr: addr + EN0_RCNTLO); |
342 | writeb (val: count >> 8, addr: addr + EN0_RCNTHI); |
343 | writeb (val: 0, addr: addr + EN0_RSARLO); |
344 | writeb (val: start_page, addr: addr + EN0_RSARHI); |
345 | writeb (E8390_RWRITE | E8390_START, addr: addr + E8390_CMD); |
346 | |
347 | if (ei_local->word16) |
348 | writesw (addr: dma_base, buffer: buf, count: count >> 1); |
349 | else |
350 | writesb (addr: dma_base, buffer: buf, count); |
351 | |
352 | dma_start = jiffies; |
353 | |
354 | while ((readb (addr: addr + EN0_ISR) & ENISR_RDC) == 0) |
355 | if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ |
356 | netdev_warn(dev, format: "timeout waiting for TX RDC\n" ); |
357 | etherh_reset (dev); |
358 | __NS8390_init (dev, startp: 1); |
359 | break; |
360 | } |
361 | |
362 | writeb (ENISR_RDC, addr: addr + EN0_ISR); |
363 | ei_local->dmaing = 0; |
364 | } |
365 | |
366 | /* |
367 | * Read a block of data from the 8390 |
368 | */ |
369 | static void |
370 | etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) |
371 | { |
372 | struct ei_device *ei_local = netdev_priv(dev); |
373 | unsigned char *buf; |
374 | void __iomem *dma_base, *addr; |
375 | |
376 | if (ei_local->dmaing) { |
377 | netdev_err(dev, format: "DMAing conflict in etherh_block_input: " |
378 | " DMAstat %d irqlock %d\n" , |
379 | ei_local->dmaing, ei_local->irqlock); |
380 | return; |
381 | } |
382 | |
383 | ei_local->dmaing = 1; |
384 | |
385 | addr = (void __iomem *)dev->base_addr; |
386 | dma_base = etherh_priv(dev)->dma_base; |
387 | |
388 | buf = skb->data; |
389 | writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr: addr + E8390_CMD); |
390 | writeb (val: count, addr: addr + EN0_RCNTLO); |
391 | writeb (val: count >> 8, addr: addr + EN0_RCNTHI); |
392 | writeb (val: ring_offset, addr: addr + EN0_RSARLO); |
393 | writeb (val: ring_offset >> 8, addr: addr + EN0_RSARHI); |
394 | writeb (E8390_RREAD | E8390_START, addr: addr + E8390_CMD); |
395 | |
396 | if (ei_local->word16) { |
397 | readsw (addr: dma_base, buffer: buf, count: count >> 1); |
398 | if (count & 1) |
399 | buf[count - 1] = readb (addr: dma_base); |
400 | } else |
401 | readsb (addr: dma_base, buffer: buf, count); |
402 | |
403 | writeb (ENISR_RDC, addr: addr + EN0_ISR); |
404 | ei_local->dmaing = 0; |
405 | } |
406 | |
407 | /* |
408 | * Read a header from the 8390 |
409 | */ |
410 | static void |
411 | (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) |
412 | { |
413 | struct ei_device *ei_local = netdev_priv(dev); |
414 | void __iomem *dma_base, *addr; |
415 | |
416 | if (ei_local->dmaing) { |
417 | netdev_err(dev, format: "DMAing conflict in etherh_get_header: " |
418 | " DMAstat %d irqlock %d\n" , |
419 | ei_local->dmaing, ei_local->irqlock); |
420 | return; |
421 | } |
422 | |
423 | ei_local->dmaing = 1; |
424 | |
425 | addr = (void __iomem *)dev->base_addr; |
426 | dma_base = etherh_priv(dev)->dma_base; |
427 | |
428 | writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr: addr + E8390_CMD); |
429 | writeb (val: sizeof (*hdr), addr: addr + EN0_RCNTLO); |
430 | writeb (val: 0, addr: addr + EN0_RCNTHI); |
431 | writeb (val: 0, addr: addr + EN0_RSARLO); |
432 | writeb (val: ring_page, addr: addr + EN0_RSARHI); |
433 | writeb (E8390_RREAD | E8390_START, addr: addr + E8390_CMD); |
434 | |
435 | if (ei_local->word16) |
436 | readsw (addr: dma_base, buffer: hdr, count: sizeof (*hdr) >> 1); |
437 | else |
438 | readsb (addr: dma_base, buffer: hdr, count: sizeof (*hdr)); |
439 | |
440 | writeb (ENISR_RDC, addr: addr + EN0_ISR); |
441 | ei_local->dmaing = 0; |
442 | } |
443 | |
444 | /* |
445 | * Open/initialize the board. This is called (in the current kernel) |
446 | * sometime after booting when the 'ifconfig' program is run. |
447 | * |
448 | * This routine should set everything up anew at each open, even |
449 | * registers that "should" only need to be set once at boot, so that |
450 | * there is non-reboot way to recover if something goes wrong. |
451 | */ |
452 | static int |
453 | etherh_open(struct net_device *dev) |
454 | { |
455 | struct ei_device *ei_local = netdev_priv(dev); |
456 | |
457 | if (request_irq(irq: dev->irq, handler: __ei_interrupt, flags: 0, name: dev->name, dev)) |
458 | return -EAGAIN; |
459 | |
460 | /* |
461 | * Make sure that we aren't going to change the |
462 | * media type on the next reset - we are about to |
463 | * do automedia manually now. |
464 | */ |
465 | ei_local->interface_num = 0; |
466 | |
467 | /* |
468 | * If we are doing automedia detection, do it now. |
469 | * This is more reliable than the 8390's detection. |
470 | */ |
471 | if (dev->flags & IFF_AUTOMEDIA) { |
472 | dev->if_port = IF_PORT_10BASET; |
473 | etherh_setif(dev); |
474 | mdelay(1); |
475 | if (!etherh_getifstat(dev)) { |
476 | dev->if_port = IF_PORT_10BASE2; |
477 | etherh_setif(dev); |
478 | } |
479 | } else |
480 | etherh_setif(dev); |
481 | |
482 | etherh_reset(dev); |
483 | __ei_open(dev); |
484 | |
485 | return 0; |
486 | } |
487 | |
488 | /* |
489 | * The inverse routine to etherh_open(). |
490 | */ |
491 | static int |
492 | etherh_close(struct net_device *dev) |
493 | { |
494 | __ei_close (dev); |
495 | free_irq (dev->irq, dev); |
496 | return 0; |
497 | } |
498 | |
499 | /* |
500 | * Read the ethernet address string from the on board rom. |
501 | * This is an ascii string... |
502 | */ |
503 | static int etherh_addr(char *addr, struct expansion_card *ec) |
504 | { |
505 | struct in_chunk_dir cd; |
506 | char *s; |
507 | |
508 | if (!ecard_readchunk(&cd, ec, 0xf5, 0)) { |
509 | printk(KERN_ERR "%s: unable to read module description string\n" , |
510 | dev_name(&ec->dev)); |
511 | goto no_addr; |
512 | } |
513 | |
514 | s = strchr(cd.d.string, '('); |
515 | if (s) { |
516 | int i; |
517 | |
518 | for (i = 0; i < 6; i++) { |
519 | addr[i] = simple_strtoul(s + 1, &s, 0x10); |
520 | if (*s != (i == 5? ')' : ':')) |
521 | break; |
522 | } |
523 | |
524 | if (i == 6) |
525 | return 0; |
526 | } |
527 | |
528 | printk(KERN_ERR "%s: unable to parse MAC address: %s\n" , |
529 | dev_name(&ec->dev), cd.d.string); |
530 | |
531 | no_addr: |
532 | return -ENODEV; |
533 | } |
534 | |
535 | /* |
536 | * Create an ethernet address from the system serial number. |
537 | */ |
538 | static int __init etherm_addr(char *addr) |
539 | { |
540 | unsigned int serial; |
541 | |
542 | if (system_serial_low == 0 && system_serial_high == 0) |
543 | return -ENODEV; |
544 | |
545 | serial = system_serial_low | system_serial_high; |
546 | |
547 | addr[0] = 0; |
548 | addr[1] = 0; |
549 | addr[2] = 0xa4; |
550 | addr[3] = 0x10 + (serial >> 24); |
551 | addr[4] = serial >> 16; |
552 | addr[5] = serial >> 8; |
553 | return 0; |
554 | } |
555 | |
556 | static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
557 | { |
558 | strscpy(p: info->driver, DRV_NAME, size: sizeof(info->driver)); |
559 | strscpy(p: info->version, DRV_VERSION, size: sizeof(info->version)); |
560 | strscpy(p: info->bus_info, q: dev_name(dev: dev->dev.parent), |
561 | size: sizeof(info->bus_info)); |
562 | } |
563 | |
564 | static int etherh_get_link_ksettings(struct net_device *dev, |
565 | struct ethtool_link_ksettings *cmd) |
566 | { |
567 | ethtool_convert_legacy_u32_to_link_mode(dst: cmd->link_modes.supported, |
568 | etherh_priv(dev)->supported); |
569 | cmd->base.speed = SPEED_10; |
570 | cmd->base.duplex = DUPLEX_HALF; |
571 | cmd->base.port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; |
572 | cmd->base.autoneg = (dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : |
573 | AUTONEG_DISABLE); |
574 | return 0; |
575 | } |
576 | |
577 | static int etherh_set_link_ksettings(struct net_device *dev, |
578 | const struct ethtool_link_ksettings *cmd) |
579 | { |
580 | switch (cmd->base.autoneg) { |
581 | case AUTONEG_ENABLE: |
582 | dev->flags |= IFF_AUTOMEDIA; |
583 | break; |
584 | |
585 | case AUTONEG_DISABLE: |
586 | switch (cmd->base.port) { |
587 | case PORT_TP: |
588 | dev->if_port = IF_PORT_10BASET; |
589 | break; |
590 | |
591 | case PORT_BNC: |
592 | dev->if_port = IF_PORT_10BASE2; |
593 | break; |
594 | |
595 | default: |
596 | return -EINVAL; |
597 | } |
598 | dev->flags &= ~IFF_AUTOMEDIA; |
599 | break; |
600 | |
601 | default: |
602 | return -EINVAL; |
603 | } |
604 | |
605 | etherh_setif(dev); |
606 | |
607 | return 0; |
608 | } |
609 | |
610 | static u32 etherh_get_msglevel(struct net_device *dev) |
611 | { |
612 | struct ei_device *ei_local = netdev_priv(dev); |
613 | |
614 | return ei_local->msg_enable; |
615 | } |
616 | |
617 | static void etherh_set_msglevel(struct net_device *dev, u32 v) |
618 | { |
619 | struct ei_device *ei_local = netdev_priv(dev); |
620 | |
621 | ei_local->msg_enable = v; |
622 | } |
623 | |
624 | static const struct ethtool_ops etherh_ethtool_ops = { |
625 | .get_drvinfo = etherh_get_drvinfo, |
626 | .get_ts_info = ethtool_op_get_ts_info, |
627 | .get_msglevel = etherh_get_msglevel, |
628 | .set_msglevel = etherh_set_msglevel, |
629 | .get_link_ksettings = etherh_get_link_ksettings, |
630 | .set_link_ksettings = etherh_set_link_ksettings, |
631 | }; |
632 | |
633 | static const struct net_device_ops etherh_netdev_ops = { |
634 | .ndo_open = etherh_open, |
635 | .ndo_stop = etherh_close, |
636 | .ndo_set_config = etherh_set_config, |
637 | .ndo_start_xmit = __ei_start_xmit, |
638 | .ndo_tx_timeout = __ei_tx_timeout, |
639 | .ndo_get_stats = __ei_get_stats, |
640 | .ndo_set_rx_mode = __ei_set_multicast_list, |
641 | .ndo_validate_addr = eth_validate_addr, |
642 | .ndo_set_mac_address = eth_mac_addr, |
643 | #ifdef CONFIG_NET_POLL_CONTROLLER |
644 | .ndo_poll_controller = __ei_poll, |
645 | #endif |
646 | }; |
647 | |
648 | static u32 etherh_regoffsets[16]; |
649 | static u32 etherm_regoffsets[16]; |
650 | |
651 | static int |
652 | etherh_probe(struct expansion_card *ec, const struct ecard_id *id) |
653 | { |
654 | const struct etherh_data *data = id->data; |
655 | struct ei_device *ei_local; |
656 | struct net_device *dev; |
657 | struct etherh_priv *eh; |
658 | u8 addr[ETH_ALEN]; |
659 | int ret; |
660 | |
661 | ret = ecard_request_resources(ec); |
662 | if (ret) |
663 | goto out; |
664 | |
665 | dev = ____alloc_ei_netdev(size: sizeof(struct etherh_priv)); |
666 | if (!dev) { |
667 | ret = -ENOMEM; |
668 | goto release; |
669 | } |
670 | |
671 | SET_NETDEV_DEV(dev, &ec->dev); |
672 | |
673 | dev->netdev_ops = ðerh_netdev_ops; |
674 | dev->irq = ec->irq; |
675 | dev->ethtool_ops = ðerh_ethtool_ops; |
676 | |
677 | if (data->supported & SUPPORTED_Autoneg) |
678 | dev->flags |= IFF_AUTOMEDIA; |
679 | if (data->supported & SUPPORTED_TP) { |
680 | dev->flags |= IFF_PORTSEL; |
681 | dev->if_port = IF_PORT_10BASET; |
682 | } else if (data->supported & SUPPORTED_BNC) { |
683 | dev->flags |= IFF_PORTSEL; |
684 | dev->if_port = IF_PORT_10BASE2; |
685 | } else |
686 | dev->if_port = IF_PORT_UNKNOWN; |
687 | |
688 | eh = etherh_priv(dev); |
689 | eh->supported = data->supported; |
690 | eh->ctrl = 0; |
691 | eh->id = ec->cid.product; |
692 | eh->memc = ecardm_iomap(ec, ECARD_RES_MEMC, 0, PAGE_SIZE); |
693 | if (!eh->memc) { |
694 | ret = -ENOMEM; |
695 | goto free; |
696 | } |
697 | |
698 | eh->ctrl_port = eh->memc; |
699 | if (data->ctrl_ioc) { |
700 | eh->ioc_fast = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, PAGE_SIZE); |
701 | if (!eh->ioc_fast) { |
702 | ret = -ENOMEM; |
703 | goto free; |
704 | } |
705 | eh->ctrl_port = eh->ioc_fast; |
706 | } |
707 | |
708 | dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset; |
709 | eh->dma_base = eh->memc + data->dataport_offset; |
710 | eh->ctrl_port += data->ctrlport_offset; |
711 | |
712 | /* |
713 | * IRQ and control port handling - only for non-NIC slot cards. |
714 | */ |
715 | if (ec->slot_no != 8) { |
716 | ecard_setirq(ec, ðerh_ops, eh); |
717 | } else { |
718 | /* |
719 | * If we're in the NIC slot, make sure the IRQ is enabled |
720 | */ |
721 | etherh_set_ctrl(eh, ETHERH_CP_IE); |
722 | } |
723 | |
724 | ei_local = netdev_priv(dev); |
725 | spin_lock_init(&ei_local->page_lock); |
726 | |
727 | if (ec->cid.product == PROD_ANT_ETHERM) { |
728 | etherm_addr(addr); |
729 | ei_local->reg_offset = etherm_regoffsets; |
730 | } else { |
731 | etherh_addr(addr, ec); |
732 | ei_local->reg_offset = etherh_regoffsets; |
733 | } |
734 | eth_hw_addr_set(dev, addr); |
735 | |
736 | ei_local->name = dev->name; |
737 | ei_local->word16 = 1; |
738 | ei_local->tx_start_page = data->tx_start_page; |
739 | ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES; |
740 | ei_local->stop_page = data->stop_page; |
741 | ei_local->reset_8390 = etherh_reset; |
742 | ei_local->block_input = etherh_block_input; |
743 | ei_local->block_output = etherh_block_output; |
744 | ei_local->get_8390_hdr = etherh_get_header; |
745 | ei_local->interface_num = 0; |
746 | |
747 | etherh_reset(dev); |
748 | __NS8390_init(dev, startp: 0); |
749 | |
750 | ret = register_netdev(dev); |
751 | if (ret) |
752 | goto free; |
753 | |
754 | netdev_info(dev, format: "%s in slot %d, %pM\n" , |
755 | data->name, ec->slot_no, dev->dev_addr); |
756 | |
757 | ecard_set_drvdata(ec, dev); |
758 | |
759 | return 0; |
760 | |
761 | free: |
762 | free_netdev(dev); |
763 | release: |
764 | ecard_release_resources(ec); |
765 | out: |
766 | return ret; |
767 | } |
768 | |
769 | static void etherh_remove(struct expansion_card *ec) |
770 | { |
771 | struct net_device *dev = ecard_get_drvdata(ec); |
772 | |
773 | ecard_set_drvdata(ec, NULL); |
774 | |
775 | unregister_netdev(dev); |
776 | |
777 | free_netdev(dev); |
778 | |
779 | ecard_release_resources(ec); |
780 | } |
781 | |
782 | static struct etherh_data etherm_data = { |
783 | .ns8390_offset = ETHERM_NS8390, |
784 | .dataport_offset = ETHERM_NS8390 + ETHERM_DATAPORT, |
785 | .ctrlport_offset = ETHERM_NS8390 + ETHERM_CTRLPORT, |
786 | .name = "ANT EtherM" , |
787 | .supported = SUPPORTED_10baseT_Half, |
788 | .tx_start_page = ETHERM_TX_START_PAGE, |
789 | .stop_page = ETHERM_STOP_PAGE, |
790 | }; |
791 | |
792 | static struct etherh_data etherlan500_data = { |
793 | .ns8390_offset = ETHERH500_NS8390, |
794 | .dataport_offset = ETHERH500_NS8390 + ETHERH500_DATAPORT, |
795 | .ctrlport_offset = ETHERH500_CTRLPORT, |
796 | .ctrl_ioc = 1, |
797 | .name = "i3 EtherH 500" , |
798 | .supported = SUPPORTED_10baseT_Half, |
799 | .tx_start_page = ETHERH_TX_START_PAGE, |
800 | .stop_page = ETHERH_STOP_PAGE, |
801 | }; |
802 | |
803 | static struct etherh_data etherlan600_data = { |
804 | .ns8390_offset = ETHERH600_NS8390, |
805 | .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, |
806 | .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, |
807 | .name = "i3 EtherH 600" , |
808 | .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, |
809 | .tx_start_page = ETHERH_TX_START_PAGE, |
810 | .stop_page = ETHERH_STOP_PAGE, |
811 | }; |
812 | |
813 | static struct etherh_data etherlan600a_data = { |
814 | .ns8390_offset = ETHERH600_NS8390, |
815 | .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, |
816 | .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, |
817 | .name = "i3 EtherH 600A" , |
818 | .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, |
819 | .tx_start_page = ETHERH_TX_START_PAGE, |
820 | .stop_page = ETHERH_STOP_PAGE, |
821 | }; |
822 | |
823 | static const struct ecard_id etherh_ids[] = { |
824 | { MANU_ANT, PROD_ANT_ETHERM, ðerm_data }, |
825 | { MANU_I3, PROD_I3_ETHERLAN500, ðerlan500_data }, |
826 | { MANU_I3, PROD_I3_ETHERLAN600, ðerlan600_data }, |
827 | { MANU_I3, PROD_I3_ETHERLAN600A, ðerlan600a_data }, |
828 | { 0xffff, 0xffff } |
829 | }; |
830 | |
831 | static struct ecard_driver etherh_driver = { |
832 | .probe = etherh_probe, |
833 | .remove = etherh_remove, |
834 | .id_table = etherh_ids, |
835 | .drv = { |
836 | .name = DRV_NAME, |
837 | }, |
838 | }; |
839 | |
840 | static int __init etherh_init(void) |
841 | { |
842 | int i; |
843 | |
844 | for (i = 0; i < 16; i++) { |
845 | etherh_regoffsets[i] = i << 2; |
846 | etherm_regoffsets[i] = i << 5; |
847 | } |
848 | |
849 | return ecard_register_driver(ðerh_driver); |
850 | } |
851 | |
852 | static void __exit etherh_exit(void) |
853 | { |
854 | ecard_remove_driver(ðerh_driver); |
855 | } |
856 | |
857 | module_init(etherh_init); |
858 | module_exit(etherh_exit); |
859 | |