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

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