OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [eth/] [v2_0/] [doc/] [driver_doc] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
This file provides a simple description of how to write a low-level,
2
hardware dependent ethernet driver.
3
 
4
The basic idea is that there is a high-level driver (which is only
5
code/functions) that is part of the stack.  There will be one or more
6
low-level driver tied to the actual network hardware.  Each of these
7
drivers contains one or more driver instances.  The principal idea is
8
that the low-level drivers know nothing of the details of the stack that
9
will be using them.  Thus, the same driver can be used by the eCos
10
supported TCP/IP stack, or any other, with no changes.
11
 
12
A driver instance is contained within a "struct eth_drv_sc".
13
 
14
   struct eth_hwr_funs {
15
      // Initialize hardware (including startup)
16
      void (*start)(struct eth_drv_sc *sc,
17
                    unsigned char *enaddr);
18
      // Shut down hardware
19
      void (*stop)(struct eth_drv_sc *sc);
20
      // Control interface
21
      int (*control)(struct eth_drv_sc *sc,
22
                     unsigned long cmd,
23
                     void *data,
24
                     int len);
25
      // Query interface - can a packet be sent?
26
      int (*can_send)(struct eth_drv_sc *sc);
27
      // Send a packet of data
28
      void (*send)(struct eth_drv_sc *sc,
29
                   struct eth_drv_sg *sg_list,
30
                   int sg_len,
31
                   int total_len,
32
                   unsigned long key);
33
      // Receive [unload] a packet of data
34
      void (*recv)(struct eth_drv_sc *sc,
35
                   struct eth_drv_sg *sg_list,
36
                   int sg_len);
37
      // Deliver data to/from device from/to stack memory space
38
      // (moves lots of memcpy()s out of DSRs into thread)
39
      void (*deliver)(struct eth_drv_sc *sc);
40
      // Poll for interrupts/device service
41
      void (*poll)(struct eth_drv_sc *sc);
42
      // Get interrupt information from hardware driver
43
      int (*int_vector)(struct eth_drv_sc *sc);
44
      // Logical driver interface
45
      struct eth_drv_funs *eth_drv, *eth_drv_old;
46
  };
47
 
48
  struct eth_drv_sc {
49
      struct eth_hwr_funs *funs;
50
      void                *driver_private;
51
      const char          *dev_name;
52
      struct arpcom       sc_arpcom; /* ethernet common */
53
  };
54
 
55
You create one of these instances using the "ETH_DRV_SC()" macro which
56
sets up the structure, including the prototypes for the functions, etc.
57
By doing things this way, if the internal design of the ethernet drivers
58
changes (e.g. we need to add a new low-level implementation function),
59
existing drivers will no longer compile until updated.  This is much
60
better than to have all of the definitions in the low-level drivers
61
themselves and have them be [quietly] broken if the interfaces change.
62
 
63
The "magic" which gets the drivers started [and indeed, linked] is
64
similar to what is used for the I/O subsystem. [Note: I may try and
65
make it part of the I/O subsystem later.]  This is done using the
66
"NETDEVTAB_ENTRY()" macro, which defines an initialization function
67
and the basic data structures for the low-level driver.
68
 
69
  typedef struct cyg_netdevtab_entry {
70
      const char        *name;
71
      bool             (*init)(struct cyg_netdevtab_entry *tab);
72
      void              *device_instance;
73
      unsigned long     status;
74
  } cyg_netdevtab_entry_t;
75
 
76
The "device_instance" entry here would point to the "struct
77
eth_drv_sc" entry previously defined.  This allows the network driver
78
setup to work with any class of driver, not just ethernet drivers.  In
79
the future, there will surely be serial PPP drivers, etc.  These will
80
use the "NETDEVTAB" setup to create the basic driver, but they will
81
most likely be built on top of other high-level device driver layers.
82
 
83
So, the bottom line is that a hardware driver will have a template
84
(boilerplate) which looks like this:
85
 
86
        #include 
