Linux operating system network driver programming 3

Source: Internet
Author: User

/* For Load Balancing driver pair support */

Unsigned long pkt_queue;/* packets queued */
Struct device * slave;/* slave device */
Struct net_alias_info * alias_info;/* main Dev alias info */
Struct net_alias * my_alias;/* alias Devs */

/* Pointer to the interface buffers .*/
Struct sk_buff_head buffs [dev_numbuffs];

/* Pointers to interface service routines .*/
INT (* open) (struct device * Dev );
INT (* Stop) (struct device * Dev );
INT (* hard_start_xmit) (struct sk_buff * SKB,
Struct device * Dev );
INT (* hard_header) (struct sk_buff * SKB,
Struct device * Dev,
Unsigned short type,
Void * daddr,
Void * saddr,
Unsigned Len );
INT (* rebuild_header) (void * Eth, struct device * Dev,
Unsigned long raddr, struct sk_buff * SKB );
# Define have_multicast
Void (* set_multicast_list) (struct device * Dev );
# Define have_set_mac_addr
INT (* set_mac_address) (struct device * Dev, void * ADDR );
# Define have_private_ioctl
INT (* do_ioctl) (struct device * Dev, struct ifreq * IFR, int cmd );
# Define have_set_config
INT (* set_config) (struct device * Dev, struct ifmap * map );
# Define have_header_cache
Void (* header_cache_bind) (struct hh_cache ** HHP, struct Device
* Dev, unsigned short htype, _ u32 daddr );
Void (* header_cache_update) (struct hh_cache * hh, struct Device
* Dev, unsigned char * haddr );
# Define have_change_mtu
INT (* change_mtu) (struct device * Dev, int new_mtu );

Struct iw_statistics * (* get_wireless_stats) (struct device * Dev );
};

2.4 Common System Support

2.4.1 memory application and release
Include/Linux/kernel. h declares kmalloc () and kfree (). Used for applying in kernel mode
Please and release the memory.
Void * kmalloc (unsigned int Len, int priority );
Void kfree (void * _ PTR );
Unlike malloc () in user mode, the size of the kmalloc () application space is limited. The length is an integer of 2.
Power. The maximum length that can be applied is limited. In addition, kmalloc () has the priority parameter, which is usually used
It can be gfp_kernel. If the gfp_atomic parameter is used in the interrupt call, the gfp_kernel
The caller may enter the sleep status, which is not allowed when the service is interrupted.
The memory released by kfree () must be applied by kmalloc. If you know the memory size, you can also use
Kfree_s () is released.

2.4.2 request_irq (), free_irq ()
This is the call for the driver to request and release the interrupt. Declare it in include/Linux/sched. h.
Request_irq () call definition:
Int request_irq (unsigned int IRQ,
Void (* Handler) (int irq, void * dev_id, struct pt_regs * regs ),
Unsigned long irqflags,
Const char * devname,
Void * dev_id );
IRQ is the hardware interrupt number to be applied. On Intel Platform, the range is 0--15. Handler registers with the System
. This is a callback function. When an interrupt occurs, the system calls this function and the input parameters.
The number includes the hardware interrupt number, device ID, and register value. Dev_id is passed when the following request_irq is passed
The system parameter dev_id. Irqflags is an attribute of Interrupt Processing. Sa_interrupt,
Indicates whether the interrupt processing program is a fast processing program (set sa_interrupt) or a slow processing program (not set
Sa_interrupt ). All interrupts are blocked when the quick processing program is called. The slow processing program is not blocked. And
A sa_shirq attribute. Multiple devices are interrupted to share. Dev_id is used when sharing is interrupted.
To. It is generally set to the device structure of the device itself or null. The interrupt handler can use dev_id
Find the device that controls the interruption, or use irq2dev_map to find the device that is interrupted.
Void free_irq (unsigned int IRQ, void * dev_id );

