´ÙÀ½ ÀÌÀü Â÷·Ê

8. ±â¼úÀû Á¤º¸

ÀÌ ¹®¼­´Â Ä«µå°¡ ¾î¶»°Ô ÀÛµ¿Çϴ°¡¸¦ Á¶±ÝÀÌ¶óµµ ´õ ÀÌÇØÇÏ±æ ¿øÇϰųª, ÇöÀç µå¶óÀ̹öµéÀ» °¡Áö°í ³î°Å³ª ÇöÀç Áö¿øµÇÁö ¾Ê´Â Ä«µåÀÇ °íÀ¯ÇÑ µå¶óÀ̹ö¸¦ ¸¸µé·Á°í ÇÏ´ÂÀ̵鿡°Ô ¸Å¿ì À¯¿ë ÇÒ °ÍÀÌ´Ù. ¸¸ÀÏ ÀÌ Ä«Å×°í¸®¿¡ ºüÁ®µé±â ½È´Ù¸é ÀÌ ÀåÀ» ³Ñ¾î°¡µµ µÈ´Ù.

8.1 Programmed I/O vs. °øÀ¯ ¸Þ¸ð¸® vs. DMA

¸¸ÀÏ ¿©·¯ºÐÀÌ ÀÌ¹Ì ¹éÅõ¹é ÆÐŶµéÀ» º¸³»°í ¹ÞÀ»¼ö ÀÖ´Ù¸é, ¼±À» ÅëÇØ ´õ ¸¹Àº °ÍÀ» ³ÖÀ»¼ö´Â ¾ø´Ù. ¸ðµç Çö´ëÀûÀÎ ÀÌ´õ³Ý Ä«µå´Â ¹éÅõ¹é ÆÐŶµéÀ» ¹ÞÀ»¼ö ÀÖ´Ù. ¸®´ª½ºÀÇ DP8390 µå¶óÀ̹öµé (wd80x3, SMC-Ultra, 3c503, ne2000, µîµî)Àº ¹éÅõ¹é ÆÐŶµéÀ» ¸Å¿ì Àß º¸³»°í(ÇöÀçÀÇ ÀÎÅÍ·´Æ® ´ë±â½Ã°£¿¡ ÀÇÁ¸ÇÑ´Ù) 3c509¿Í AT1500 Çϵå¿þ¾î´Â ÀÚµ¿À¸·Î ¹éÅõ¹é ÆÐŶµéÀ» º¸³»´Âµ¥ ÀüÇô ¹® Á¦°¡ ¾ø´Ù.

ISA ¹ö½º´Â 5.3MB/sec (42Mb/sec)ÀÇ ¼Óµµ¸¦ °¡Áú¼ö ÀÖÀ¸¸ç, 10Mbps ÀÌ´õ³Ý¿¡´Â ÃæºÐÇØ º¸ÀδÙ. 100Mbps Ä«µåµéÀÇ °æ¿ì¿¡´Â ³×Æ®¿öÅ© ´ë¿ªÆøÀÇ ÀÌÁ¡À» ¾ò±â À§Çؼ­´Â ´õ ºü¸¥ ¹ö½º°¡ ÇÊ¿äÇÑ °ÍÀÌ ´ç¿¬ÇÏ´Ù.

Programmed I/O (e.g. NE2000, 3c509)

Pro: ¾î¶°ÇÑ °­Á¦ÀûÀÎ ½Ã½ºÅÛ ÀÚ¿øÀÇ »ç¿ëµµ ¾øÀ¸¸ç, ¾ÆÁÖ Á¶±ÝÀÇ I/O ·¹Áö½ºÅ͸¦ »ç¿ëÇÏ°í, 16M Á¦ÇÑÀ» °¡ÁöÁö ¾Ê´Â´Ù.

Con: º¸Åë Àü¼Û·üÀÌ °¡Àå ´À¸®°í, CPU´Â Ç×»ó ±â´Ù·Á¾ßÇϸç, ³¢¾îµç ÆÐŶ¿¡ ´ëÇÑ Á¢±ÙÀº º¸Åë Èûµé°Å³ª ºÒ°¡´ÉÇÏ´Ù.