87
        #include 
88
        #include 
89
        #include 
90
        #include 
91
        #include 
92
 
93
        ETH_DRV_SC(DRV_sc,
94
                   0,             // No driver specific data needed
95
                   "eth0",        // Name for this interface
96
                   HRDWR_start,
97
                   HRDWR_stop,
98
                   HRDWR_control,
99
                   HRDWR_can_send
100
                   HRDWR_send,
101
                   HRDWR_recv);
102
 
103
        NETDEVTAB_ENTRY(DRV_netdev,
104
                        "DRV",
105
                        DRV_HRDWR_init,
106
                        &DRV_sc);
107
 
108
This, along with the referenced functions, completely define the driver.
109
Extensibility note: if one needed the same low-level driver to handle
110
multiple similar hardware interfaces, you would need multiple invocations
111
of the "ETH_DRV_SC()/NETDEVTAB_ENTRY()" macros.  You would add a pointer
112
to some instance specific data, e.g. containing base addresses, interrupt
113
numbers, etc, where the "0, // No driver specific data" is currently.
114
 
115
Now a quick waltz through the functions.  This discussion will use the
116
generic names from above.
117
 
118
static bool DRV_HDWR_init(struct cyg_netdevtab_entry *tab)
119
==========================================================
120
 
121
This function is called as part of system initialization.  Its primary
122
function is to decide if the hardware [as indicated via
123
tab->device_instance] is working and if the interface needs to be made
124
available in the system.  If this is the case, this function needs to
125
finish with a call to the ethernet driver function:
126
 
127
        eth_drv_init((struct eth_drv_sc *)tab->device_instance,
128
                     unsigned char *enaddr);
129
 
130
where 'enaddr' is a pointer to the ethernet station address for this
131
unit.  Note: the ethernet station address is supposed to be a
132
world-unique, 48 bit address for this particular ethernet interface.
133
Typically it is provided by the board/hardware manufacturer in ROM.
134
 
135
In many packages it is possible for the ESA to be set from RedBoot,
136
(perhaps from 'fconfig' data), hard-coded from CDL, or from an EPROM.
137
A driver should choose a run-time specified ESA (e.g. from RedBoot)
138
preferentially, otherwise (in order) it should use a CDL specified
139
ESA if one has been set, otherwise an EPROM set ESA, or otherwise
140
fail. See the cl/cs8900a eth driver for an example.
141
 
142
static void
143
HRDWR_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
144
====================================================================
145
 
146
This function is called, perhaps much later than system initialization
147
time, when the system (an application) is ready for the interface to
148
become active.  The purpose of this function is to set up the hardware
149
interface to start accepting packets from the network and be able to
150
send packets out.  Note: this function will be called whenever the
151
up/down state of the logical interface changes, e.g. when the IP address
152
changes.  This may occur more than one time, so this function needs to
153
be prepared for that case.
154
 
155
FUTURE: the "flags" field (currently unused) may be used to tell the
156
function how to start up, e.g. whether interrupts will be used,
157
selection of "promiscuous" mode etc.
158
 
159
static void HRDWR_stop(struct eth_drv_sc *sc)
160
=============================================
161
 
162
This function is the inverse of "start".  It should shut down the
163
hardware and keep it from interacting with the physical network.
164
 
165
static int
166
HRDWR_control(struct eth_drv_sc *sc, unsigned long key, void *data, int len)
167
============================================================================
168
 
169
This function is used to perform low-level "control" operations on the
170
interface.  These operations would be initiated via 'ioctl()' in the BSD
171
stack, and would be anything that would require the hardware setup to
172
possibly change (i.e.  cannot be performed totally by the
173
platform-independent layers).
174
 
175
Current operations:
176
 
177
ETH_DRV_SET_MAC_ADDRESS:
178
  This function sets the ethernet station address (ESA or MAC) for the
179
  device.  Normally this address is kept in non-volatile memory and is
180
  unique in the world.  This function must at least set the interface to