2.4.3 clock
Clock processing is similar to an interrupt. It is also a time processing function registered. After the scheduled time, the system
This function is called. Declare it in include/Linux/Timer. h.
Struct timer_list {
Struct timer_list * next;
Struct timer_list * Prev;
Unsigned long expires;
Unsigned long data;
Void (* function) (unsigned long );
};
Void add_timer (struct timer_list * timer );
Int del_timer (struct timer_list * timer );
Void init_timer (struct timer_list * timer );
Use the clock to declare a timer_list structure and call init_timer to initialize it.
In the time_list structure, expires indicates the cycle of the clock. The unit is jiffies.
Jiffies is a global variable in Linux, representing the time. Its unit varies with the hardware platform.
A constant Hz is defined in the system, representing the number of minimum time intervals per second. In this way, the unit of jiffies
It is 1/Hz. Jiffies on Intel is measured in 1/100 seconds, which is the minimum time that can be distinguished by the system.
Interval. Therefore, expires/Hz is the cycle of the clock in seconds.
Function is the callback function after the time is reached. Its parameter is data in timer_list.
The data parameter is assigned a value when the clock is initialized and is generally assigned to the device structure pointer of the device.
Call the function from the preset time to the system, and the system clears the time_list from the scheduled queue.
Division. So if you need to keep using the timer function, you need to call add_timer () again in the function

------------------ Linux operating system network driver programming -------------------
------------ Contact the author by mailto: bordi@bordi.dhs.org ------

Timer_list added to the scheduled queue.

2.4.4 I/O
I/O port access and usage:
Inline unsigned int INB (unsigned short port );
Inline unsigned int inb_p (unsigned short port );
Inline void outb (char value, unsigned short port );
Inline void outb_p (char value, unsigned short port );
Defined in include/ADM/IO. h.
Inb_p (), outb_p (), INB (), and outb_p () are different in that the former has a waiting time when accessing I/O.
(Pause) a slow I/O device.
To prevent access to I/O conflicts, Linux provides control over port usage. Port used
Previously, you can check whether the required I/O is in use. If not, mark the port as in use,
Release after use. The system provides the following functions to do this.
Int check_region (unsigned int from, unsigned int extent );
Void request_region (unsigned int from, unsigned int extent, const char * Name );
Void release_region (unsigned int from, unsigned int extent );
The parameter from indicates the start address of the I/O port used, and extent indicates the end starting from
Number of ports. Name indicates the device name.

2.4.5 enable or disable an interrupt
The system provides the driver with the ability to open and close the response to interruptions. Is in include/ASM/system. h
.
# Define CLI () _ ASM _ volatile _ (\ "CLI \"::)
# Define STI () _ ASM _ volatile _ (\ "Sti \"::)

2.4.6 print information
Similar to printf () in a common program, the driver needs to output information using printk (). In include
/Linux/kernel. h.
Int printk (const char * FMT ,...);
FMT is a formatted string .... Yes. Both are in the same format as printf.

2.4.7 register the driver
If you use the module method to load the driver, you must register the device during module initialization.
Go to the system device table. Remove the device from the system when it is no longer in use. Defined in drivers/NET/net_init.h
The two functions in.
Int register_netdev (struct device * Dev );
Void unregister_netdev (struct device * Dev );
Dev is the device structure pointer to be registered into the system. In register_netdev (), Dev structure 1
Enter the first 11 items, that is, to init. Initialization is not required for the subsequent items. The most important thing is the name pointer and
Init method. The name pointer is null or the content is \ "\ 0 \" or the name [0] is a space.
Use your device as an Ethernet device. Ethernet devices have a uniform naming format, ethx. For Ethernet
This special treatment is probably related to the history of Linux.
The init method must be provided. register_netdev () will call this method to check the hardware and
.
Register_netdev () returns 0, indicating that the operation is successful. Otherwise, the operation fails.