°øÀ¯ ¸Þ¸ð¸® (e.g. WD80x3, SMC-Ultra, 3c503)

Pro: °£´ÜÇÏ°í, programmed I/O º¸´Ù ºü¸£¸ç, ÆÐŶµé¿¡ ´ëÇÑ ¹«ÀÛÀ§ Á¢±ÙÀÌ Çã¿ëµÈ´Ù. ¾îµð¿¡¼­ »ç¿ëµÇ³Ä¸é, ¸®´ª½º µå¶óÀ̹öµéÀÌ µé¾î¿Â IP ÆÐŶµéÀÌ Ä«µå¿¡¼­ º¹»çµÇ¹Ç·Î ±×µéÀÇ Ã¼Å©¼¶À» °è »êÇÏ°í, ±×·ÎÀÎÇØ µ¿±ÞÀÇ PIO Ä«µå¿¡ ºñÇØ CPU Á¡À¯À²ÀÌ Àû¾îÁø´Ù.

Con: ¸Þ¸ð¸® °ø°£À» »ç¿ëÇϸç (DOS »ç¿ëÀڵ鿡°Ô´Â ¸Å¿ì Å«°ÅÁö¸¸, ¸®´ª½º»ó¿¡¼­´Â Ưº°È÷ ¹®Á¦ µÇÁö ¾Ê´Â´Ù), ±×¸®°í ¿©ÀüÈ÷ CPU¸¦ Àâ¾ÆµÐ´Ù.

Slave (normal) Direct Memory Access (e.g. ¸®´ª½º¿¡´Â ¾ø´Ù!)

Pro: ½ÇÁ¦ µ¥ÀÌŸ Àü¼Û½Ã¿¡´Â CPU ¸¦ ³õ¾ÆÁØ´Ù.

Con: °æ°è¼± »óŸ¦ È®ÀÎÇÏ°í, ÀÎÁ¢ÇÑ ¹öÆÛµéÀ» Àç¹èÄ¡Çϸç, DMA ¸®Áö½ºÅ͵éÀ» ÇÁ·Î±×·¡¹ÖÇÏ¿© ¸ðµç ±â¼úµéÁß¿¡ °¡Àå ´À¸®´Ù. ¶ÇÇÑ ºÎÁ·ÇÑ DMA ä³ÎÀ» »ç¿ëÇϸç, Àú¼öÁØ ¸Þ¸ð¸® ¹öÆÛÀÇ Á¤·ÄÀ» ÇÊ¿ä·Î ÇÑ´Ù.

Bus Master Direct Memory Access (e.g. LANCE, DEC 21040)

Pro: µ¥ÀÌŸ Àü¼ÛÁß¿¡´Â CPU°¡ ÀÚÀ¯·Î¿ì¸ç, ¹öÆÛµé°ú ÇÔ²² ¹è¿­ÇÒ¼ö ÀÖÀ¸¸ç, ISA ¹ö½º»ó¿¡¼­ ÀÒ¾î¹ö¸®´Â ¾ÆÁÖ Á¶±ÝÀ̳ª ¾Æ´Ï¸é CPU½Ã°£À» ÀüÇô ÇÊ¿ä·ÎÇÏÁö ¾Ê±âµµ ÇÑ´Ù. ´ëºÎºÐÀÇ ¹ö½º ¸¶½º Å͸µ ¸®´ª½º µå¶óÀ̹öµéÀº ÇöÀç `Ä«ÇǺ극ÀÌÅ©' ±¸Á¶¸¦ »ç¿ëÇϴµ¥ ÀÌ°ÍÀº Ä«µå°¡ Å« ÆÐŶµéÀ» Ä¿³Î ³×Æ®¿öÅ· ¹öÆÛ¿¡ Á÷Á¢ ³Ö´Â Àå¼ÒÀÌ°í, ÀÛÀº ÆÐŶµéÀº CPU°¡ º¹»çÇÔÀ¸·Î¼­ ÀÌÈÄ·Î ÁøÇàµÇ´Â ij½Ã¸¦ ÁغñÇÏ°Ô ÇÑ´Ù.

Con: (ISA ¹ö½º Ä«µåµé¿¡¸¸ ÇØ´çµÈ´Ù) Ä«µå¿¡´Â Àú¼öÁØ ¸Þ¸ð¸® ¹öÆÛ¿Í DMAä³ÎÀÌ ÇÊ¿äÇÏ´Ù. Any bus-master will have problems with other bus-masters that are bus-hogs, such as some primitive SCSI adaptors. A few badly-designed motherboard chipsets have problems with bus-masters. And a reason for not using any type of DMA device is using a 486 processor designed for plug-in replacement of a 386: these processors must flush their cache with each DMA cycle. (This includes the Cx486DLC, Ti486DLC, Cx486SLC, Ti486SLC, etc.)

8.2 Writing a Driver

The only thing that one needs to use an ethernet card with Linux is the appropriate driver. For this, it is essential that the manufacturer will release the technical programming information to the general public without you (or anyone) having to sign your life away. A good guide for the likelihood of getting documentation (or, if you aren't writing code, the likelihood that someone else will write that driver you really, really need) is the availability of the Crynwr (nee Clarkson) packet driver. Russ Nelson runs this operation, and has been very helpful in supporting the development of drivers for Linux. Net-surfers can try this URL to look up Russ' software.

Russ Nelson's Packet Drivers

Given the documentation, you can write a driver for your card and use it for Linux (at least in theory). Keep in mind that some old hardware that was designed for XT type machines will not function very well in a multitasking environment such as Linux. Use of these will lead to major problems if your network sees a reasonable amount of traffic.

Most cards come with drivers for MS-DOS interfaces such as NDIS and ODI, but these are useless for Linux. Many people have suggested directly linking them in or automatic translation, but this is nearly impossible. The MS-DOS drivers expect to be in 16 bit mode and hook into `software interrupts', both incompatible with the Linux kernel. This incompatibility is actually a feature, as some Linux drivers are considerably better than their MS-DOS counterparts. The `8390' series drivers, for instance, use ping-pong transmit buffers, which are only now being introduced in the MS-DOS world.

(Ping-pong Tx buffers means using at least 2 max-size packet buffers for Tx packets. One is loaded while the card is transmitting the other. The second is then sent as soon as the first finished, and so on. In this way, most cards are able to continuously send back-to-back packets onto the wire.)

OK. So you have decided that you want to write a driver for the Foobar Ethernet card, as you have the programming information, and it hasn't been done yet. (...these are the two main requirements ;-) You should start with the skeleton network driver that is provided with the Linux kernel source tree. It can be found in the file /usr/src/linux/drivers/net/skeleton.c in all recent kernels. Also have a look at the Kernel Hackers Guide, at the following URL: KHG

8.3 Driver interface to the kernel

Here are some notes on the functions that you would have to write if creating a new driver. Reading this in conjunction with the above skeleton driver may help clear things up.

Probe

Called at boot to check for existence of card. Best if it can check un-obtrsively by reading from memory, etc. Can also read from I/O ports. Initial writing to I/O ports in a probe is not good as it may kill another device. Some device initialization is usually done here (allocating I/O space, IRQs,filling in the dev->??? fields etc.) You need to know what io ports/mem the card can be configured to, how to enable shared memory (if used) and how to select/enable interrupt generation, etc.

Interrupt handler

Called by the kernel when the card posts an interrupt. This has the job of determining why the card posted an interrupt, and acting accordingly. Usual interrupt conditions are data to be rec'd, transmit completed, error conditions being reported. You need to know any relevant interrupt status bits so that you can act accordingly.

Transmit function