181
  use the new address.  It may also update the NVM as appropriate.
182
 
183
This function should return zero if the specified operation was
184
completed successfully.  It should return non-zero if the operation
185
could not be performed, for any reason.
186
 
187
static int HRDWR_can_send(struct eth_drv_sc *sc)
188
================================================
189
 
190
This function is called to determine if it is possible to start the
191
transmission of a packet on the interface.  Some interfaces will allow
192
multiple packets to be "queued" and this function allows for the highest
193
possible utilization of that mode.
194
 
195
Return the number of packets which could be accepted at this time, zero
196
implies that the interface is saturated/busy.
197
 
198
static void
199
HRDWR_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
200
                       int total_len, unsigned long key)
201
=========================================================================
202
 
203
This function is used to send a packet of data to the network.  It is
204
the responsibility of this function to somehow hand the data over to the
205
hardware interface.  This will most likely require copying, but just the
206
address/length values could be used by smart hardware.
207
 
208
NOTE: All data in/out of the driver is specified via a "scatter-gather"
209
list.  This is just an array of address/length pairs which describe
210
sections of data to move (in the order given by the array).
211
 
212
Once the data has been successfully sent by the interface (or if an
213
error occurs), the driver should call 'eth_drv_tx_done()' using the
214
specified 'key'.  Only then will the upper layers release the resources
215
for that packet and start another transmission.
216
 
217
FUTURE: This function may be extended so that the data need not be
218
copied by having the function return a "disposition" code (done, send
219
pending, etc).  At this point, you should move the data to some "safe"
220
location before returning.
221
 
222
static void
223
HRDWR_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
224
=========================================================================
225
 
226
This function is actually a call back, only invoked after the
227
upper-level function
228
  eth_drv_recv(struct eth_drv_sc *sc, int total_len)
229
has been called.  This upper level function is called by the hardware
230
driver when it knows that a packet of data is available on the
231
interface.  The 'eth_drv_recv()' function then arranges network buffers
232
and structures for the data and then calls "HRDWR_recv()" to actually
233
move the data from the interface.
234
 
235
static void
236
HRDWR_deliver(struct eth_drv_sc *sc)
237
=========================================================================
238
 
239
This function is actually a call back, and notifies the driver that delivery
240
is happening. This allows it to actually do the copy of packet data to/from
241
the hardware from/to the packet buffer. And once that's done, then do things
242
like unmask its interrupts, and free any relevant resources so it can process
243
further packets.
244
 
245
In general it will be called from the user thread responsible for delivering
246
network packets.
247
 
248
static void
249
HRDWR_poll(struct eth_drv_sc *sc)
250
=========================================================================
251
 
252
This function is used when in a non-interrupt driven system, e.g. when
253
interrupts are completely disabled. This allows the driver time to check
254
whether anything needs doing either for transmission, or to check if
255
anything has been received, or if any other processing needs doing..
256
 
257
static int
258
HRDWR_int_vector(struct eth_drv_sc *sc)
259
=========================================================================
260
 
261
This function returns the interrupt vector number used for RX interrupts.
262
This is so the common GDB stubs infrastructure can detect when to check
263
for incoming ctrl-c's when doing debugging over ethernet.
264
 
265
Upper layer functions - called by drivers
266
=========================================
267
 
268
These functions are defined by the upper layers (machine independent) of
269
the networking driver support.  They are present to hide the interfaces
270
to the actual networking stack so that the hardware drivers may possibly
271
be used by any network stack implementation.
272
 
273
These functions require a pointer to a "struct eth_drv_sc" table which
274
describes the interface at a logical level.  It is assumed that the
275
driver [lowest level hardware support] will keep track of this pointer
276
so it may be passed "up" as appropriate.
277
 
278
  struct eth_drv_sc {
279
      struct eth_drv_funs *funs; // Pointer to hardware functions (see above)
280
      void                *driver_private;   // Device specific data
281
      const char          *dev_name;
282
      struct arpcom       sc_arpcom; // ethernet common
283
  };
