source: trunk/kernel/drivers/soclib/soclib_cma.c @ 15

Last change on this file since 15 was 4, checked in by alain, 8 years ago

Introduce the chdev_t structure in place of device_t.

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