source: trunk/kernel/drivers/soclib/soclib_nic.c @ 2

Last change on this file since 2 was 1, checked in by alain, 8 years ago

First import

File size: 11.7 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_types.h>
25#include <hal_remote.h>
26#include <hal_special.h>
27#include <device.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
37/////////////////////////////////////
38void soclib_nic_init( xptr_t dev_xp )
39{
40    uint32_t    i;
41    kmem_req_t  req;
42   
43    // get NIC device descriptor cluster and local pointer
44    cxy_t      dev_cxy  = GET_CXY( dev_xp );
45    device_t * dev_ptr  = (device_t *)GET_PTR( dev_xp );
46 
47    // get hardware device base address
48        xptr_t     base = hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
49
50    // get hardware device cluster and local pointer
51    cxy_t      nic_cxy  = GET_CXY( base );
52    uint32_t * nic_ptr  = (uint32_t *)GET_PTR( base );
53
54    // initialize Soclib NIC global registers
55    hal_remote_sw( XPTR( nic_cxy , &nic_ptr + NIC_G_BC_ENABLE ) , 0 );
56    hal_remote_sw( XPTR( nic_cxy , &nic_ptr + NIC_G_RUN       ) , 0 );
57
58    // allocate memory for chbuf descriptor (one page)
59    if( sizeof(nic_chbuf_t) > CONFIG_PPM_PAGE_SIZE )
60    {
61        printk("\n[PANIC] in %s : chbuf descriptor exceeds one page\n", __FUNCTION__ );
62        hal_core_sleep();
63    }
64
65    req.type   = KMEM_PAGE;
66    req.size   = 0;
67    req.flags  = AF_KERNEL;
68
69    nic_chbuf_t * chbuf = (nic_chbuf_t *)kmem_alloc( &req );
70
71    if( chbuf == NULL )
72    {
73        hal_core_sleep("%s : no more memory for chbuf desccriptor\n", __FUNCTION__ );
74    }
75
76    // initialise chbuf state
77    chbuf->cont_id  = 0;
78    chbuf->pkt_id   = 0;
79    chbuf->word_id  = 34;
80   
81    // allocate containers (one page per container)
82    // and complete chbuf descriptor initialization
83    if( CONFIG_PPM_PAGE_SIZE != 4096 )
84    {
85        hal_core_sleep("%s : chbuf container must be 4 Kbytes\n", __FUNCTION__ );
86    }
87
88    for( i = 0 ; i < CONFIG_NIC_CHBUF_DEPTH ; i++ )
89    {
90        uint32_t * container = (uint32_t *)kmem_alloc( &req );   
91
92        if( container == NULL )
93        {
94            hal_core_sleep("%s : no more memory for container\n", __FUNCTION__ );
95        }
96       
97        chbuf->cont[i] = container;
98        chbuf->full[i] = (paddr_t)XPTR( local_cxy , container );
99    }
100
101} // end soclib_nic_init()
102
103
104//////////////////////////////////////////////////////////////////
105void __attribute__ ((noinline)) soclib_nic_cmd( xptr_t thread_xp )
106{
107    uint32_t       cmd;          // command type   
108    char         * buffer;       // pointer on command buffer   
109    uint32_t       length;       // Ethernet packet length
110    xptr_t         dev_xp;       // extended pointer on NIC device
111    nic_chbuf_t  * chbuf;        // pointer on chbuf descriptor
112    uint32_t       cont_id;      // index of current container in chbuf
113    uint32_t       pkt_id;       // index of current packet in container
114    uint32_t       word_id;      // index of first word of current packet in container
115    uint32_t     * container;    // pointer on container (array of uint32_t)
116    uint16_t     * header;       // pointer on container header (array of uint16_t)
117    uint32_t       npackets;     // number of packets in current container
118
119    // get local pointer for client thread
120    thread_t * thread_ptr = (thread_t *)GET_PTR( thread_xp );
121
122    // get command arguments
123    cmd    = thread_ptr->dev.nic.cmd;
124    buffer = thread_ptr->dev.nic.buffer;
125    length = thread_ptr->dev.nic.length;
126    dev_xp = thread_ptr->dev.nic.dev_xp;
127
128    // get local pointer for device
129    device_t * dev_ptr = (device_t *)GET_PTR( dev_xp );
130
131    // get chbuf descriptor pointer
132    chbuf = (nic_chbuf_t *)dev_ptr->ext.nic.queue;
133
134    // analyse command type
135    switch( cmd )
136    {
137        /////////////////////////////////////////////////////////////////////////////
138        case NIC_CMD_READ:   // transfer one packet from RX queue to command buffer
139        {
140            // get current container index
141            cont_id = chbuf->cont_id;
142           
143            if( chbuf->full[cont_id] == 0 )  // container empty
144            {
145                printk("PANIC in %s : read an empty container\n", __FUNCTION__ );
146                hal_core_sleep();
147            }
148
149            // get pointer on container and header
150            container = chbuf->cont[cont_id];
151            header    = (uint16_t *)container;
152
153            // get  expected packet index and first word index in container
154            pkt_id  = chbuf->pkt_id;
155            word_id = chbuf->word_id;
156
157            // get packet length and number of packets from container header
158            length    = header[pkt_id + 2];
159            npackets  = header[0];
160
161            if( pkt_id >= npackets )  // packet index too large
162            {
163                printk("PANIC in %s : read a non readable container\n", __FUNCTION__ );
164                hal_core_sleep();
165            }
166
167            // move the packet from container to buffer
168            memcpy( buffer , container + word_id , length );
169
170            // update current packet index and first word index
171            chbuf->pkt_id  = pkt_id + 1;
172            if( length & 0x3 ) chbuf->word_id = word_id + (length>>2) + 1;
173            else               chbuf->word_id = word_id + (length>>2);
174        }
175        break;    // end READ
176           
177        //////////////////////////////////////////////////////////////////////////
178        case NIC_CMD_WRITE:  // move one packet from command buffer to TX queue
179        {
180            // get current TX container indexes
181            cont_id = chbuf->cont_id;
182            pkt_id  = chbuf->pkt_id;
183            word_id = chbuf->word_id;
184
185            if( chbuf->full[cont_id] != 0 )  // container full
186            {
187                printk("PANIC in %s : write to a full container\n", __FUNCTION__ );
188                hal_core_sleep();
189            }
190
191            // get pointer on container and header
192            container = chbuf->cont[cont_id];
193            header    = (uint16_t *)container;
194
195            if( length > ((1024 - word_id)<<2) )  // packet length too large
196            {
197                printk("PANIC in %s : write to a non writable container\n", __FUNCTION__ );
198                hal_core_sleep();
199            }
200
201            // update packet length in container header
202            header[pkt_id + 2] = (uint16_t)length;
203
204            // move the packet from buffer to container
205            memcpy( container + word_id , buffer , length );
206
207            // update current packet index and first word index
208            chbuf->pkt_id  = pkt_id + 1;
209            if( length & 0x3 ) chbuf->word_id = word_id + (length>>2) + 1;
210            else               chbuf->word_id = word_id + (length>>2);
211        }
212        break;  // end WRITE
213
214        ////////////////////////////////////////////////////////////////////////////
215        case NIC_CMD_WRITABLE:  // analyse chbuf status / update status if required
216        {
217            // get current container state
218            cont_id = chbuf->cont_id;
219            word_id = chbuf->word_id;
220
221            // compute current container writable
222            bool_t ok = ( chbuf->full[cont_id] == 0 ) &&
223                        ( length <= ((1024 - word_id)<<2) );
224
225            if( ok )                // current container writable
226            {
227                // return chbuf writable
228                thread_ptr->dev.nic.status = true;
229            }
230            else                    // current container not writable
231            {
232                // release current container
233                chbuf->full[cont_id] = 1;
234
235                // check next container
236                cont_id = (cont_id + 1) % CONFIG_NIC_CHBUF_DEPTH;
237
238                if( chbuf->full[cont_id] == 0 ) // next container empty
239                {
240                    // update chbuf status
241                    chbuf->word_id = 34;
242                    chbuf->cont_id = cont_id;
243                    chbuf->pkt_id  = 0;
244                     
245                    // return chbuf writable
246                    thread_ptr->dev.nic.status = true;
247                }
248                else                            // next container full     
249                {
250                    // return chbuf non writable
251                    thread_ptr->dev.nic.status = false;
252                }
253            }
254        }
255        break;  // end WRITABLE
256
257        /////////////////////////////////////////////////////////////////////////////
258        case NIC_CMD_READABLE:  // analyse chbuf status / update status if required
259        {
260            // get current container state
261            cont_id  = chbuf->cont_id;
262            pkt_id   = chbuf->pkt_id;
263            npackets = chbuf->cont[cont_id][0] & 0x0000FFFF; 
264           
265            // compute current container readable
266            bool_t ok = ( chbuf->full[cont_id] == 1 ) &&
267                        ( pkt_id < npackets );
268
269            if( ok )                    // current container readable
270            {
271                // return chbuf readable     
272                thread_ptr->dev.nic.status = true;
273            }
274            else                        // current container non readable
275            {
276                // release current container
277                chbuf->full[cont_id] = 0;
278
279                // check next container
280                cont_id = (cont_id + 1) % CONFIG_NIC_CHBUF_DEPTH;
281
282                if( chbuf->full[cont_id] == 1 ) // next container full
283                {
284                    // update chbuf status
285                    chbuf->word_id = 34;
286                    chbuf->cont_id = cont_id;
287                    chbuf->pkt_id  = 0;
288                     
289                    // return chbuf readable
290                    thread_ptr->dev.nic.status = true;
291                }
292                else                            // next container empty   
293                {
294                    // return chbuf non readable
295                    thread_ptr->dev.nic.status = false;
296                }
297            }
298   
299        }
300        break;  // end READABLE
301    } 
302} // end soclib_nic_cmd()
303
304
305////////////////////////////////////////////////////////////////
306void __attribute__ ((noinline)) soclib_nic_isr( device_t * dev )
307{
308    // get base, size, channel, is_rx from NIC channel device NIC
309    xptr_t     base    = dev->base;
310    uint32_t   channel = dev->channel;
311    bool_t     is_rx   = dev->is_rx;
312
313    // get NIC peripheral cluster and local pointer
314    cxy_t      cxy_nic = GET_CXY( base );
315    uint32_t * ptr_nic = (uint32_t *)GET_PTR( base );
316
317    // compute local pointer on status register
318    uint32_t * offset;
319    if( is_rx ) offset = ptr_nic + (NIC_CHANNEL_SPAN * (channel + 1)) + NIC_RX_STATUS;
320    else        offset = ptr_nic + (NIC_CHANNEL_SPAN * (channel + 1)) + NIC_TX_STATUS;
321
322    // read NIC channel status and acknowledge IRQ
323    uint32_t status = hal_remote_lw( XPTR( cxy_nic , offset ) );
324
325    if( status != 0 ) hal_core_sleep("%s : illegal address\n", __FUNCTION__ );
326   
327    // unblock server thread
328    thread_t * server = dev->server;
329    thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_IO );
330
331} // end soclib_nic_isr()
332
333
334
Note: See TracBrowser for help on using the repository browser.