📄 ethdrv.sgml
字号:
</variablelist><para>This function should return zero if the specified operation wascompleted successfully. It should return non-zero if the operationcould not be performed, for any reason.</para></sect2><sect2 id="io-eth-drv-api-can-send"><title>Can-send function</title><para><programlisting>static int <replaceable>HRDWR</replaceable>_can_send(struct eth_drv_sc *sc)</programlisting>This function is called to determine if it is possible to start thetransmission of a packet on the interface. Some interfaces will allowmultiple packets to be "queued" and this function allows for the highestpossible utilization of that mode.</para><para>Return the number of packets which could be accepted at this time, zeroimplies that the interface is saturated/busy.</para></sect2><sect2 id="io-eth-drv-api-send"><title>Send function</title><para><programlisting>struct eth_drv_sg { CYG_ADDRESS buf; CYG_ADDRWORD len;};static void<replaceable>HRDWR</replaceable>_send( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key)</programlisting>This function is used to send a packet of data to the network. It isthe responsibility of this function to somehow hand the data over to thehardware interface. This will most likely require copying, but just theaddress/length values could be used by smart hardware.</para><note><para>All data in/out of the driver is specified via a“scatter-gather”list. This is just an array of address/length pairs which describesections of data to move (in the order given by the array), as in the<type>struct eth_drv_sg</type> defined above and pointed to by<parameter>sg_list</parameter>.</para></note><para>Once the data has been successfully sent by the interface (or if anerror occurs), the driver should call<function>(sc->funs->eth_drv->tx_done)()</function>(see <xref linkend=io-eth-drv-tx-done>)using the specified <parameter>key</parameter>.Only then will the upper layers release the resourcesfor that packet and start another transmission.</para><note><para>In future, this function may be extended so that the data need not becopied by having the function return a “disposition” code(done, send pending, etc). At this point, you should move the data to some“safe” location before returning.</para></note></sect2><sect2 id="io-eth-drv-api-deliver"><title>Deliver function</title><para><programlisting>static void<replaceable>HRDWR</replaceable>_deliver(struct eth_drv_sc *sc)</programlisting>This function is called from the “Network Delivery Thread” inorder to let the device driver do the time-consuming work associated withreceiving a packet — usually copying the entire packet from thehardware or a special memory location into the network stack's memory.</para><para>After handling any outstanding incoming packets or pending transmissionstatus, it can unmask the device's interrupts, and free any relevantresources so it can process further packets.</para><para>It will be called when the interrupt handler for the network devicehas called<programlisting> eth_drv_dsr( vector, count, (cyg_addrword_t)sc );</programlisting>to alert the system that “something requires attention.”This <function>eth_drv_dsr()</function> call must occur from within theinterrupt handler's DSR (not the ISR) or actually <emphasis>be</emphasis>the DSR, whenever it is determined thatthe device needs attention from the foreground. The third parameter(<parameter>data</parameter> in the prototype of<function>eth_drv_dsr()</function> <emphasis>must</emphasis>be a valid <type>struct eth_drv_sc</type> pointer <varname>sc</varname>.</para><para>The reason for this slightly convoluted train of events is to keep the DSR(and ISR) execution time as short as possible, so that other activities ofhigher priority than network servicing are not denied the CPU by networktraffic.</para><para>To deliver a newly-received packet into the network stack, the deliverroutine must call<programlisting>(sc->funs->eth_drv->recv)(sc, len);</programlisting>which will in turn call the receive function, which we talk about next.See also <xref linkend=io-eth-drv-upper-recv> below.</para></sect2><sect2 id="io-eth-drv-api-recv"><title>Receive function</title><para><programlisting>static void<replaceable>HRDWR</replaceable>_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)</programlisting>This function is a call back, only invoked after theupper-level function<programlisting>(sc->funs->eth_drv->recv)(struct eth_drv_sc *sc, int total_len)</programlisting>has been called itself from your deliver function when it knows that apacket of data is available on theinterface. The <function>(sc->funs->eth_drv->recv)()</function>function then arranges network buffersand structures for the data and then calls<function><replaceable>HRDWR</replaceable>_recv()</function> to actuallymove the data from the interface.</para><para>A scatter-gather list (<type>struct eth_drv_sg</type>) is used once more,just like in the send case.</para></sect2><sect2 id="io-eth-drv-api-poll"><title>Poll function</title><para><programlisting>static void<replaceable>HRDWR</replaceable>_poll(struct eth_drv_sc *sc)</programlisting>This function is used when in a non-interrupt driven system, e.g. wheninterrupts are completely disabled. This allows the driver time to checkwhether anything needs doing either for transmission, or to check ifanything has been received, or if any other processing needs doing.</para><para>It is perfectly correct and acceptable for the poll function to look likethis:<programlisting>static void<replaceable>HRDWR</replaceable>_poll(struct eth_drv_sc *sc){ <replaceable>my_interrupt_ISR</replaceable>(sc); <replaceable>HRDWR</replaceable>_deliver(struct eth_drv_sc *sc);}</programlisting>provided that both the ISR and the deliver functions are idempotent andharmless if called when there is no attention needed by the hardware. Somedevices might not need a call to the ISR here if the deliver functioncontains all the “intelligence.”</para></sect2><sect2 id="io-eth-drv-api-int-vector"><title>Interrupt-vector function</title><para><programlisting>static int<replaceable>HRDWR</replaceable>_int_vector(struct eth_drv_sc *sc)</programlisting>This function returns the interrupt vector number used for receiveinterrupts.This is so that the common GDB stubs can detect when to checkfor incoming “CTRL-C” packets (used to asynchronouslyhalt the application) when debugging over ethernet.The GDB stubs need to know which interrupt the ethernet device usesso that they can mask or unmask that interrupt as required.</para></sect2></sect1><sect1 id=io-eth-drv-upper-api><title>Upper Layer Functions</title><para>Upper layer functions are called by drivers to deliver received packetsor transmission completion status back up into the network stack.</para><para>These functions are defined by the hardware independent upper layers ofthe networking driver support. They are present to hide the interfacesto the actual networking stack so that the hardware drivers maybe used by different network stack implementations without change.</para><para>These functions require a pointer to a <type>struct eth_drv_sc</type>which describes the interface at a logical level. It is assumed that thelow level hardware driver will keep track of this pointer soit may be passed “up” as appropriate.</para><sect2 id="io-eth-drv-upper-init"><title>Callback Init function</title><para><programlisting>void (sc->funs->eth_drv->init)( struct eth_drv_sc *sc, unsigned char *enaddr)</programlisting>This function establishes the device at initialization time.It should be called once per device instance only, from theinitialization function, if all is well(see <xref linkend=io-eth-drv-api-init>).The hardware should be totally initialized(<emphasis>not</emphasis> “started”)when this function is called.</para></sect2><sect2 id="io-eth-drv-tx-done"><title>Callback Tx-Done function</title><para><programlisting>void (sc->funs->eth_drv->tx_done)( struct eth_drv_sc *sc, unsigned long key, int status)</programlisting>This function is called when a packet completes transmission on theinterface. The <parameter>key</parameter>value must be one of the keys provided to<function><replaceable>HRDWR</replaceable>_send()</function>above. The value <parameter>status</parameter> should be non-zero(details currently undefined) to indicate that an error occurred during thetransmission, and zero if all was well.</para><para>It should be called from the deliver function(see <xref linkend=io-eth-drv-api-deliver>)or poll function(see <xref linkend=io-eth-drv-api-poll>).</para></sect2><sect2 id="io-eth-drv-upper-recv"><title>Callback Receive function</title><para><programlisting>void (sc->funs->eth_drv->recv)(struct eth_drv_sc *sc, int len)</programlisting>This function is called to indicate that a packet of length<parameter>len</parameter> hasarrived at the interface.The callback<function><replaceable>HRDWR</replaceable>_recv()</function> functiondescribed above will be used to actually unload the data from theinterface into buffers used by the device independent layers.</para><para>It should be called from the deliver function(see <xref linkend=io-eth-drv-api-deliver>)or poll function(see <xref linkend=io-eth-drv-api-poll>).</para></sect2></sect1><sect1 id=io-eth-call-graph><title>Calling graph for Transmission and Reception</title><para>It may be worth clarifying further the flow of control in the transmit andreceive cases, where the hardware driver does use interrupts and so DSRs totell the “foreground” when something asynchronous has occurred.</para><sect2 id=io-eth-call-graph-tx><title>Transmission</title><orderedlist><listitem><para>Some foreground task such as the application, SNMP “daemon”,DHCP management thread or whatever, calls into network stack to send apacket, or the stack decides to send a packet in response to incomingtraffic such as a “ping” or <acronym>ARP</acronym> request.</para></listitem><listitem><para>The driver calls the<function><replaceable>HRDWR</replaceable>_can_send()</function>function in the hardware driver.</para></listitem><listitem><para><function><replaceable>HRDWR</replaceable>_can_send()</function>returns the number of available "slots" in which itcan store a pending transmit packet.If it cannot send at this time, the packet is queued outside thehardware driver for later; in this case, the hardware is already busytransmitting, so expect an interrupt as described below for completionof the packet currently outgoing.</para></listitem><listitem><para>If it can send right now, <replaceable>HRDWR</replaceable>_send() is called.<function><replaceable>HRDWR</replaceable>_send()</function> copies thedata into special hardware buffers, or instructs the hardware to“send that.” It also remembers the key that is associated withthis tx request.</para></listitem><listitem><para>These calls return … time passes …</para></listitem><listitem><para>Asynchronously, the hardware makes an interrupt to say“transmit is done.”The ISR quietens the interrupt source in the hardware andrequests that the associated DSR be run.</para></listitem><listitem><para>The DSR calls (or <emphasis>is</emphasis>) the<function>eth_drv_dsr()</function> function in the generic driver.</para></listitem><listitem><para><function>eth_drv_dsr()</function> in the generic driver awakens the“Network Delivery Thread” which calls the deliver function<replaceable>HRDWR</replaceable>_deliver() in the driver.</para></listitem><listitem><para>The deliver function realizes that a transmit request has completed,and calls the callback tx-done function<function>(sc->funs->eth_drv->tx_done)()</function>with the same key that it remembered for this tx.</para></listitem><listitem><para>The callback tx-done functionuses the key to find the resources associated withthis transmit request; thus the stack knows that the transmit hascompleted and its resources can be freed.</para></listitem><listitem><para>The callback tx-done functionalso enquires whether <replaceable>HRDWR</replaceable>_can_send() now says“yes, we can send”and if so, dequeues a further transmit requestwhich may have been queued as described above. If so, then<replaceable>HRDWR</replaceable>_send() copies the data into the hardware buffers, orinstructs the hardware to "send that" and remembers the new key, as above.These calls then all return to the “Network Delivery Thread”which then sleeps, awaiting the next asynchronous event.</para></listitem><listitem><para>All done …</para></listitem></orderedlist></sect2><sect2 id=io-eth-call-graph-rx><title>Receive</title><orderedlist><listitem><para>Asynchronously, the hardware makes an interrupt to say“there is ready data in a receive buffer.”The ISR quietens the interrupt source in the hardware andrequests that the associated DSR be run.</para></listitem><listitem><para>The DSR calls (or <emphasis>is</emphasis>) the<function>eth_drv_dsr()</function> function in the generic driver.</para></listitem><listitem><para><function>eth_drv_dsr()</function> in the generic driver awakens the“Network Delivery Thread” which calls the deliver function<replaceable>HRDWR</replaceable>_deliver() in the driver.</para></listitem><listitem><para>The deliver function realizes that there is data ready and callsthe callback receive function<function>(sc->funs->eth_drv->recv)()</function>to tell it how many bytes to prepare for.</para></listitem><listitem><para>The callback receive function allocates memory within the stack(eg. <type>MBUFs</type> in BSD/Unix style stacks) and preparesa set of scatter-gather buffers that canaccommodate the packet.</para></listitem><listitem><para>It then calls back into the hardware driver routine<replaceable>HRDWR</replaceable>_recv().<replaceable>HRDWR</replaceable>_recv() must copy the data from thehardware's buffers into the scatter-gather buffers provided, and return.</para></listitem><listitem><para>The network stack now has the data in-hand, and does with it what it will.This might include recursive calls to transmit a response packet.When this all is done, these calls return, and the“Network Delivery Thread”sleeps once more, awaiting the next asynchronous event.</para></listitem></orderedlist></sect2></sect1></chapter></part>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -