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

Last change on this file since 635 was 635, checked in by alain, 15 months ago

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

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