2.4.8 sk_buff
Data transmission between different layers of the Linux network is through sk_buff. Sk_buff provides a set of management Buffering
The partition method is the key to the efficient running of the Linux system network. Each sk_buff includes some control methods and
Block data buffer. The control method is divided into two types by function. One method is to control the entire buffer chain,
Another method is to control the data buffer. Sk_buff is organized into a two-way linked list based on network applications.
The operation on the linked list is mainly to delete the elements of the linked list header and add them to the end of the linked list. Sk_buff Control
Methods are short and small to minimize system load. (Translated from article written by Alan
Cox)
Common methods include:
. Alloc_skb () applies for a sk_buff and initializes it. The requested sk_buff is returned.
. Dev_alloc_skb () is similar to alloc_skb. After applying for a buffer zone, leave the 16-byte frame header blank.
. It is mainly used in Ethernet drivers.
. Kfree_skb () releases a sk_buff.
. Skb_clone () copies a sk_buff, but does not copy the data.
. Skb_copy () completely copies a sk_buff.
. Skb_dequeue () extracts the first element from a sk_buff linked list. Return the retrieved sk_buff,
If the linked list is empty, return null. This is a common operation.
. Skb_queue_head () puts an element in the header of A sk_buff linked list.
. Skb_queue_tail () puts an element at the end of a sk_buff linked list. This is also a common
Operation. Network data processing is mainly for the management of a first-in-first-out queue, skb_queue_tail ()
And skb_dequeue.
. Skb_insert () inserts an element before an element in the linked list.
. Skb_append () inserts an element after an element in the linked list. For some protocols (such as TCP ),
Skb_insert () and skb_append () are used for restructuring the data arriving in sequence ().

. Skb_reserve () reserves a space in the buffer zone of the applied sk_buff. This space
It is generally used as the header space of the next layer of protocol.
. Skb_put () reserves a space for data in the buffer zone of the applied sk_buff. In
After alloc_skb, the buffer of the applied sk_buff is in the free status, with
The tail Pointer Points to free space. In fact, tail points to the buffer header at the beginning. Skb_reserve ()
Apply for the protocol header space in the free space, and apply for the data space using skb_put. See the figure below.
. Skb_push () moves the data space in the sk_buff buffer forward. Move the space in the head room
Data area.
. Skb_pull () moves the space in the data area in the sk_buff buffer to the head room.

--------------------------------------------------
| Tail room (free) |
--------------------------------------------------
After alloc_skb ()

--------------------------------------------------
| Head room | tail room (free) |
--------------------------------------------------
After skb_reserve ()

--------------------------------------------------
| Head room | data area | tail room (free) |
--------------------------------------------------
After skb_put ()

--------------------------------------------------
| HEAD | SKB _ | data | tail room (free) |
| Room | push |
| Data area |
--------------------------------------------------
After skb_push ()

--------------------------------------------------
| HEAD | SKB _ | data area | tail room (free) |
| Pull |
| Head room |
--------------------------------------------------
After skb_pull ()

------------------ Linux operating system network driver programming -------------------
------------ Contact the author by mailto: bordi@bordi.dhs.org ------

3. Notes for compiling Linux network drivers

3.1 interrupt sharing
In Linux, several devices run to share the same interrupt. If you need to share, specify
Sharing Mode. Definition of system-provided request_irq () call:
Int request_irq (unsigned int IRQ,
Void (* Handler) (int irq, void * dev_id, struct pt_regs * regs ),
Unsigned long irqflags,
Const char * devname,
Void * dev_id );
If the sharing is interrupted, irqflags sets the sa_shirq attribute so that other devices can apply for the same
Interrupted. Note that the owner must be set for all devices that use this interrupt when calling request_irq ().
. When the system calls back each interrupt handler, you can use the dev_id parameter to find the corresponding device. I
Dev_id is set to the device structure itself. When the system processes shared interruptions, it uses the respective dev_id parameters to adjust them in sequence.
Use each interrupt handler.