284
 
285
This structure is created, one per logical interface, via ETH_DRV_SC macro.
286
 
287
void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
288
===============================================================
289
 
290
This function establishes the device at initialization time.  The
291
hardware should be totally intialized (not "started") when this function
292
is called.
293
 
294
void eth_drv_tx_done(struct eth_drv_sc *sc, unsigned long key, int status)
295
==========================================================================
296
 
297
This function is called when a packet completes transmission on the
298
interface.  The 'key' value must be one of the keys provided to
299
"HRDWR_send()" above.  The value 'status' should be non-zero (currently
300
undefined) to indicate that an error occurred during the transmission.
301
 
302
void eth_drv_recv(struct eth_drv_sc *sc, int len)
303
=================================================
304
 
305
This function is called to indicate that a packet of length 'len' has
306
arrived at the interface.  The callback "HRDWR_recv()" function
307
described above will be used to actually unload the data from the
308
interface into buffers used by the machine independent layers.
309
 
310
 
311
 
312
Calling graph for Transmit and Receive
313
--------------------------------------
314
 
315
It may be worth clarifying further the flow of control in the transmit
316
and receive cases, where the hardware driver does use interrupts and so
317
DSRs to tell the "foreground" when something asynchronous has occurred.
318
 
319
Transmit:
320
  Foreground task calls into network stack to send a packet (or the
321
  stack decides to send a packet in response to incoming traffic).
322
  The driver calls the HRDWR_can_send() function in the hardware driver.
323
    HRDWR_can_send() returns the number of available "slots" in which it
324
    can store a pending transmit packet.
325
  If it cannot send at this time, the packet is queued outside the
326
  hardware driver for later; in this case, the hardware is already busy
327
  transmitting, so expect an interrupt as described below for completion
328
  of the packet currently outgoing.
329
  If it can send right now, HRDWR_send() is called.
330
    HRDWR_send() copies the data into special hardware buffers, or
331
    instructs the hardware to "send that".
332
    It also remembers the key that is associated with this tx request.
333
  these calls return.
334
  ...
335
 
336
  Asynchronously, the hardware makes an interrupt to say "transmit is
337
  done"; the ISR quietens the interrupt source in the hardware and
338
  requests that the associated DSR be run.
339
  The DSR realizes that a transmit request has completed, and calls
340
  eth_drv_tx_done() with the same key that it remembered for this tx.
341
    eth_drv_tx_done() uses the key to find the resources associated with
342
    this transmit request; thus the stack knows that the transmit has
343
    completed and its resources can be freed.
344
    eth_drv_tx_done() also enquires whether HRDWR_can_send() now says
345
    "yes, we can send" and if so, dequeues a further transmit request
346
    which may have been queued as described above.  If so:
347
      HRDWR_send() copies the data into the hardware buffers, or
348
      instructs the hardware to "send that" and remembers the new key.
349
  these calls return to the DSR and thus to the foreground.
350
  ...
351
 
352
 
353
Receive:
354
  ...
355
 
356
  Asynchronously, the hardware makes an interrupt to say "there is ready
357
  data in a receive buffer"; the ISR quietens the interrupt source in
358
  the hardware and requests that the associated DSR be run.
359
  The DSR realizes that there is data ready and calls eth_drv_recv()
360
  with the length of the data that is available.
361
    eth_drv_recv() prepares a set of scatter-gather buffers that can
362
    accommodate that data.
363
    It then calls back into the hardware driver routine HRDWR_recv().
364
       HRDWR_recv() must copy the data from the hardware's buffers into
365
       the scatter-gather buffers provided, and return.
366
    eth_drv_recv() sends the new packet up the network stack and returns.
367
  Back in the DSR now, the driver cleans the receive buffer and returns
368
  it to the hardware's control, available to receive another packet from
369
  the network.
370
  The DSR returns to the foreground.
371
  ...
372
 
373
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.