source: trunk/hal/tsar_mips32/drivers/soclib_nic.c @ 479

Last change on this file since 479 was 451, checked in by alain, 6 years ago

Fix a bug in soclib_pic driver (bad separation between IOPIC an LAPIC initialisation)

File size: 11.5 KB
Line 
1/*
2 * soclib_nic.c - SOCLIB_NIC (Network Interface Controler) driver implementation.
3 *
4 * Author     Alain Greiner (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH.is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_kernel_types.h>
25#include <hal_remote.h>
26#include <hal_special.h>
27#include <chdev.h>
28#include <dev_nic.h>
29#include <spinlock.h>
30#include <kmem.h>
31#include <printk.h>
32#include <memcpy.h>
33#include <thread.h>
34#include <soclib_nic.h>
35
36///////////////////////////////////////
37void soclib_nic_init( chdev_t * chdev )
38{
39    uint32_t    i;
40    kmem_req_t  req;
41
42    // set driver specific fields in chdev descriptor
43    chdev->cmd = &soclib_nic_cmd;
44    chdev->isr = &soclib_nic_isr;
45   
46    // get hardware device cluster and local pointer
47    cxy_t      nic_cxy  = GET_CXY( chdev->base );
48    uint32_t * nic_ptr  = (uint32_t *)GET_PTR( chdev->base );
49
50    // initialize Soclib NIC global registers
51    hal_remote_sw( XPTR( nic_cxy , nic_ptr + NIC_GLOBAL_SPAN + NIC_G_BC_ENABLE ) , 0 );
52    hal_remote_sw( XPTR( nic_cxy , nic_ptr + NIC_GLOBAL_SPAN + NIC_G_RUN       ) , 0 );
53
54    // allocate memory for chbuf descriptor (one page)
55    assert( (sizeof(nic_chbuf_t) <= CONFIG_PPM_PAGE_SIZE ) , __FUNCTION__ ,
56            "chbuf descriptor exceeds one page" );
57
58    req.type   = KMEM_PAGE;
59    req.size   = 0;
60    req.flags  = AF_KERNEL;
61
62    nic_chbuf_t * chbuf = (nic_chbuf_t *)kmem_alloc( &req );
63
64    assert( (chbuf != NULL) , __FUNCTION__ , 
65             "cannot allocate chbuf descriptor" );
66
67    // initialise chbuf state
68    chbuf->cont_id  = 0;
69    chbuf->pkt_id   = 0;
70    chbuf->word_id  = 34;
71   
72    // allocate containers (one page per container)
73    // and complete chbuf descriptor initialization
74    assert( (CONFIG_PPM_PAGE_SIZE == 4096) , __FUNCTION__ ,
75            "chbuf container must be 4 Kbytes" );
76
77    for( i = 0 ; i < CONFIG_NIC_CHBUF_DEPTH ; i++ )
78    {
79        uint32_t * container = (uint32_t *)kmem_alloc( &req );   
80
81        assert( (container != NULL) , __FUNCTION__ , 
82                "cannot allocate container" );
83       
84        chbuf->cont[i] = container;
85        chbuf->full[i] = (paddr_t)XPTR( local_cxy , container );
86    }
87} // end soclib_nic_init()
88
89
90//////////////////////////////////////////////////////////////////
91void __attribute__ ((noinline)) soclib_nic_cmd( xptr_t thread_xp )
92{
93    uint32_t       cmd;          // command type   
94    char         * buffer;       // pointer on command buffer   
95    uint32_t       length;       // Ethernet packet length
96    xptr_t         dev_xp;       // extended pointer on NIC device
97    nic_chbuf_t  * chbuf;        // pointer on chbuf descriptor
98    uint32_t       cont_id;      // index of current container in chbuf
99    uint32_t       pkt_id;       // index of current packet in container
100    uint32_t       word_id;      // index of first word of current packet in container
101    uint32_t     * container;    // pointer on container (array of uint32_t)
102    uint16_t     * header;       // pointer on container header (array of uint16_t)
103    uint32_t       npackets;     // number of packets in current container
104
105    // get local pointer for client thread
106    thread_t * thread_ptr = (thread_t *)GET_PTR( thread_xp );
107
108    // get command arguments
109    cmd    = thread_ptr->nic_cmd.cmd;
110    buffer = thread_ptr->nic_cmd.buffer;
111    length = thread_ptr->nic_cmd.length;
112    dev_xp = thread_ptr->nic_cmd.dev_xp;
113
114    // get local pointer for device
115    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
116
117    // get chbuf descriptor pointer
118    chbuf = (nic_chbuf_t *)dev_ptr->ext.nic.queue;
119
120    // analyse command type
121    switch( cmd )
122    {
123        /////////////////////////////////////////////////////////////////////////////
124        case NIC_CMD_READ:   // transfer one packet from RX queue to command buffer
125        {
126            // get current container index
127            cont_id = chbuf->cont_id;
128           
129            if( chbuf->full[cont_id] == 0 )  // container empty
130            {
131                printk("PANIC in %s : read an empty container\n", __FUNCTION__ );
132                hal_core_sleep();
133            }
134
135            // get pointer on container and header
136            container = chbuf->cont[cont_id];
137            header    = (uint16_t *)container;
138
139            // get  expected packet index and first word index in container
140            pkt_id  = chbuf->pkt_id;
141            word_id = chbuf->word_id;
142
143            // get packet length and number of packets from container header
144            length    = header[pkt_id + 2];
145            npackets  = header[0];
146
147            if( pkt_id >= npackets )  // packet index too large
148            {
149                printk("PANIC in %s : read a non readable container\n", __FUNCTION__ );
150                hal_core_sleep();
151            }
152
153            // move the packet from container to buffer
154            memcpy( buffer , container + word_id , length );
155
156            // update current packet index and first word index
157            chbuf->pkt_id  = pkt_id + 1;
158            if( length & 0x3 ) chbuf->word_id = word_id + (length>>2) + 1;
159            else               chbuf->word_id = word_id + (length>>2);
160        }
161        break;    // end READ
162           
163        //////////////////////////////////////////////////////////////////////////
164        case NIC_CMD_WRITE:  // move one packet from command buffer to TX queue
165        {
166            // get current TX container indexes
167            cont_id = chbuf->cont_id;
168            pkt_id  = chbuf->pkt_id;
169            word_id = chbuf->word_id;
170
171            if( chbuf->full[cont_id] != 0 )  // container full
172            {
173                printk("PANIC in %s : write to a full container\n", __FUNCTION__ );
174                hal_core_sleep();
175            }
176
177            // get pointer on container and header
178            container = chbuf->cont[cont_id];
179            header    = (uint16_t *)container;
180
181            if( length > ((1024 - word_id)<<2) )  // packet length too large
182            {
183                printk("PANIC in %s : write to a non writable container\n", __FUNCTION__ );
184                hal_core_sleep();
185            }
186
187            // update packet length in container header
188            header[pkt_id + 2] = (uint16_t)length;
189
190            // move the packet from buffer to container
191            memcpy( container + word_id , buffer , length );
192
193            // update current packet index and first word index
194            chbuf->pkt_id  = pkt_id + 1;
195            if( length & 0x3 ) chbuf->word_id = word_id + (length>>2) + 1;
196            else               chbuf->word_id = word_id + (length>>2);
197        }
198        break;  // end WRITE
199
200        ////////////////////////////////////////////////////////////////////////////
201        case NIC_CMD_WRITABLE:  // analyse chbuf status / update status if required
202        {
203            // get current container state
204            cont_id = chbuf->cont_id;
205            word_id = chbuf->word_id;
206
207            // compute current container writable
208            bool_t ok = ( chbuf->full[cont_id] == 0 ) &&
209                        ( length <= ((1024 - word_id)<<2) );
210
211            if( ok )                // current container writable
212            {
213                // return chbuf writable
214                thread_ptr->nic_cmd.status = true;
215            }
216            else                    // current container not writable
217            {
218                // release current container
219                chbuf->full[cont_id] = 1;
220
221                // check next container
222                cont_id = (cont_id + 1) % CONFIG_NIC_CHBUF_DEPTH;
223
224                if( chbuf->full[cont_id] == 0 ) // next container empty
225                {
226                    // update chbuf status
227                    chbuf->word_id = 34;
228                    chbuf->cont_id = cont_id;
229                    chbuf->pkt_id  = 0;
230                     
231                    // return chbuf writable
232                    thread_ptr->nic_cmd.status = true;
233                }
234                else                            // next container full     
235                {
236                    // return chbuf non writable
237                    thread_ptr->nic_cmd.status = false;
238                }
239            }
240        }
241        break;  // end WRITABLE
242
243        /////////////////////////////////////////////////////////////////////////////
244        case NIC_CMD_READABLE:  // analyse chbuf status / update status if required
245        {
246            // get current container state
247            cont_id  = chbuf->cont_id;
248            pkt_id   = chbuf->pkt_id;
249            npackets = chbuf->cont[cont_id][0] & 0x0000FFFF; 
250           
251            // compute current container readable
252            bool_t ok = ( chbuf->full[cont_id] == 1 ) &&
253                        ( pkt_id < npackets );
254
255            if( ok )                    // current container readable
256            {
257                // return chbuf readable     
258                thread_ptr->nic_cmd.status = true;
259            }
260            else                        // current container non readable
261            {
262                // release current container
263                chbuf->full[cont_id] = 0;
264
265                // check next container
266                cont_id = (cont_id + 1) % CONFIG_NIC_CHBUF_DEPTH;
267
268                if( chbuf->full[cont_id] == 1 ) // next container full
269                {
270                    // update chbuf status
271                    chbuf->word_id = 34;
272                    chbuf->cont_id = cont_id;
273                    chbuf->pkt_id  = 0;
274                     
275                    // return chbuf readable
276                    thread_ptr->nic_cmd.status = true;
277                }
278                else                            // next container empty   
279                {
280                    // return chbuf non readable
281                    thread_ptr->nic_cmd.status = false;
282                }
283            }
284   
285        }
286        break;  // end READABLE
287    } 
288} // end soclib_nic_cmd()
289
290
291/////////////////////////////////////////////////////////////////
292void __attribute__ ((noinline)) soclib_nic_isr( chdev_t * chdev )
293{
294    // get base, size, channel, is_rx from NIC channel device NIC
295    xptr_t     base    = chdev->base;
296    uint32_t   channel = chdev->channel;
297    bool_t     is_rx   = chdev->is_rx;
298
299    // get NIC peripheral cluster and local pointer
300    cxy_t      cxy_nic = GET_CXY( base );
301    uint32_t * ptr_nic = (uint32_t *)GET_PTR( base );
302
303    // compute local pointer on status register
304    uint32_t * offset;
305    if( is_rx ) offset = ptr_nic + (NIC_CHANNEL_SPAN * (channel + 1)) + NIC_RX_STATUS;
306    else        offset = ptr_nic + (NIC_CHANNEL_SPAN * (channel + 1)) + NIC_TX_STATUS;
307
308    // read NIC channel status and acknowledge IRQ
309    uint32_t status = hal_remote_lw( XPTR( cxy_nic , offset ) );
310
311    if( status != 0 ) hal_core_sleep("%s : illegal address\n", __FUNCTION__ );
312   
313    // unblock server thread
314    thread_t * server = chdev->server;
315    thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_IO );
316
317} // end soclib_nic_isr()
318
319
320
Note: See TracBrowser for help on using the repository browser.