1 | .. comment SPDX-License-Identifier: CC-BY-SA-4.0 |
---|
2 | |
---|
3 | .. COMMENT: Written by Eric Norum |
---|
4 | .. COMMENT: COPYRIGHT (c) 1988-2002. |
---|
5 | .. COMMENT: On-Line Applications Research Corporation (OAR). |
---|
6 | .. COMMENT: All rights reserved. |
---|
7 | |
---|
8 | Networking Driver |
---|
9 | ################# |
---|
10 | |
---|
11 | Introduction |
---|
12 | ============ |
---|
13 | |
---|
14 | This chapter is intended to provide an introduction to the procedure for |
---|
15 | writing RTEMS network device drivers. The example code is taken from the |
---|
16 | 'Generic 68360' network device driver. The source code for this driver is |
---|
17 | located in the :file:`c/src/lib/libbsp/m68k/gen68360/network` directory in the |
---|
18 | RTEMS source code distribution. Having a copy of this driver at hand when |
---|
19 | reading the following notes will help significantly. |
---|
20 | |
---|
21 | Learn about the network device |
---|
22 | ============================== |
---|
23 | |
---|
24 | Before starting to write the network driver become completely familiar with the |
---|
25 | programmer's view of the device. The following points list some of the details |
---|
26 | of the device that must be understood before a driver can be written. |
---|
27 | |
---|
28 | - Does the device use DMA to transfer packets to and from memory or does the |
---|
29 | processor have to copy packets to and from memory on the device? |
---|
30 | |
---|
31 | - If the device uses DMA, is it capable of forming a single outgoing packet |
---|
32 | from multiple fragments scattered in separate memory buffers? |
---|
33 | |
---|
34 | - If the device uses DMA, is it capable of chaining multiple outgoing packets, |
---|
35 | or does each outgoing packet require intervention by the driver? |
---|
36 | |
---|
37 | - Does the device automatically pad short frames to the minimum 64 bytes or |
---|
38 | does the driver have to supply the padding? |
---|
39 | |
---|
40 | - Does the device automatically retry a transmission on detection of a |
---|
41 | collision? |
---|
42 | |
---|
43 | - If the device uses DMA, is it capable of buffering multiple packets to |
---|
44 | memory, or does the receiver have to be restarted after the arrival of each |
---|
45 | packet? |
---|
46 | |
---|
47 | - How are packets that are too short, too long, or received with CRC errors |
---|
48 | handled? Does the device automatically continue reception or does the driver |
---|
49 | have to intervene? |
---|
50 | |
---|
51 | - How is the device Ethernet address set? How is the device programmed to |
---|
52 | accept or reject broadcast and multicast packets? |
---|
53 | |
---|
54 | - What interrupts does the device generate? Does it generate an interrupt for |
---|
55 | each incoming packet, or only for packets received without error? Does it |
---|
56 | generate an interrupt for each packet transmitted, or only when the transmit |
---|
57 | queue is empty? What happens when a transmit error is detected? |
---|
58 | |
---|
59 | In addition, some controllers have specific questions regarding board specific |
---|
60 | configuration. For example, the SONIC Ethernet controller has a very |
---|
61 | configurable data bus interface. It can even be configured for sixteen and |
---|
62 | thirty-two bit data buses. This type of information should be obtained from |
---|
63 | the board vendor. |
---|
64 | |
---|
65 | Understand the network scheduling conventions |
---|
66 | ============================================= |
---|
67 | |
---|
68 | When writing code for the driver transmit and receive tasks, take care to |
---|
69 | follow the network scheduling conventions. All tasks which are associated with |
---|
70 | networking share various data structures and resources. To ensure the |
---|
71 | consistency of these structures the tasks execute only when they hold the |
---|
72 | network semaphore (``rtems_bsdnet_semaphore``). The transmit and receive tasks |
---|
73 | must abide by this protocol. Be very careful to avoid 'deadly embraces' with |
---|
74 | the other network tasks. A number of routines are provided to make it easier |
---|
75 | for the network driver code to conform to the network task scheduling |
---|
76 | conventions. |
---|
77 | |
---|
78 | - ``void rtems_bsdnet_semaphore_release(void)`` |
---|
79 | This function releases the network semaphore. The network driver tasks must |
---|
80 | call this function immediately before making any blocking RTEMS request. |
---|
81 | |
---|
82 | - ``void rtems_bsdnet_semaphore_obtain(void)`` |
---|
83 | This function obtains the network semaphore. If a network driver task has |
---|
84 | released the network semaphore to allow other network-related tasks to run |
---|
85 | while the task blocks, then this function must be called to reobtain the |
---|
86 | semaphore immediately after the return from the blocking RTEMS request. |
---|
87 | |
---|
88 | - ``rtems_bsdnet_event_receive(rtems_event_set, rtems_option, rtems_interval, rtems_event_set *)`` |
---|
89 | The network driver task should call this function when it wishes to wait for |
---|
90 | an event. This function releases the network semaphore, calls |
---|
91 | ``rtems_event_receive`` to wait for the specified event or events and |
---|
92 | reobtains the semaphore. The value returned is the value returned by the |
---|
93 | ``rtems_event_receive``. |
---|
94 | |
---|
95 | Network Driver Makefile |
---|
96 | ======================= |
---|
97 | |
---|
98 | Network drivers are considered part of the BSD network package and as such are |
---|
99 | to be compiled with the appropriate flags. This can be accomplished by adding |
---|
100 | ``-D__INSIDE_RTEMS_BSD_TCPIP_STACK__`` to the ``command line``. If the driver |
---|
101 | is inside the RTEMS source tree or is built using the RTEMS application |
---|
102 | Makefiles, then adding the following line accomplishes this: |
---|
103 | |
---|
104 | .. code-block:: c |
---|
105 | |
---|
106 | DEFINES += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ |
---|
107 | |
---|
108 | This is equivalent to the following list of definitions. Early versions of the |
---|
109 | RTEMS BSD network stack required that all of these be defined. |
---|
110 | |
---|
111 | .. code-block:: c |
---|
112 | |
---|
113 | -D_COMPILING_BSD_KERNEL_ -DKERNEL -DINET -DNFS \ |
---|
114 | -DDIAGNOSTIC -DBOOTP_COMPAT |
---|
115 | |
---|
116 | Defining these macros tells the network header files that the driver is to be |
---|
117 | compiled with extended visibility into the network stack. This is in sharp |
---|
118 | contrast to applications that simply use the network stack. Applications do |
---|
119 | not require this level of visibility and should stick to the portable |
---|
120 | application level API. |
---|
121 | |
---|
122 | As a direct result of being logically internal to the network stack, network |
---|
123 | drivers use the BSD memory allocation routines This means, for example, that |
---|
124 | malloc takes three arguments. See the SONIC device driver |
---|
125 | (:file:`c/src/lib/libchip/network/sonic.c`) for an example of this. Because of |
---|
126 | this, network drivers should not include ``<stdlib.h>``. Doing so will result |
---|
127 | in conflicting definitions of ``malloc()``. |
---|
128 | |
---|
129 | *Application level* code including network servers such as the FTP daemon are |
---|
130 | *not* part of the BSD kernel network code and should not be compiled with the |
---|
131 | BSD network flags. They should include ``<stdlib.h>`` and not define the |
---|
132 | network stack visibility macros. |
---|
133 | |
---|
134 | Write the Driver Attach Function |
---|
135 | ================================ |
---|
136 | |
---|
137 | The driver attach function is responsible for configuring the driver and making |
---|
138 | the connection between the network stack and the driver. |
---|
139 | |
---|
140 | Driver attach functions take a pointer to an ``rtems_bsdnet_ifconfig`` |
---|
141 | structure as their only argument. and set the driver parameters based on the |
---|
142 | values in this structure. If an entry in the configuration structure is zero |
---|
143 | the attach function chooses an appropriate default value for that parameter. |
---|
144 | |
---|
145 | The driver should then set up several fields in the ifnet structure in the |
---|
146 | device-dependent data structure supplied and maintained by the driver: |
---|
147 | |
---|
148 | ``ifp->if_softc`` |
---|
149 | Pointer to the device-dependent data. The first entry in the |
---|
150 | device-dependent data structure must be an ``arpcom`` structure. |
---|
151 | |
---|
152 | ``ifp->if_name`` |
---|
153 | The name of the device. The network stack uses this string and the device |
---|
154 | number for device name lookups. The device name should be obtained from |
---|
155 | the ``name`` entry in the configuration structure. |
---|
156 | |
---|
157 | ``ifp->if_unit`` |
---|
158 | The device number. The network stack uses this number and the device name |
---|
159 | for device name lookups. For example, if ``ifp->if_name`` is ``scc`` and |
---|
160 | ``ifp->if_unit`` is ``1``, the full device name would be ``scc1``. The |
---|
161 | unit number should be obtained from the 'name' entry in the configuration |
---|
162 | structure. |
---|
163 | |
---|
164 | ``ifp->if_mtu`` |
---|
165 | The maximum transmission unit for the device. For Ethernet devices this |
---|
166 | value should almost always be 1500. |
---|
167 | |
---|
168 | ``ifp->if_flags`` |
---|
169 | The device flags. Ethernet devices should set the flags to |
---|
170 | ``IFF_BROADCAST|IFF_SIMPLEX``, indicating that the device can broadcast |
---|
171 | packets to multiple destinations and does not receive and transmit at the |
---|
172 | same time. |
---|
173 | |
---|
174 | ``ifp->if_snd.ifq_maxlen`` |
---|
175 | The maximum length of the queue of packets waiting to be sent to the |
---|
176 | driver. This is normally set to ``ifqmaxlen``. |
---|
177 | |
---|
178 | ``ifp->if_init`` |
---|
179 | The address of the driver initialization function. |
---|
180 | |
---|
181 | ``ifp->if_start`` |
---|
182 | The address of the driver start function. |
---|
183 | |
---|
184 | ``ifp->if_ioctl`` |
---|
185 | The address of the driver ioctl function. |
---|
186 | |
---|
187 | ``ifp->if_output`` |
---|
188 | The address of the output function. Ethernet devices should set this to |
---|
189 | ``ether_output``. |
---|
190 | |
---|
191 | RTEMS provides a function to parse the driver name in the configuration |
---|
192 | structure into a device name and unit number. |
---|
193 | |
---|
194 | .. code-block:: c |
---|
195 | |
---|
196 | int rtems_bsdnet_parse_driver_name ( |
---|
197 | const struct rtems_bsdnet_ifconfig *config, |
---|
198 | char **namep |
---|
199 | ); |
---|
200 | |
---|
201 | The function takes two arguments; a pointer to the configuration structure and |
---|
202 | a pointer to a pointer to a character. The function parses the configuration |
---|
203 | name entry, allocates memory for the driver name, places the driver name in |
---|
204 | this memory, sets the second argument to point to the name and returns the unit |
---|
205 | number. On error, a message is printed and ``-1`` is returned. |
---|
206 | |
---|
207 | Once the attach function has set up the above entries it must link the driver |
---|
208 | data structure onto the list of devices by calling ``if_attach``. Ethernet |
---|
209 | devices should then call ``ether_ifattach``. Both functions take a pointer to |
---|
210 | the device's ``ifnet`` structure as their only argument. |
---|
211 | |
---|
212 | The attach function should return a non-zero value to indicate that the driver |
---|
213 | has been successfully configured and attached. |
---|
214 | |
---|
215 | Write the Driver Start Function. |
---|
216 | ================================ |
---|
217 | |
---|
218 | This function is called each time the network stack wants to start the |
---|
219 | transmitter. This occures whenever the network stack adds a packet to a |
---|
220 | device's send queue and the ``IFF_OACTIVE`` bit in the device's ``if_flags`` is |
---|
221 | not set. |
---|
222 | |
---|
223 | For many devices this function need only set the ``IFF_OACTIVE`` bit in the |
---|
224 | ``if_flags`` and send an event to the transmit task indicating that a packet is |
---|
225 | in the driver transmit queue. |
---|
226 | |
---|
227 | Write the Driver Initialization Function. |
---|
228 | ========================================= |
---|
229 | |
---|
230 | This function should initialize the device, attach to interrupt handler, and |
---|
231 | start the driver transmit and receive tasks. The function |
---|
232 | |
---|
233 | .. code-block:: c |
---|
234 | |
---|
235 | rtems_id |
---|
236 | rtems_bsdnet_newproc (char *name, |
---|
237 | int stacksize, |
---|
238 | void(*entry)(void *), |
---|
239 | void *arg); |
---|
240 | |
---|
241 | should be used to start the driver tasks. |
---|
242 | |
---|
243 | Note that the network stack may call the driver initialization function more |
---|
244 | than once. Make sure multiple versions of the receive and transmit tasks are |
---|
245 | not accidentally started. |
---|
246 | |
---|
247 | Write the Driver Transmit Task |
---|
248 | ============================== |
---|
249 | |
---|
250 | This task is reponsible for removing packets from the driver send queue and |
---|
251 | sending them to the device. The task should block waiting for an event from |
---|
252 | the driver start function indicating that packets are waiting to be |
---|
253 | transmitted. When the transmit task has drained the driver send queue the task |
---|
254 | should clear the ``IFF_OACTIVE`` bit in ``if_flags`` and block until another |
---|
255 | outgoing packet is queued. |
---|
256 | |
---|
257 | Write the Driver Receive Task |
---|
258 | ============================= |
---|
259 | |
---|
260 | This task should block until a packet arrives from the device. If the device |
---|
261 | is an Ethernet interface the function ``ether_input`` should be called to |
---|
262 | forward the packet to the network stack. The arguments to ``ether_input`` are |
---|
263 | a pointer to the interface data structure, a pointer to the ethernet header and |
---|
264 | a pointer to an mbuf containing the packet itself. |
---|
265 | |
---|
266 | Write the Driver Interrupt Handler |
---|
267 | ================================== |
---|
268 | |
---|
269 | A typical interrupt handler will do nothing more than the hardware manipulation |
---|
270 | required to acknowledge the interrupt and send an RTEMS event to wake up the |
---|
271 | driver receive or transmit task waiting for the event. Network interface |
---|
272 | interrupt handlers must not make any calls to other network routines. |
---|
273 | |
---|
274 | Write the Driver IOCTL Function |
---|
275 | =============================== |
---|
276 | |
---|
277 | This function handles ioctl requests directed at the device. The ioctl |
---|
278 | commands which must be handled are: |
---|
279 | |
---|
280 | ``SIOCGIFADDR`` |
---|
281 | |
---|
282 | ``SIOCSIFADDR`` |
---|
283 | If the device is an Ethernet interface these commands should be passed on |
---|
284 | to ``ether_ioctl``. |
---|
285 | |
---|
286 | ``SIOCSIFFLAGS`` |
---|
287 | This command should be used to start or stop the device, depending on the |
---|
288 | state of the interface ``IFF_UP`` and ``IFF_RUNNING`` bits in ``if_flags``: |
---|
289 | |
---|
290 | ``IFF_RUNNING`` |
---|
291 | Stop the device. |
---|
292 | |
---|
293 | ``IFF_UP`` |
---|
294 | Start the device. |
---|
295 | |
---|
296 | ``IFF_UP|IFF_RUNNING`` |
---|
297 | Stop then start the device. |
---|
298 | |
---|
299 | ``0`` |
---|
300 | Do nothing. |
---|
301 | |
---|
302 | Write the Driver Statistic-Printing Function |
---|
303 | ============================================ |
---|
304 | |
---|
305 | This function should print the values of any statistic/diagnostic counters the |
---|
306 | network driver may use. The driver ioctl function should call the |
---|
307 | statistic-printing function when the ioctl command is ``SIO_RTEMS_SHOW_STATS``. |
---|