Linked to dev->hard_start_xmit() and is called by the kernel when there is some data that the kernel wants to put out over the device. This puts the data onto the card and triggers the transmit. You need to know how to bundle the data and how to get it onto the card (shared memory copy, PIO transfer, DMA?) and in the right place on the card. Then you need to know how to tell the card to send the data down the wire, and (possibly) post an interrupt when done. When the hardware can't accept additional packets it should set the dev->tbusy flag. When additional room is available, usually during a transmit-complete interrupt, dev->tbusy should be cleared and the higher levels informed with mark_bh(INET_BH).

Receive function

Called by the kernel interrupt handler when the card reports that there is data on the card. It pulls the data off the card, packages it into a sk_buff and lets the kernel know the data is there for it by doing a netif_rx(sk_buff). You need to know how to enable interrupt generation upon Rx of data, how to check any relevant Rx status bits, and how to get that data off the card (again sh mem, PIO, DMA, etc.)

Open function

linked to dev->open and called by the networking layers when somebody does ifconfig eth0 up - this puts the device on line and enables it for Rx/Tx of data. Any special initialization incantations that were not done in the probe sequence (enabling IRQ generation, etc.) would go in here.

Close function (optional)

This puts the card in a sane state when someone does ifconfig eth0 down. It should free the IRQs and DMA channels if the hardware permits, and turn off anything that will save power (like the transceiver).

Miscellaneous functions

Things like a reset function, so that if things go south, the driver can try resetting the card as a last ditch effort. Usually done when a Tx times out or similar. Also a function to read the statistics registers of the card if so equipped.

8.4 Technical information from 3Com

If you are interested in working on drivers for 3Com cards, you can get technical documentation from 3Com. Cameron has been kind enough to tell us how to go about it below:

3Com's Ethernet Adapters are documented for driver writers in our `Technical References' (TRs). These manuals describe the programmer interfaces to the boards but they don't talk about the diagnostics, installation programs, etc that end users can see.

The Network Adapter Division marketing department has the TRs to give away. To keep this program efficient, we centralized it in a thing called `CardFacts.' CardFacts is an automated phone system. You call it with a touch-tone phone and it faxes you stuff. To get a TR, call CardFacts at 408-727-7021. Ask it for Developer's Order Form, document number 9070. Have your fax number ready when you call. Fill out the order form and fax it to 408-764-5004. Manuals are shipped by Federal Express 2nd Day Service.

There are people here who think we are too free with the manuals, and they are looking for evidence that the system is too expensive, or takes too much time and effort. So far, 3Com customers have been really good about this, and there's no problem with the level of requests we've been getting. We need your continued cooperation and restraint to keep it that way.

8.5 Notes on AMD PCnet / LANCE Based cards

The AMD LANCE (Local Area Network Controller for Ethernet) was the original offering, and has since been replaced by the `PCnet-ISA' chip, otherwise known as the 79C960. Note that the name `LANCE' has stuck, and some people will refer to the new chip by the old name. Dave Roberts of the Network Products Division of AMD was kind enough to contribute the following information regarding this chip:

`Functionally, it is equivalent to a NE1500. The register set is identical to the old LANCE with the 1500/2100 architecture additions. Older 1500/2100 drivers will work on the PCnet-ISA. The NE1500 and NE2100 architecture is basically the same. Initially Novell called it the 2100, but then tried to distinguish between coax and 10BASE-T cards. Anything that was 10BASE-T only was to be numbered in the 1500 range. That's the only difference.

Many companies offer PCnet-ISA based products, including HP, Racal-Datacom, Allied Telesis, Boca Research, Kingston Technology, etc. The cards are basically the same except that some manufacturers have added `jumperless' features that allow the card to be configured in software. Most have not. AMD offers a standard design package for a card that uses the PCnet-ISA and many manufacturers use our design without change. What this means is that anybody who wants to write drivers for most PCnet-ISA based cards can just get the data-sheet from AMD. Call our literature distribution center at (800)222-9323 and ask for the Am79C960, PCnet-ISA data sheet. It's free.

