879d0bdca99f579f826e2f5ec80d1dd7c74155f4
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / trans / nsr.c
1 /*
2  * Acess2 UDI Layer
3  * - By John Hodge (thePowersGang)
4  *
5  * trans/nsr.c
6  * - "Network Service Requester" (UDI->IP Translation)
7  */
8 #define DEBUG   1
9 #include <udi.h>
10 #include <udi_nic.h>
11 #include <acess.h>
12 #include <trans_nsr.h>
13 #include <IPStack/include/adapters_api.h>
14 #include <workqueue.h>
15
16 #define NUM_RX_BUFFERS  4
17 #define NUM_TX_DESCS    4
18
19 enum {
20         ACESSNSR_OPS_CTRL = 1,
21         ACESSNSR_OPS_TX,
22         ACESSNSR_OPS_RX,
23 };
24 enum {
25         ACESSNSR_META_NIC = 1
26 };
27 enum {
28         ACESSNSR_CB_CTRL = 1,
29         ACESSNSR_CB_RX,
30         ACESSNSR_CB_TX
31 };
32
33 // === TYPES ===
34 typedef struct acessnsr_txdesc_s
35 {
36         //udi_nic_tx_cb_t       cb;
37         tMutex  CompleteMutex;
38          int    BufIdx;
39         tIPStackBuffer  *IPBuffer;
40 } acessnsr_txdesc_t;
41
42 typedef struct
43 {
44         udi_init_context_t      init_context;   
45         udi_cb_t        *active_cb;
46
47         udi_index_t     init_idx;
48         udi_buf_t       *rx_buffers[NUM_RX_BUFFERS];
49         udi_nic_rx_cb_t *rx_cbs[NUM_RX_BUFFERS];
50
51         tWorkqueue      RXQueue;
52
53         tIPStack_AdapterType    AdapterType;
54         void    *ipstack_handle;
55
56         tWorkqueue      TXWorkQueue;
57         acessnsr_txdesc_t       TXDescs[NUM_TX_DESCS];
58         
59         udi_channel_t   rx_channel;
60         udi_channel_t   tx_channel;
61 } acessnsr_rdata_t;
62
63 // === PROTOTYPES ===
64 // --- Management metalang
65 void acessnsr_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
66 void acessnsr_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
67 void acessnsr_final_cleanup_req(udi_mgmt_cb_t *cb);
68 // --- NSR Control
69 void acessnsr_ctrl_channel_event_ind(udi_channel_event_cb_t *cb);
70 void acessnsr_ctrl_ch_ev_ind__rx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel);
71 void acessnsr_ctrl_ch_ev_ind__tx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel);
72 void acessnsr_ctrl_bind_ack(udi_nic_bind_cb_t *cb, udi_status_t status);
73 void acessnsr_ctrl_bind_ack__rx_buf_allocated(udi_cb_t *gcb, udi_buf_t *new_buf);
74 void acessnsr_ctrl_bind_ack__rx_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb);
75 void acessnsr_ctrl_bind_ack__tx_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb);
76 void acessnsr_ctrl_unbind_ack(udi_nic_cb_t *cb, udi_status_t status);
77 void acessnsr_ctrl_enable_ack(udi_nic_cb_t *cb, udi_status_t status);
78 void acessnsr_ctrl_disable_ack(udi_nic_cb_t *cb, udi_status_t status);
79 void acessnsr_ctrl_ctrl_ack(udi_nic_ctrl_cb_t *cb, udi_status_t status);
80 void acessnsr_ctrl_status_ind(udi_nic_status_cb_t *cb);
81 void acessnsr_ctrl_info_ack(udi_nic_info_cb_t *cb);
82 // --- NSR TX
83 void acessnsr_tx_channel_event_ind(udi_channel_event_cb_t *cb);
84 void acessnsr_tx_rdy(udi_nic_tx_cb_t *cb);
85 void acessnsr_tx_rdy__buffer_cleared(udi_cb_t *gcb, udi_buf_t *buf);
86 // --- NSR RX
87 void acessnsr_rx_channel_event_ind(udi_channel_event_cb_t *cb);
88 void acessnsr_rx_ind(udi_nic_rx_cb_t *cb);
89 void acessnsr_rx_exp_ind(udi_nic_rx_cb_t *cb);
90 // --- Acess IPStack
91  int    acessnsr_SendPacket(void *Card, tIPStackBuffer *Buffer);
92 void    acessnsr_SendPacket__buf_write_complete(udi_cb_t *gcb, udi_buf_t *buf);
93 tIPStackBuffer  *acessnsr_WaitForPacket(void *Card);
94
95 // === CODE ===
96 // --- Management metalang
97 void acessnsr_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
98 {
99         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
100         switch(resource_level)
101         {
102         }
103
104         Workqueue_Init(&rdata->RXQueue, "AcessNSR RX", offsetof(udi_nic_rx_cb_t, chain));
105         Workqueue_Init(&rdata->TXWorkQueue, "AcessNSR TX", offsetof(udi_nic_tx_cb_t, chain));
106
107         udi_usage_res(cb);
108 }
109 void acessnsr_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
110 {
111         UNIMPLEMENTED();
112 }
113 void acessnsr_final_cleanup_req(udi_mgmt_cb_t *cb)
114 {
115         UNIMPLEMENTED();
116 }
117 // --- NSR Control
118 void acessnsr_ctrl_channel_event_ind(udi_channel_event_cb_t *cb)
119 {
120         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
121         switch(cb->event)
122         {
123         case UDI_CHANNEL_CLOSED:
124                 break;
125         case UDI_CHANNEL_BOUND: {
126                 rdata->active_cb = UDI_GCB(cb);
127                 udi_channel_spawn(acessnsr_ctrl_ch_ev_ind__rx_channel_spawned,
128                         cb->params.parent_bound.bind_cb, UDI_GCB(cb)->channel,
129                         1, ACESSNSR_OPS_RX, rdata);
130                 // V V V V
131                 break; }
132         }
133 }
134 void acessnsr_ctrl_ch_ev_ind__rx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel)
135 {
136         acessnsr_rdata_t *rdata = gcb->context;
137         rdata->rx_channel = channel;
138         udi_channel_spawn(acessnsr_ctrl_ch_ev_ind__tx_channel_spawned, gcb, gcb->channel,
139                 2, ACESSNSR_OPS_TX, rdata);
140         // V V V V
141 }
142 void acessnsr_ctrl_ch_ev_ind__tx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel)
143 {
144         acessnsr_rdata_t *rdata = gcb->context;
145         rdata->tx_channel = channel;
146         udi_nic_bind_cb_t *bind_cb = UDI_MCB(gcb, udi_nic_bind_cb_t);
147         udi_nd_bind_req(bind_cb, 2, 1);
148         // V V V V
149 }
150 void acessnsr_ctrl_bind_ack(udi_nic_bind_cb_t *cb, udi_status_t status)
151 {
152         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
153         // TODO: Parse cb and register with IPStack
154         // - Pass on capabilities and media type
155         switch(cb->media_type)
156         {
157         case UDI_NIC_ETHER:     rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_10M;     break;
158         case UDI_NIC_FASTETHER: rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_100M;    break;
159         case UDI_NIC_GIGETHER:  rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_1G;      break;
160         default:
161                 udi_channel_event_complete( UDI_MCB(rdata->active_cb,udi_channel_event_cb_t), UDI_OK );
162                 break;
163         }
164
165         if(cb->capabilities & UDI_NIC_CAP_TX_IP_CKSUM)
166                 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_IP4;
167         if(cb->capabilities & UDI_NIC_CAP_TX_TCP_CKSUM)
168                 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_TCP;
169         if(cb->capabilities & UDI_NIC_CAP_TX_UDP_CKSUM)
170                 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_UDP;
171         
172         rdata->AdapterType.Name = "udi";
173         rdata->AdapterType.SendPacket = acessnsr_SendPacket;
174         rdata->AdapterType.WaitForPacket = acessnsr_WaitForPacket;
175
176         rdata->ipstack_handle = IPStack_Adapter_Add(&rdata->AdapterType, rdata, cb->mac_addr);
177
178         // Allocate RX CBs and buffers
179         rdata->init_idx = -1;
180         acessnsr_ctrl_bind_ack__rx_buf_allocated(rdata->active_cb, NULL);
181         // V V V V
182 }
183 void acessnsr_ctrl_bind_ack__rx_buf_allocated(udi_cb_t *gcb, udi_buf_t *new_buf)
184 {
185         acessnsr_rdata_t *rdata = gcb->context;
186         if( rdata->init_idx != (udi_index_t)-1 )
187         {
188                 rdata->rx_buffers[rdata->init_idx] = new_buf;
189         }
190         rdata->init_idx ++;
191         if( rdata->init_idx < NUM_RX_BUFFERS )
192         {
193                 UDI_BUF_ALLOC(acessnsr_ctrl_bind_ack__rx_buf_allocated, gcb, NULL, 0, NULL);
194                 // A A A A
195                 return ;
196         }
197         
198         rdata->init_idx = -1;
199         acessnsr_ctrl_bind_ack__rx_cb_allocated(gcb, NULL);
200 }
201 void acessnsr_ctrl_bind_ack__rx_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb)
202 {
203         acessnsr_rdata_t *rdata = gcb->context;
204         if( rdata->init_idx != (udi_index_t)-1 )
205         {
206                 udi_nic_rx_cb_t *cb = UDI_MCB(new_cb, udi_nic_rx_cb_t);
207                 rdata->rx_cbs[rdata->init_idx] = cb;
208                 cb->rx_buf = rdata->rx_buffers[rdata->init_idx];
209                 udi_nd_rx_rdy(cb);
210         }
211         rdata->init_idx ++;
212         if( rdata->init_idx < NUM_RX_BUFFERS )
213         {
214                 udi_cb_alloc(acessnsr_ctrl_bind_ack__rx_cb_allocated, gcb, ACESSNSR_CB_RX, rdata->rx_channel);
215                 // A A A A
216                 return ;
217         }
218         rdata->init_idx = -1;
219         acessnsr_ctrl_bind_ack__tx_cb_allocated(gcb, NULL);
220         // V V V V
221 }
222 void acessnsr_ctrl_bind_ack__tx_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb)
223 {
224         acessnsr_rdata_t *rdata = gcb->context;
225         if( rdata->init_idx != (udi_index_t)-1 )
226         {
227                 //udi_assert(new_cb);
228                 ASSERT(new_cb);
229                 Workqueue_AddWork( &rdata->TXWorkQueue,  UDI_MCB(new_cb, udi_nic_tx_cb_t) );
230         }
231         rdata->init_idx ++;
232         if( rdata->init_idx < NUM_TX_DESCS )
233         {
234                 udi_cb_alloc(acessnsr_ctrl_bind_ack__tx_cb_allocated, gcb, ACESSNSR_CB_TX, rdata->tx_channel);
235                 // A A A A
236                 return ;
237         }
238         udi_channel_event_complete( UDI_MCB(rdata->active_cb,udi_channel_event_cb_t), UDI_OK );
239         // = = = =
240 }
241 void acessnsr_ctrl_unbind_ack(udi_nic_cb_t *cb, udi_status_t status)
242 {
243         UNIMPLEMENTED();
244 }
245 void acessnsr_ctrl_enable_ack(udi_nic_cb_t *cb, udi_status_t status)
246 {
247         UNIMPLEMENTED();
248 }
249 void acessnsr_ctrl_disable_ack(udi_nic_cb_t *cb, udi_status_t status)
250 {
251         UNIMPLEMENTED();
252 }
253 void acessnsr_ctrl_ctrl_ack(udi_nic_ctrl_cb_t *cb, udi_status_t status)
254 {
255         UNIMPLEMENTED();
256 }
257 void acessnsr_ctrl_status_ind(udi_nic_status_cb_t *cb)
258 {
259         UNIMPLEMENTED();
260 }
261 void acessnsr_ctrl_info_ack(udi_nic_info_cb_t *cb)
262 {
263         UNIMPLEMENTED();
264 }
265 // --- NSR TX
266 void acessnsr_tx_channel_event_ind(udi_channel_event_cb_t *cb)
267 {
268         UNIMPLEMENTED();
269 }
270 void acessnsr_tx_rdy(udi_nic_tx_cb_t *cb)
271 {
272         //acessnsr_txdesc_t *tx = UDI_GCB(cb)->context;
273         // TODO: Can errors be detected here?
274         UDI_BUF_DELETE(acessnsr_tx_rdy__buffer_cleared, UDI_GCB(cb), cb->tx_buf->buf_size, cb->tx_buf, 0);
275 }
276 void acessnsr_tx_rdy__buffer_cleared(udi_cb_t *gcb, udi_buf_t *buf)
277 {
278         acessnsr_txdesc_t *tx = gcb->scratch;
279         udi_nic_tx_cb_t *cb = UDI_MCB(gcb, udi_nic_tx_cb_t);
280         cb->tx_buf = buf;
281         Mutex_Release(&tx->CompleteMutex);      // triggers acessnsr_SendPacket
282 }
283 // --- NSR RX
284 void acessnsr_rx_channel_event_ind(udi_channel_event_cb_t *cb)
285 {
286         UNIMPLEMENTED();
287 }
288 void acessnsr_rx_ind(udi_nic_rx_cb_t *cb)
289 {
290         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
291         udi_nic_rx_cb_t *next;
292         do {
293                 next = cb->chain;
294                 Workqueue_AddWork(&rdata->RXQueue, cb);
295         } while( (cb = next) );
296 }
297 void acessnsr_rx_exp_ind(udi_nic_rx_cb_t *cb)
298 {
299         acessnsr_rx_ind(cb);
300         //UNIMPLEMENTED();
301 }
302 // --- Acess IPStack
303 int acessnsr_SendPacket(void *Card, tIPStackBuffer *Buffer)
304 {
305         acessnsr_rdata_t *rdata = Card;
306         udi_nic_tx_cb_t *cb = Workqueue_GetWork(&rdata->TXWorkQueue);
307         ASSERT(cb);
308         acessnsr_txdesc_t *tx = UDI_GCB(cb)->scratch;
309         ASSERT(tx);
310         
311         Mutex_Acquire(&tx->CompleteMutex);
312         tx->IPBuffer = Buffer;
313         tx->BufIdx = -1;
314         acessnsr_SendPacket__buf_write_complete(UDI_GCB(cb), NULL);
315
316         // Double lock is resolved once TX is complete
317         Mutex_Acquire(&tx->CompleteMutex);
318         Mutex_Release(&tx->CompleteMutex);
319         // TODO: TX status
320         
321         Workqueue_AddWork(&rdata->TXWorkQueue, tx);
322         return 0;
323 }
324 void acessnsr_SendPacket__buf_write_complete(udi_cb_t *gcb, udi_buf_t *buf)
325 {
326         acessnsr_txdesc_t *tx = gcb->scratch;
327         udi_nic_tx_cb_t *cb = UDI_MCB(gcb, udi_nic_tx_cb_t);
328         if( tx->BufIdx >= 0 ) {
329                 cb->tx_buf = buf;
330         }
331         size_t  buflen;
332         const void      *bufptr;
333         if( (tx->BufIdx = IPStack_Buffer_GetBuffer(tx->IPBuffer, tx->BufIdx, &buflen, &bufptr )) != -1 )
334         {
335                 udi_buf_write(acessnsr_SendPacket__buf_write_complete, gcb,
336                         bufptr, buflen, cb->tx_buf, (cb->tx_buf ? cb->tx_buf->buf_size : 0), 0, NULL);
337                 // A A A A
338                 return ;
339         }
340         
341         udi_nd_tx_req(cb);
342         // continued in acessnsr_tx_rdy
343 }
344 void _FreeHeapSubBuf(void *Arg, size_t Pre, size_t Post, const void *DataBuf)
345 {
346         free(Arg);
347 }
348 tIPStackBuffer *acessnsr_WaitForPacket(void *Card)
349 {
350         acessnsr_rdata_t *rdata = Card;
351         udi_nic_rx_cb_t *cb = Workqueue_GetWork(&rdata->RXQueue);
352
353         tIPStackBuffer  *ret = IPStack_Buffer_CreateBuffer(1);
354         void    *data = malloc( cb->rx_buf->buf_size );
355         udi_buf_read(cb->rx_buf, 0, cb->rx_buf->buf_size, data);
356         IPStack_Buffer_AppendSubBuffer(ret, cb->rx_buf->buf_size, 0, data, _FreeHeapSubBuf, data);
357
358         udi_nd_rx_rdy(cb);
359         return ret;
360 }
361
362 // === UDI Bindings ===
363 udi_mgmt_ops_t  acessnsr_mgmt_ops = {
364         acessnsr_usage_ind,
365         udi_enumerate_no_children,
366         acessnsr_devmgmt_req,
367         acessnsr_final_cleanup_req
368 };
369 udi_ubit8_t     acessnsr_mgmt_ops_flags[4] = {0,0,0,0};
370
371 udi_primary_init_t      acessnsr_pri_init = {
372         .mgmt_ops = &acessnsr_mgmt_ops,
373         .mgmt_op_flags = acessnsr_mgmt_ops_flags,
374         .mgmt_scratch_requirement = 0,
375         .enumeration_attr_list_length = 4,
376         .rdata_size = sizeof(acessnsr_rdata_t),
377         .child_data_size = 0,
378         .per_parent_paths = 0
379 };
380
381 udi_nsr_ctrl_ops_t      acessnsr_ctrl_ops = {
382         acessnsr_ctrl_channel_event_ind,
383         acessnsr_ctrl_bind_ack,
384         acessnsr_ctrl_unbind_ack,
385         acessnsr_ctrl_enable_ack,
386         acessnsr_ctrl_ctrl_ack,
387         acessnsr_ctrl_info_ack,
388         acessnsr_ctrl_status_ind
389 };
390 udi_ubit8_t     acessnsr_ctrl_op_flags[7] = {0};
391
392 udi_nsr_tx_ops_t        acessnsr_tx_ops = {
393         acessnsr_tx_channel_event_ind,
394         acessnsr_tx_rdy
395 };
396 udi_ubit8_t     acessnsr_tx_ops_flags[2] = {0};
397
398 udi_nsr_rx_ops_t        acessnsr_rx_ops = {
399         acessnsr_rx_channel_event_ind,
400         acessnsr_rx_ind,
401         acessnsr_rx_exp_ind
402 };
403 udi_ubit8_t     acessnsr_rx_ops_flags[3] = {0};
404
405 udi_ops_init_t  acessnsr_ops_list[] = {
406         {
407                 ACESSNSR_OPS_CTRL, ACESSNSR_META_NIC, UDI_NSR_CTRL_OPS_NUM,
408                 0, (udi_ops_vector_t*)&acessnsr_ctrl_ops, acessnsr_ctrl_op_flags
409         },
410         {
411                 ACESSNSR_OPS_TX, ACESSNSR_META_NIC, UDI_NSR_TX_OPS_NUM,
412                 0, (udi_ops_vector_t*)&acessnsr_tx_ops, acessnsr_tx_ops_flags
413         },
414         {
415                 ACESSNSR_OPS_RX, ACESSNSR_META_NIC, UDI_NSR_RX_OPS_NUM,
416                 0, (udi_ops_vector_t*)&acessnsr_rx_ops, acessnsr_rx_ops_flags
417         },
418         {0}
419 };
420 udi_cb_init_t   acessnsr_cb_init_list[] = {
421         {ACESSNSR_CB_CTRL, ACESSNSR_META_NIC, UDI_NIC_BIND_CB_NUM, 0, 0,NULL},
422         {ACESSNSR_CB_RX, ACESSNSR_META_NIC, UDI_NIC_RX_CB_NUM, 0, 0,NULL},
423         {ACESSNSR_CB_TX, ACESSNSR_META_NIC, UDI_NIC_TX_CB_NUM, sizeof(acessnsr_txdesc_t), 0,NULL},
424         {0}
425 };
426 const udi_init_t        acessnsr_init = {
427         .primary_init_info = &acessnsr_pri_init,
428         .ops_init_list = acessnsr_ops_list,
429         .cb_init_list = acessnsr_cb_init_list,
430 };
431 const char      acessnsr_udiprops[] = 
432         "properties_version 0x101\0"
433         "message 1 Acess2 Kernel\0"
434         "message 2 John Hodge ([email protected])\0"
435         "message 3 Acess2 NSR\0"
436         "supplier 1\0"
437         "contact 2\0"
438         "name 3\0"
439         "module acess_nsr\0"
440         "shortname acessnsr\0"
441         "requires udi 0x101\0"
442         "requires udi_nic 0x101\0"
443         "meta 1 udi_nic\0"
444         "message 101 Ethernet Adapter\0"
445         "device 101 1 if_media string eth\0"
446         "parent_bind_ops 1 0 1 1\0"
447         "\0";
448 size_t  acessnsr_udiprops_size = sizeof(acessnsr_udiprops);
449

UCC git Repository :: git.ucc.asn.au