Linux Device Drivers 2nd Edition (779877), страница 101
Текст из файла (страница 101)
Whenever you register adevice, the kernel asks the driver to initialize itself. Initialization means probing forthe physical interface and filling the net_device structure with the proper values, as described in the following section. If initialization fails, the structure is notlinked to the global list of network devices. This peculiar way of setting things upis most useful during system boot; every driver tries to register its own devices, butonly devices that exist are linked to the list.Because the real initialization is performed elsewhere, the initialization functionhas little to do, and a single statement does it:for (i=0; i<2; i++)if ( (result = register_netdev(snull_devs + i)) )printk("snull: error %i registering device \"%s\"\n",result, snull_devs[i].name);else device_present++;43122 June 2001 16:43http://openlib.org.uaChapter 14: Network DriversInitializing Each DeviceProbing for the device should be performed in the init function for the interface(which is often called the “probe” function).
The single argument received by initis a pointer to the device being initialized; its return value is either 0 or a negativeerror code, usually -ENODEV.No real probing is performed for the snull interface, because it is not bound toany hardware. When you write a real driver for a real interface, the usual rules forprobing devices apply, depending on the peripheral bus you are using.
Also, youshould avoid registering I/O ports and interrupt lines at this point. Hardware registration should be delayed until device open time; this is particularly important ifinterrupt lines are shared with other devices. You don’t want your interface to becalled every time another device triggers an IRQ line just to reply “no, it’s notmine.”The main role of the initialization routine is to fill in the dev structure for thisdevice. Note that for network devices, this structure is always put together at runtime. Because of the way the network interface probing works, the dev structurecannot be set up at compile time in the same manner as a file_operations orblock_device_operations structure. So, on exit from dev->init, the devstructure should be filled with correct values.
Fortunately, the kernel takes care ofsome Ethernet-wide defaults through the function ether_setup, which fills severalfields in struct net_device.The core of snull_init is as follows:ether_setup(dev); /* assign some of the fields */dev->open= snull_open;dev->stop= snull_release;dev->set_config= snull_config;dev->hard_start_xmit = snull_tx;dev->do_ioctl= snull_ioctl;dev->get_stats= snull_stats;dev->rebuild_header = snull_rebuild_header;dev->hard_header= snull_header;#ifdef HAVE_TX_TIMEOUTdev->tx_timeout= snull_tx_timeout;dev->watchdog_timeo = timeout;#endif/* keep the default flags, just add NOARP */dev->flags|= IFF_NOARP;dev->hard_header_cache = NULL;/* Disable caching */SET_MODULE_OWNER(dev);The single unusual feature of the code is setting IFF_NOARP in the flags.
Thisspecifies that the interface cannot use ARP, the Address Resolution Protocol. ARP is43222 June 2001 16:43http://openlib.org.uaConnecting to the Kernela low-level Ethernet protocol; its job is to turn IP addresses into Ethernet MediumAccess Control (MAC) addresses. Since the “remote” systems simulated by snull donot really exist, there is nobody available to answer ARP requests for them.
Ratherthan complicate snull with the addition of an ARP implementation, we chose tomark the interface as being unable to handle that protocol. The assignment tohard_header_cache is there for a similar reason: it disables the caching of the(nonexistent) ARP replies on this interface. This topic is discussed in detail later inthis chapter in “MAC Address Resolution.”The initialization code also sets a couple of fields (tx_timeout and watchdog_timeo) that relate to the handling of transmission timeouts. We will coverthis topic thoroughly later in this chapter in “Transmission Timeouts.”Finally, this code calls SET_MODULE_OWNER, which initializes the owner field ofthe net_device structure with a pointer to the module itself. The kernel usesthis information in exactly the same way it uses the owner field of thefile_operations structure—to maintain the module’s usage count.We’ll look now at one more struct net_device field, priv.
Its role is similarto that of the private_data pointer that we used for char drivers. Unlikefops->private_data, this priv pointer is allocated at initialization timeinstead of open time, because the data item pointed to by priv usually includesthe statistical information about interface activity. It’s important that statistical information always be available, even when the interface is down, because users maywant to display the statistics at any time by calling ifconfig. The memory wastedby allocating priv during initialization instead of on open is irrelevant becausemost probed interfaces are constantly up and running in the system. The snullmodule declares a snull_priv data structure to be used for priv:struct snull_priv {struct net_device_stats stats;int status;int rx_packetlen;u8 *rx_packetdata;int tx_packetlen;u8 *tx_packetdata;struct sk_buff *skb;spinlock_t lock;};The structure includes an instance of struct net_device_stats, which is thestandard place to hold interface statistics.
The following lines in snull_init allocateand initialize dev->priv:dev->priv = kmalloc(sizeof(struct snull_priv), GFP_KERNEL);if (dev->priv == NULL)return -ENOMEM;memset(dev->priv, 0, sizeof(struct snull_priv));spin_lock_init(& ((struct snull_priv *) dev->priv)->lock);43322 June 2001 16:43http://openlib.org.uaChapter 14: Network DriversModule UnloadingNothing special happens when the module is unloaded. The module cleanupfunction simply unregisters the interfaces from the list after releasing memory associated with the private structure:void snull_cleanup(void){int i;for (i=0; i<2; i++) {kfree(snull_devs[i].priv);unregister_netdev(snull_devs + i);}return;}Modularized and Nonmodularized DriversAlthough char and block drivers are the same regardless of whether they’re modular or linked into the kernel, that’s not the case for network drivers.When a driver is linked directly into the Linux kernel, it doesn’t declare its ownnet_device structures; the structures declared in drivers/net/Space.c are usedinstead.
Space.c declares a linked list of all the network devices, both driver-specific structures like plip1 and general-purpose eth devices. Ethernet driversdon’t care about their net_device structures at all, because they use the generalpurpose structures. Such general eth device structures declare ethif_ probe as theirinit function. A programmer inserting a new Ethernet interface in the mainstreamkernel needs only to add a call to the driver’s initialization function to ethif_ probe.Authors of non-eth drivers, on the other hand, insert their net_device structures in Space.c. In both cases only the source file Space.c has to be modified ifthe driver must be linked to the kernel proper.At system boot, the network initialization code loops through all the net_devicestructures and calls their probing (dev->init) functions by passing them apointer to the device itself. If the probe function succeeds, the kernel initializes thenext available net_device structure to use that interface.
This way of setting updrivers permits incremental assignment of devices to the names eth0, eth1, andso on, without changing the name field of each device.When a modularized driver is loaded, on the other hand, it declares its ownnet_device structures (as we have seen in this chapter), even if the interface itcontrols is an Ethernet interface.The curious reader can learn more about interface initialization by looking atSpace.c and net_init.c.43422 June 2001 16:43http://openlib.org.uaThe net_device Structure in DetailThe net_device Structure in DetailThe net_device structure is at the very core of the network driver layer anddeserves a complete description.
At a first reading, however, you can skip this section, because you don’t need a thorough understanding of the structure to getstarted. This list describes all the fields, but more to provide a reference than to bememorized. The rest of this chapter briefly describes each field as soon as it isused in the sample code, so you don’t need to keep referring back to this section.struct net_device can be conceptually divided into two parts: visible andinvisible.
The visible part of the structure is made up of the fields that can beexplicitly assigned in static net_device structures. All structures indrivers/net/Space.c are initialized in this way, without using the tagged syntax forstructure initialization. The remaining fields are used internally by the networkcode and usually are not initialized at compilation time, not even by tagged initialization.
Some of the fields are accessed by drivers (for example, the ones that areassigned at initialization time), while some shouldn’t be touched.The Visible HeadThe first part of struct net_device is composed of the following fields, inthis order:char name[IFNAMSIZ];The name of the device. If the name contains a %d format string, the firstavailable device name with the given base is used; assigned numbers start atzero.unsigned long rmem_end;unsigned long rmem_start;unsigned long mem_end;unsigned long mem_start;Device memory information. These fields hold the beginning and endingaddresses of the shared memory used by the device. If the device has differentreceive and transmit memories, the mem fields are used for transmit memoryand the rmem fields for receive memory.