A quick way to understand whether the card is a `stock' card is to just look at it. If it's stock, it should just have one large chip on it, a crystal, a small IEEE address PROM, possibly a socket for a boot ROM, and a connector (1, 2, or 3, depending on the media options offered). Note that if it's a coax card, it will have some transceiver stuff built onto it as well, but that should be near the connector and away from the PCnet-ISA.'

A note to would-be card hackers is that different LANCE implementations do `restart' in different ways. Some pick up where they left off in the ring, and others start right from the beginning of the ring, as if just initialised.

8.6 Multicast and Promiscuous Mode

Another one of the things Donald has worked on is implementing multicast and promiscuous mode hooks. All of the released (i.e. not ALPHA) ISA drivers now support promiscuous mode.

Donald writes: `I'll start by discussing promiscuous mode, which is conceptually easy to implement. For most hardware you only have to set a register bit, and from then on you get every packet on the wire. Well, it's almost that easy; for some hardware you have to shut the board (potentially dropping a few packet), reconfigure it, and then re-enable the ethercard. OK, so that's easy, so I'll move on something that's not quite so obvious: Multicast. It can be done two ways:

  1. Use promiscuous mode, and a packet filter like the Berkeley packet filter (BPF). The BPF is a pattern matching stack language, where you write a program that picks out the addresses you are interested in. Its advantage is that it's very general and programmable. Its disadvantage is that there is no general way for the kernel to avoid turning on promiscuous mode and running every packet on the wire through every registered packet filter. See The Berkeley Packet Filter for more info.
  2. Using the built-in multicast filter that most etherchips have.

I guess I should list what a few ethercards/chips provide:

        
        Chip/card  Promiscuous  Multicast filter
        ----------------------------------------
        Seeq8001/3c501  Yes     Binary filter (1)
        3Com/3c509      Yes     Binary filter (1)
        8390            Yes     Autodin II six bit hash (2) (3)
        LANCE           Yes     Autodin II six bit hash (2) (3)
        i82586          Yes     Hidden Autodin II six bit hash (2) (4)
        

  1. These cards claim to have a filter, but it's a simple yes/no `accept all multicast packets', or `accept no multicast packets'.
  2. AUTODIN II is the standard ethernet CRC (checksum) polynomial. In this scheme multicast addresses are hashed and looked up in a hash table. If the corresponding bit is enabled, this packet is accepted. Ethernet packets are laid out so that the hardware to do this is trivial -- you just latch six (usually) bits from the CRC circuit (needed anyway for error checking) after the first six octets (the destination address), and use them as an index into the hash table (six bits -- a 64-bit table).
  3. These chips use the six bit hash, and must have the table computed and loaded by the host. This means the kernel must include the CRC code.
  4. The 82586 uses the six bit hash internally, but it computes the hash table itself from a list of multicast addresses to accept.

Note that none of these chips do perfect filtering, and we still need a middle-level module to do the final filtering. Also note that in every case we must keep a complete list of accepted multicast addresses to recompute the hash table when it changes.

8.7 The Berkeley Packet Filter (BPF)

The general idea of the developers is that the BPF functionality should not be provided by the kernel, but should be in a (hopefully little-used) compatibility library.

For those not in the know: BPF (the Berkeley Packet Filter) is an mechanism for specifying to the kernel networking layers what packets you are interested in. It's implemented as a specialized stack language interpreter built into a low level of the networking code. An application passes a program written in this language to the kernel, and the kernel runs the program on each incoming packet. If the kernel has multiple BPF applications, each program is run on each packet.

The problem is that it's difficult to deduce what kind of packets the application is really interested in from the packet filter program, so the general solution is to always run the filter. Imagine a program that registers a BPF program to pick up a low data-rate stream sent to a multicast address. Most ethernet cards have a hardware multicast address filter implemented as a 64 entry hash table that ignores most unwanted multicast packets, so the capability exists to make this a very inexpensive operation. But with the BPF the kernel must switch the interface to promiscuous mode, receive _all_ packets, and run them through this filter. This is work, BTW, that's very difficult to account back to the process requesting the packets.


´ÙÀ½ ÀÌÀü Â÷·Ê