UDI - Fix types in GIO metalang
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / trans / bus_pci.c
1 /*
2  * Acess2 UDI Layer
3  * - By John Hodge (thePowersGang)
4  *
5  * trans/bus_pci.c
6  * - PCI Bus Driver
7  */
8 #define DEBUG   1
9 #include <udi.h>
10 #include <udi_physio.h>
11 #include <udi_pci.h>
12 #include <acess.h>
13 #include <drv_pci.h>    // acess
14 #include <udi_internal.h>
15 #include <trans_pci.h>
16
17 // === MACROS ===
18 /* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */
19 #define DPT_SET_ATTR_BOOLEAN(attr, name, val)   \
20                 udi_strcpy((attr)->attr_name, (name)); \
21                 (attr)->attr_type = UDI_ATTR_BOOLEAN; \
22                 (attr)->attr_length = sizeof(udi_boolean_t); \
23                 UDI_ATTR32_SET((attr)->attr_value, (val))
24
25 #define DPT_SET_ATTR32(attr, name, val) \
26                 udi_strcpy((attr)->attr_name, (name)); \
27                 (attr)->attr_type = UDI_ATTR_UBIT32; \
28                 (attr)->attr_length = sizeof(udi_ubit32_t); \
29                 UDI_ATTR32_SET((attr)->attr_value, (val))
30
31 #define DPT_SET_ATTR_ARRAY8(attr, name, val, len) \
32                 udi_strcpy((attr)->attr_name, (name)); \
33                 (attr)->attr_type = UDI_ATTR_ARRAY8; \
34                 (attr)->attr_length = (len); \
35                 udi_memcpy((attr)->attr_value, (val), (len))
36
37 #define DPT_SET_ATTR_STRING(attr, name, val, len) \
38                 udi_strcpy((attr)->attr_name, (name)); \
39                 (attr)->attr_type = UDI_ATTR_STRING; \
40                 (attr)->attr_length = (len); \
41                 udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len))
42
43 #define PCI_OPS_BRIDGE  1
44 #define PCI_OPS_IRQ     2
45
46 #define PCI_MAX_EVENT_CBS       8
47
48 // === TYPES ===
49 typedef struct
50 {
51         udi_init_context_t      init_context;
52         
53         tPCIDev cur_iter;
54 } pci_rdata_t;
55
56 typedef struct
57 {
58         udi_child_chan_context_t        child_chan_context;
59         
60         udi_channel_t   interrupt_channel;
61         struct {
62                 tPAddr  paddr;
63                 void    *vaddr;
64                 size_t  length;
65         } bars[6];
66
67          int    interrupt_handle;
68
69         udi_pio_handle_t        intr_preprocessing;
70         udi_intr_event_cb_t     *event_cbs[PCI_MAX_EVENT_CBS];
71         udi_index_t     event_cb_wr_ofs;
72         udi_index_t     event_cb_rd_ofs;
73          int    bIntrEnabled;
74 } pci_child_chan_context_t;
75
76 // === PROTOTYPES ===
77 void    pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
78 void    pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
79 void    pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
80 void    pci_final_cleanup_req(udi_mgmt_cb_t *cb);
81
82 void    pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb);
83 void    pci_unbind_req(udi_bus_bind_cb_t *cb);
84 void    pci_bind_req_op(udi_bus_bind_cb_t *cb);
85 void    pci_intr_attach_req(udi_intr_attach_cb_t *cb);
86 void    pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel);
87 void    pci_intr_detach_req(udi_intr_detach_cb_t *cb);
88
89 void    pci_intr_ch_event_ind(udi_channel_event_cb_t *cb);
90 void    pci_intr_event_rdy(udi_intr_event_cb_t *cb);
91 void    pci_intr_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result);
92 void    pci_intr_handler(int irq, void *void_context);
93 void    pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result);
94
95 // - Hook to physio (UDI doesn't define these)
96  int    pci_pio_get_regset(udi_cb_t *gcb, udi_ubit32_t regset_idx, void **baseptr, size_t *lenptr);
97
98 // === CODE ===
99 void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
100 {
101         pci_rdata_t     *rdata = UDI_GCB(cb)->context;
102         
103         switch(cb->meta_idx)
104         {
105         case 1: // mgmt
106                 break;
107         }
108
109         switch(resource_level)
110         {
111         case UDI_RESOURCES_CRITICAL:
112         case UDI_RESOURCES_LOW:
113         case UDI_RESOURCES_NORMAL:
114         case UDI_RESOURCES_PLENTIFUL:
115                 break;
116         }
117
118         // TODO: Initialise rdata
119         rdata->cur_iter = -1;
120
121         udi_usage_res(cb);
122 }
123 void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
124 {
125         pci_rdata_t     *rdata = UDI_GCB(cb)->context;
126         switch(enumeration_level)
127         {
128         case UDI_ENUMERATE_START:
129         case UDI_ENUMERATE_START_RESCAN:
130                 rdata->cur_iter = -1;
131         case UDI_ENUMERATE_NEXT:
132                 // TODO: Filters
133                 if( (rdata->cur_iter = PCI_GetDeviceByClass(0,0, rdata->cur_iter)) == -1 )
134                 {
135                         udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
136                 }
137                 else
138                 {
139                         udi_instance_attr_list_t *attr_list = cb->attr_list;
140                         Uint16  ven, dev;
141                         Uint32  class;
142                         PCI_GetDeviceInfo(rdata->cur_iter, &ven, &dev, &class);
143                         Uint8   revision;
144                         PCI_GetDeviceVersion(rdata->cur_iter, &revision);
145                         Uint16  sven, sdev;
146                         PCI_GetDeviceSubsys(rdata->cur_iter, &sven, &sdev);
147
148                         udi_strcpy(attr_list->attr_name, "identifier");
149                         attr_list->attr_length = sprintf((char*)attr_list->attr_value,
150                                 "%04x%04x%02x%04x%04x",
151                                 ven, dev, revision, sven, sdev);
152                         attr_list ++;
153                         DPT_SET_ATTR_STRING(attr_list, "bus_type", "pci", 3);
154                         attr_list ++;
155                         DPT_SET_ATTR32(attr_list, "pci_vendor_id", ven);
156                         attr_list ++;
157                         DPT_SET_ATTR32(attr_list, "pci_device_id", dev);
158                         attr_list ++;
159
160                         cb->attr_valid_length = attr_list - cb->attr_list;
161                         cb->child_ID = rdata->cur_iter;
162                         udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 1);
163                 }
164                 break;
165         }
166 }
167 void pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
168 {
169         UNIMPLEMENTED();
170 }
171 void pci_final_cleanup_req(udi_mgmt_cb_t *cb)
172 {
173         UNIMPLEMENTED();
174 }
175
176 void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb)
177 {
178         UNIMPLEMENTED();
179 }
180 void pci_bind_req(udi_bus_bind_cb_t *cb)
181 {
182         // TODO: "Lock" PCI device
183
184         // TODO: DMA constraints
185         udi_bus_bind_ack(cb, 0, UDI_DMA_LITTLE_ENDIAN, UDI_OK);
186 }
187 void pci_unbind_req(udi_bus_bind_cb_t *cb)
188 {
189         UNIMPLEMENTED();
190 }
191 void pci_intr_attach_req(udi_intr_attach_cb_t *cb)
192 {
193         pci_child_chan_context_t *context = UDI_GCB(cb)->context;
194
195         ASSERT(cb->interrupt_idx == 0); 
196
197         context->intr_preprocessing = cb->preprocessing_handle;
198         // Check if interrupt is already bound
199         if( !UDI_HANDLE_IS_NULL(context->interrupt_channel, udi_channel_t) )
200         {
201                 udi_intr_attach_ack(cb, UDI_OK);
202                 return ;
203         }
204         // Create a channel
205         udi_channel_spawn(pci_intr_attach_req__channel_spawned, UDI_GCB(cb),
206                 cb->gcb.channel, cb->interrupt_idx, PCI_OPS_IRQ, context);
207 }
208 void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel)
209 {
210         udi_intr_attach_cb_t *cb = UDI_MCB(gcb, udi_intr_attach_cb_t);
211         pci_child_chan_context_t *context = UDI_GCB(cb)->context;
212
213         if( UDI_HANDLE_IS_NULL(new_channel, udi_channel_t) )
214         {
215                 // oops
216                 return ;
217         }       
218
219         context->interrupt_channel = new_channel;
220         
221         context->interrupt_handle = IRQ_AddHandler(
222                 PCI_GetIRQ(context->child_chan_context.child_ID),
223                 pci_intr_handler, context);
224
225         udi_intr_attach_ack(cb, UDI_OK);
226 }
227 void pci_intr_detach_req(udi_intr_detach_cb_t *cb)
228 {
229         UNIMPLEMENTED();
230 }
231
232 void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb)
233 {
234         UNIMPLEMENTED();
235 }
236 void pci_intr_event_rdy(udi_intr_event_cb_t *cb)
237 {
238         pci_child_chan_context_t        *context = UDI_GCB(cb)->context;
239
240         ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS);
241         ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS);
242
243         LOG("Rd %i, Wr %i [WR %p]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb);
244         if( context->event_cbs[context->event_cb_wr_ofs] )
245         {
246                 // oops, overrun.
247                 return ;
248         }
249         context->event_cbs[context->event_cb_wr_ofs++] = cb;
250         if( context->event_cb_wr_ofs == PCI_MAX_EVENT_CBS )
251                 context->event_cb_wr_ofs = 0;
252         
253         // TODO: Fire once >= min_event_pend CBs are recieved
254         if( !context->bIntrEnabled )
255         {
256                 context->bIntrEnabled = 1;
257                 udi_pio_trans(pci_intr_event_rdy__irqs_enabled, NULL, context->intr_preprocessing, 0, NULL, NULL);
258         }
259 }
260 void pci_intr_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result)
261 {
262         // nothing
263 }
264
265 void pci_intr_handler(int irq, void *void_context)
266 {
267         pci_child_chan_context_t *context = void_context;
268
269         LOG("irq=%i, context=%p", irq, context);
270
271         if( context->event_cb_rd_ofs == context->event_cb_wr_ofs ) {
272                 // Dropped
273                 return ;
274         }
275
276         ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS);
277         ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS);
278
279         udi_intr_event_cb_t *cb = context->event_cbs[context->event_cb_rd_ofs];
280         LOG("Rd %i, Wr %i [RD %p]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb);
281         context->event_cbs[context->event_cb_rd_ofs] = NULL;
282         context->event_cb_rd_ofs ++;
283         if( context->event_cb_rd_ofs == PCI_MAX_EVENT_CBS )
284                 context->event_cb_rd_ofs = 0;
285         ASSERT(cb);
286         
287         if( UDI_HANDLE_IS_NULL(context->intr_preprocessing, udi_pio_handle_t) )
288         {
289                 udi_intr_event_ind(cb, 0);
290         }
291         else
292         {
293                 // Processing
294                 // - no event info, so mem_ptr=NULL
295                 udi_pio_trans(pci_intr_handle__trans_done, UDI_GCB(cb),
296                         context->intr_preprocessing, 1, cb->event_buf, NULL);
297         }
298 }
299
300 void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
301 {
302         udi_intr_event_cb_t *cb = UDI_MCB(gcb, udi_intr_event_cb_t);
303         
304         cb->intr_result = result;
305         
306         udi_intr_event_ind(cb, UDI_INTR_PREPROCESSED);  
307 }
308
309 // - physio hooks
310 udi_status_t pci_pio_do_io(uint32_t child_ID, udi_ubit32_t regset_idx, udi_ubit32_t ofs, udi_ubit8_t len,
311         void *data, bool isOutput)
312 {
313 //      LOG("child_ID=%i, regset_idx=%i,ofs=0x%x,len=%i,data=%p,isOutput=%b",
314 //              child_ID, regset_idx, ofs, len, data, isOutput);
315         tPCIDev pciid = child_ID;
316         // TODO: Cache child mappings   
317
318         switch(regset_idx)
319         {
320         case UDI_PCI_CONFIG_SPACE:
321                 // TODO:
322                 return UDI_STAT_NOT_SUPPORTED;
323         case UDI_PCI_BAR_0 ... UDI_PCI_BAR_5: {
324                 Uint32 bar = PCI_GetBAR(pciid, regset_idx);
325                 if(bar & 1)
326                 {
327                         // IO BAR
328                         bar &= ~3;
329                         #define _IO(fc, type) do {\
330                                 if( isOutput ) { \
331                                         /*LOG("out"#fc"(0x%x, 0x%x)",bar+ofs,*(type*)data);*/\
332                                         out##fc(bar+ofs, *(type*)data); \
333                                 } \
334                                 else { \
335                                         *(type*)data = in##fc(bar+ofs); \
336                                         /*LOG("in"#fc"(0x%x) = 0x%x",bar+ofs,*(type*)data);*/\
337                                 }\
338                                 } while(0)
339                         switch(len)
340                         {
341                         case UDI_PIO_1BYTE:     _IO(b, udi_ubit8_t);    return UDI_OK;
342                         case UDI_PIO_2BYTE:     _IO(w, udi_ubit16_t);   return UDI_OK;
343                         case UDI_PIO_4BYTE:     _IO(d, udi_ubit32_t);   return UDI_OK;
344                         //case UDI_PIO_8BYTE:   _IO(q, uint64_t);       return UDI_OK;
345                         default:
346                                 return UDI_STAT_NOT_SUPPORTED;
347                         }
348                         #undef _IO
349                 }
350                 else
351                 {
352                         // Memory BAR
353                         //Uint64 longbar = PCI_GetValidBAR(pciid, regset_idx, PCI_BARTYPE_MEM);
354                         return UDI_STAT_NOT_SUPPORTED;
355                 }
356                 break; }
357         default:
358                 return UDI_STAT_NOT_UNDERSTOOD;
359         }
360 }
361
362 // === UDI Functions ===
363 udi_mgmt_ops_t  pci_mgmt_ops = {
364         pci_usage_ind,
365         pci_enumerate_req,
366         pci_devmgmt_req,
367         pci_final_cleanup_req
368 };
369 udi_ubit8_t     pci_mgmt_op_flags[4] = {0,0,0,0};
370 udi_bus_bridge_ops_t    pci_bridge_ops = {
371         pci_bridge_ch_event_ind,
372         pci_bind_req,
373         pci_unbind_req,
374         pci_intr_attach_req,
375         pci_intr_detach_req
376 };
377 udi_ubit8_t     pci_bridge_op_flags[5] = {0,0,0,0,0};
378 udi_intr_dispatcher_ops_t       pci_irq_ops = {
379         pci_intr_ch_event_ind,
380         pci_intr_event_rdy
381 };
382 udi_ubit8_t     pci_irq_ops_flags[2] = {0,0};
383 udi_primary_init_t      pci_pri_init = {
384         .mgmt_ops = &pci_mgmt_ops,
385         .mgmt_op_flags = pci_mgmt_op_flags,
386         .mgmt_scratch_requirement = 0,
387         .enumeration_attr_list_length = 4,
388         .rdata_size = sizeof(pci_rdata_t),
389         .child_data_size = 0,
390         .per_parent_paths = 0
391 };
392 udi_ops_init_t  pci_ops_list[] = {
393         {
394                 PCI_OPS_BRIDGE, 1, UDI_BUS_BRIDGE_OPS_NUM,
395                 sizeof(pci_child_chan_context_t),
396                 (udi_ops_vector_t*)&pci_bridge_ops,
397                 pci_bridge_op_flags
398         },
399         {
400                 PCI_OPS_IRQ, 1, UDI_BUS_INTR_DISPATCH_OPS_NUM,
401                 0,
402                 (udi_ops_vector_t*)&pci_irq_ops,
403                 pci_irq_ops_flags
404         },
405         {0}
406 };
407 udi_init_t      pci_init = {
408         .primary_init_info = &pci_pri_init,
409         .ops_init_list = pci_ops_list
410 };
411 const char      pci_udiprops[] =
412         "properties_version 0x101\0"
413         "message 1 Acess2 Kernel\0"
414         "message 2 John Hodge ([email protected])\0"
415         "message 3 Acess2 PCI Bus\0"
416         "supplier 1\0"
417         "contact 2\0"
418         "name 3\0"
419         "module acess_pci\0"
420         "shortname acesspci\0"
421         "requires udi 0x101\0"
422         "provides udi_bridge 0x101\0"
423         "meta 1 udi_bridge\0"
424         "enumerates 4 0 100 1 bus_name string pci\0"
425         "region 0\0"
426         "child_bind_ops 1 0 1\0"
427         "";
428 size_t  pci_udiprops_size = sizeof(pci_udiprops);

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