Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hp-plus.c
Go to the documentation of this file.
1 /* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
2 /*
3  Written 1994 by Donald Becker.
4 
5  This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
6  These cards are sold under several model numbers, usually 2724*.
7 
8  This software may be used and distributed according to the terms
9  of the GNU General Public License, incorporated herein by reference.
10 
11  The author may be reached as [email protected], or C/O
12  Scyld Computing Corporation
13  410 Severn Ave., Suite 210
14  Annapolis MD 21403
15 
16  As is often the case, a great deal of credit is owed to Russ Nelson.
17  The Crynwr packet driver was my primary source of HP-specific
18  programming information.
19 */
20 
21 static const char version[] =
22 "hp-plus.c:v1.10 9/24/94 Donald Becker ([email protected])\n";
23 
24 #include <linux/module.h>
25 
26 #include <linux/string.h> /* Important -- this inlines word moves. */
27 #include <linux/kernel.h>
28 #include <linux/errno.h>
29 #include <linux/ioport.h>
30 #include <linux/netdevice.h>
31 #include <linux/etherdevice.h>
32 #include <linux/init.h>
33 #include <linux/interrupt.h>
34 #include <linux/delay.h>
35 
36 #include <asm/io.h>
37 
38 #include "8390.h"
39 
40 #define DRV_NAME "hp-plus"
41 
42 /* A zero-terminated list of I/O addresses to be probed. */
43 static unsigned int hpplus_portlist[] __initdata =
44 {0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
45 
46 /*
47  The HP EtherTwist chip implementation is a fairly routine DP8390
48  implementation. It allows both shared memory and programmed-I/O buffer
49  access, using a custom interface for both. The programmed-I/O mode is
50  entirely implemented in the HP EtherTwist chip, bypassing the problem
51  ridden built-in 8390 facilities used on NE2000 designs. The shared
52  memory mode is likewise special, with an offset register used to make
53  packets appear at the shared memory base. Both modes use a base and bounds
54  page register to hide the Rx ring buffer wrap -- a packet that spans the
55  end of physical buffer memory appears continuous to the driver. (c.f. the
56  3c503 and Cabletron E2100)
57 
58  A special note: the internal buffer of the board is only 8 bits wide.
59  This lays several nasty traps for the unaware:
60  - the 8390 must be programmed for byte-wide operations
61  - all I/O and memory operations must work on whole words (the access
62  latches are serially preloaded and have no byte-swapping ability).
63 
64  This board is laid out in I/O space much like the earlier HP boards:
65  the first 16 locations are for the board registers, and the second 16 are
66  for the 8390. The board is easy to identify, with both a dedicated 16 bit
67  ID register and a constant 0x530* value in the upper bits of the paging
68  register.
69 */
70 
71 #define HP_ID 0x00 /* ID register, always 0x4850. */
72 #define HP_PAGING 0x02 /* Registers visible @ 8-f, see PageName. */
73 #define HPP_OPTION 0x04 /* Bitmapped options, see HP_Option. */
74 #define HPP_OUT_ADDR 0x08 /* I/O output location in Perf_Page. */
75 #define HPP_IN_ADDR 0x0A /* I/O input location in Perf_Page. */
76 #define HP_DATAPORT 0x0c /* I/O data transfer in Perf_Page. */
77 #define NIC_OFFSET 0x10 /* Offset to the 8390 registers. */
78 #define HP_IO_EXTENT 32
79 
80 #define HP_START_PG 0x00 /* First page of TX buffer */
81 #define HP_STOP_PG 0x80 /* Last page +1 of RX ring */
82 
83 /* The register set selected in HP_PAGING. */
84 enum PageName {
85  Perf_Page = 0, /* Normal operation. */
86  MAC_Page = 1, /* The ethernet address (+checksum). */
87  HW_Page = 2, /* EEPROM-loaded hardware parameters. */
88  LAN_Page = 4, /* Transceiver selection, testing, etc. */
89  ID_Page = 6 };
90 
91 /* The bit definitions for the HPP_OPTION register. */
92 enum HP_Option {
93  NICReset = 1, ChipReset = 2, /* Active low, really UNreset. */
94  EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
95  MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
96 
97 static int hpp_probe1(struct net_device *dev, int ioaddr);
98 
99 static void hpp_reset_8390(struct net_device *dev);
100 static int hpp_open(struct net_device *dev);
101 static int hpp_close(struct net_device *dev);
102 static void hpp_mem_block_input(struct net_device *dev, int count,
103  struct sk_buff *skb, int ring_offset);
104 static void hpp_mem_block_output(struct net_device *dev, int count,
105  const unsigned char *buf, int start_page);
106 static void hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
107  int ring_page);
108 static void hpp_io_block_input(struct net_device *dev, int count,
109  struct sk_buff *skb, int ring_offset);
110 static void hpp_io_block_output(struct net_device *dev, int count,
111  const unsigned char *buf, int start_page);
112 static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
113  int ring_page);
114 
115 
116 /* Probe a list of addresses for an HP LAN+ adaptor.
117  This routine is almost boilerplate. */
118 
119 static int __init do_hpp_probe(struct net_device *dev)
120 {
121  int i;
122  int base_addr = dev->base_addr;
123  int irq = dev->irq;
124 
125  if (base_addr > 0x1ff) /* Check a single specified location. */
126  return hpp_probe1(dev, base_addr);
127  else if (base_addr != 0) /* Don't probe at all. */
128  return -ENXIO;
129 
130  for (i = 0; hpplus_portlist[i]; i++) {
131  if (hpp_probe1(dev, hpplus_portlist[i]) == 0)
132  return 0;
133  dev->irq = irq;
134  }
135 
136  return -ENODEV;
137 }
138 
139 #ifndef MODULE
141 {
142  struct net_device *dev = alloc_eip_netdev();
143  int err;
144 
145  if (!dev)
146  return ERR_PTR(-ENOMEM);
147 
148  sprintf(dev->name, "eth%d", unit);
150 
151  err = do_hpp_probe(dev);
152  if (err)
153  goto out;
154  return dev;
155 out:
156  free_netdev(dev);
157  return ERR_PTR(err);
158 }
159 #endif
160 
161 static const struct net_device_ops hpp_netdev_ops = {
162  .ndo_open = hpp_open,
163  .ndo_stop = hpp_close,
164  .ndo_start_xmit = eip_start_xmit,
165  .ndo_tx_timeout = eip_tx_timeout,
166  .ndo_get_stats = eip_get_stats,
167  .ndo_set_rx_mode = eip_set_multicast_list,
168  .ndo_validate_addr = eth_validate_addr,
169  .ndo_set_mac_address = eth_mac_addr,
170  .ndo_change_mtu = eth_change_mtu,
171 #ifdef CONFIG_NET_POLL_CONTROLLER
172  .ndo_poll_controller = eip_poll,
173 #endif
174 };
175 
176 
177 /* Do the interesting part of the probe at a single address. */
178 static int __init hpp_probe1(struct net_device *dev, int ioaddr)
179 {
180  int i, retval;
181  unsigned char checksum = 0;
182  const char name[] = "HP-PC-LAN+";
183  int mem_start;
184  static unsigned version_printed;
185 
186  if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
187  return -EBUSY;
188 
189  /* Check for the HP+ signature, 50 48 0x 53. */
190  if (inw(ioaddr + HP_ID) != 0x4850 ||
191  (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) {
192  retval = -ENODEV;
193  goto out;
194  }
195 
196  if (ei_debug && version_printed++ == 0)
197  printk(version);
198 
199  printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
200 
201  /* Retrieve and checksum the station address. */
202  outw(MAC_Page, ioaddr + HP_PAGING);
203 
204  for(i = 0; i < ETH_ALEN; i++) {
205  unsigned char inval = inb(ioaddr + 8 + i);
206  dev->dev_addr[i] = inval;
207  checksum += inval;
208  }
209  checksum += inb(ioaddr + 14);
210 
211  printk("%pM", dev->dev_addr);
212 
213  if (checksum != 0xff) {
214  printk(" bad checksum %2.2x.\n", checksum);
215  retval = -ENODEV;
216  goto out;
217  } else {
218  /* Point at the Software Configuration Flags. */
219  outw(ID_Page, ioaddr + HP_PAGING);
220  printk(" ID %4.4x", inw(ioaddr + 12));
221  }
222 
223  /* Read the IRQ line. */
224  outw(HW_Page, ioaddr + HP_PAGING);
225  {
226  int irq = inb(ioaddr + 13) & 0x0f;
227  int option = inw(ioaddr + HPP_OPTION);
228 
229  dev->irq = irq;
230  if (option & MemEnable) {
231  mem_start = inw(ioaddr + 9) << 8;
232  printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
233  } else {
234  mem_start = 0;
235  printk(", IRQ %d, programmed-I/O mode.\n", irq);
236  }
237  }
238 
239  /* Set the wrap registers for string I/O reads. */
240  outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
241 
242  /* Set the base address to point to the NIC, not the "real" base! */
243  dev->base_addr = ioaddr + NIC_OFFSET;
244 
245  dev->netdev_ops = &hpp_netdev_ops;
246 
247  ei_status.name = name;
248  ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */
249  ei_status.tx_start_page = HP_START_PG;
250  ei_status.rx_start_page = HP_START_PG + TX_PAGES/2;
251  ei_status.stop_page = HP_STOP_PG;
252 
253  ei_status.reset_8390 = &hpp_reset_8390;
254  ei_status.block_input = &hpp_io_block_input;
255  ei_status.block_output = &hpp_io_block_output;
256  ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
257 
258  /* Check if the memory_enable flag is set in the option register. */
259  if (mem_start) {
260  ei_status.block_input = &hpp_mem_block_input;
261  ei_status.block_output = &hpp_mem_block_output;
262  ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
263  dev->mem_start = mem_start;
264  ei_status.mem = ioremap(mem_start,
265  (HP_STOP_PG - HP_START_PG)*256);
266  if (!ei_status.mem) {
267  retval = -ENOMEM;
268  goto out;
269  }
270  ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256;
271  dev->mem_end = ei_status.rmem_end
272  = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
273  }
274 
275  outw(Perf_Page, ioaddr + HP_PAGING);
276  NS8390p_init(dev, 0);
277  /* Leave the 8390 and HP chip reset. */
278  outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
279 
280  retval = register_netdev(dev);
281  if (retval)
282  goto out1;
283  return 0;
284 out1:
285  iounmap(ei_status.mem);
286 out:
287  release_region(ioaddr, HP_IO_EXTENT);
288  return retval;
289 }
290 
291 static int
292 hpp_open(struct net_device *dev)
293 {
294  int ioaddr = dev->base_addr - NIC_OFFSET;
295  int option_reg;
296  int retval;
297 
298  if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
299  return retval;
300  }
301 
302  /* Reset the 8390 and HP chip. */
303  option_reg = inw(ioaddr + HPP_OPTION);
304  outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
305  udelay(5);
306  /* Unreset the board and enable interrupts. */
307  outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
308 
309  /* Set the wrap registers for programmed-I/O operation. */
310  outw(HW_Page, ioaddr + HP_PAGING);
311  outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
312 
313  /* Select the operational page. */
314  outw(Perf_Page, ioaddr + HP_PAGING);
315 
316  return eip_open(dev);
317 }
318 
319 static int
320 hpp_close(struct net_device *dev)
321 {
322  int ioaddr = dev->base_addr - NIC_OFFSET;
323  int option_reg = inw(ioaddr + HPP_OPTION);
324 
325  free_irq(dev->irq, dev);
326  eip_close(dev);
327  outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
328  ioaddr + HPP_OPTION);
329 
330  return 0;
331 }
332 
333 static void
334 hpp_reset_8390(struct net_device *dev)
335 {
336  int ioaddr = dev->base_addr - NIC_OFFSET;
337  int option_reg = inw(ioaddr + HPP_OPTION);
338 
339  if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
340 
341  outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
342  /* Pause a few cycles for the hardware reset to take place. */
343  udelay(5);
344  ei_status.txing = 0;
345  outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
346 
347  udelay(5);
348 
349 
350  if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
351  printk("%s: hp_reset_8390() did not complete.\n", dev->name);
352 
353  if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
354 }
355 
356 /* The programmed-I/O version of reading the 4 byte 8390 specific header.
357  Note that transfer with the EtherTwist+ must be on word boundaries. */
358 
359 static void
360 hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
361 {
362  int ioaddr = dev->base_addr - NIC_OFFSET;
363 
364  outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
365  insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
366 }
367 
368 /* Block input and output, similar to the Crynwr packet driver. */
369 
370 static void
371 hpp_io_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
372 {
373  int ioaddr = dev->base_addr - NIC_OFFSET;
374  char *buf = skb->data;
375 
376  outw(ring_offset, ioaddr + HPP_IN_ADDR);
377  insw(ioaddr + HP_DATAPORT, buf, count>>1);
378  if (count & 0x01)
379  buf[count-1] = inw(ioaddr + HP_DATAPORT);
380 }
381 
382 /* The corresponding shared memory versions of the above 2 functions. */
383 
384 static void
385 hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
386 {
387  int ioaddr = dev->base_addr - NIC_OFFSET;
388  int option_reg = inw(ioaddr + HPP_OPTION);
389 
390  outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
391  outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
392  memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr));
393  outw(option_reg, ioaddr + HPP_OPTION);
394  hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3; /* Round up allocation. */
395 }
396 
397 static void
398 hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
399 {
400  int ioaddr = dev->base_addr - NIC_OFFSET;
401  int option_reg = inw(ioaddr + HPP_OPTION);
402 
403  outw(ring_offset, ioaddr + HPP_IN_ADDR);
404 
405  outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
406 
407  /* Caution: this relies on get_8390_hdr() rounding up count!
408  Also note that we *can't* use eth_io_copy_and_sum() because
409  it will not always copy "count" bytes (e.g. padded IP). */
410 
411  memcpy_fromio(skb->data, ei_status.mem, count);
412  outw(option_reg, ioaddr + HPP_OPTION);
413 }
414 
415 /* A special note: we *must* always transfer >=16 bit words.
416  It's always safe to round up, so we do. */
417 static void
418 hpp_io_block_output(struct net_device *dev, int count,
419  const unsigned char *buf, int start_page)
420 {
421  int ioaddr = dev->base_addr - NIC_OFFSET;
422  outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
423  outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
424 }
425 
426 static void
427 hpp_mem_block_output(struct net_device *dev, int count,
428  const unsigned char *buf, int start_page)
429 {
430  int ioaddr = dev->base_addr - NIC_OFFSET;
431  int option_reg = inw(ioaddr + HPP_OPTION);
432 
433  outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
434  outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
435  memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
436  outw(option_reg, ioaddr + HPP_OPTION);
437 }
438 
439 
440 #ifdef MODULE
441 #define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */
442 static struct net_device *dev_hpp[MAX_HPP_CARDS];
443 static int io[MAX_HPP_CARDS];
444 static int irq[MAX_HPP_CARDS];
445 
446 module_param_array(io, int, NULL, 0);
447 module_param_array(irq, int, NULL, 0);
448 MODULE_PARM_DESC(io, "I/O port address(es)");
449 MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
450 MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
451 MODULE_LICENSE("GPL");
452 
453 /* This is set up so that only a single autoprobe takes place per call.
454 ISA device autoprobes on a running machine are not recommended. */
455 int __init
456 init_module(void)
457 {
458  struct net_device *dev;
459  int this_dev, found = 0;
460 
461  for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
462  if (io[this_dev] == 0) {
463  if (this_dev != 0) break; /* only autoprobe 1st one */
464  printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
465  }
466  dev = alloc_eip_netdev();
467  if (!dev)
468  break;
469  dev->irq = irq[this_dev];
470  dev->base_addr = io[this_dev];
471  if (do_hpp_probe(dev) == 0) {
472  dev_hpp[found++] = dev;
473  continue;
474  }
475  free_netdev(dev);
476  printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
477  break;
478  }
479  if (found)
480  return 0;
481  return -ENXIO;
482 }
483 
484 static void cleanup_card(struct net_device *dev)
485 {
486  /* NB: hpp_close() handles free_irq */
487  iounmap(ei_status.mem);
488  release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
489 }
490 
491 void __exit
492 cleanup_module(void)
493 {
494  int this_dev;
495 
496  for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
497  struct net_device *dev = dev_hpp[this_dev];
498  if (dev) {
499  unregister_netdev(dev);
500  cleanup_card(dev);
501  free_netdev(dev);
502  }
503  }
504 }
505 #endif /* MODULE */