3.2 handling of busy hardware sending
The processing capability of the master CPU is generally faster than that of the network.
The last packet of data network devices has not been delivered yet. In Linux, network device drivers generally do not contain data.
Cache, the data that cannot be sent is a notification that the system fails to send the data, so there must be a mechanism in the hardware does not
When you are busy, notify the system to send the following data in a timely manner.
Generally, the handling of busy sending has been described in the sending method (hard_start_xmit) of the previous device,
That is, if the message is too busy, set tbusy to 1. After processing the sent data, clear tbusy In the interrupted sending.
Use mark_bh () to call the notification system to continue sending.
However, when implementing my driver, I found that such a processing system does not seem to be able to know the hard
The system will wait for a while after mark_bh. Cause sending
Low efficiency. The usage of 2 m lines is less than 10%. The kernel version is 2.0.35.
My final implementation is not to set tbusy to 1, so that the system always considers the hardware idle, but the report cannot be sent
. The system will always try again. In this way, the processing will run normally. But the network drive in the kernel source code
It does not seem like this. I don't know where the problem is.

3.3 Flow Control)
Traffic control is required for sending and receiving network data. These controls are implemented in the system and are not required.
The driver does the work. Each device data structure has a parameter Dev-> tx_queue_len, which
Indicates the maximum number of cached data packets sent. Ethernet device (10/100 Mbps) in Linux)
Tx_queue_len is generally set to 100, and the serial line (asynchronous serial port) is 10. In fact, if you look at the source code, you can
You know, setting Dev-> tx_queue_len does not apply for space to cache the data. This parameter is only
When receiving a packet from the protocol layer, determine whether the data in the sending queue has reached the limit of tx_queue_len,
To determine whether this package of data is added to the sending queue. Another aspect of traffic control during sending is higher-level protocol sending.
Send window (there is a send window in the TCP protocol ). When the window size is reached, the high-level protocol will not send data again.
The receiving traffic control is also divided into two levels. There are limits on the cached data packets of netif_rx. In addition, the high-level agreement will also
There is a maximum amount of data waiting for processing.

Sending and receiving traffic control processes do_dev_queue_xmit () and netif_rx () in net/CORE/dev. C ()
.

3.4 debugging
Many Linux drivers are compiled into the kernel to form a large Kernel File. But for debugging
This is quite troublesome. You can use the module method to debug the driver. Supported modules
The driver must provide two functions: int init_module (void) and void cleanup_module (void ).
Init_module () is called when this module is loaded. In this function, you can register register_netdev ().
Device. If init_module () is returned, 0 indicates success, and negative indicates failure. Cleanup_module () in the driver
The unregister_netdev () API is called when the program is uninstalled ().
The module can be dynamically loaded and detached. In version 2.0.xx, there is also the automatic loading module of kerneld,
But kerneld has been canceled in 2.2.xx. Manually run the insmod command and uninstall the rmmod command,
Use the lsmod command to view the modules in the kernel.
Compile the driver using GCC, the main command line parameter-dkernel-dmodule. Load as a module
To compile the program in the OBJ format (with the-C parameter ). Place the compiled target file in/lib/modules
In/2.x. XX/MISC, use insmod to load the file.

4. Further reading
Linux program design materials can be obtained from the Internet. This is the benefit of open source code. And no
"Undisclosed secrets ". The main materials I read when writing the driver include:
Linux kernel source code
<> By Michael K. Johnson
<> By Ori pomerantz
<> By Olly in BBS, you can select a template as the Start Node. the source code of the kernel contains a template for the network driver,
Drivers/NET/skeleton. C. Contains the basic content of the driver. However, this template is based on the Ethernet
For network devices, Ethernet processing has special "treatment" in Linux.
Refer device. Pay attention to some details, mainly in the initialization program.
Finally, it is probably the most effective help to listen to the experiences of other developers by referring to programs written by others.
.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.