IRQ: added irq source capability and make the inthandler setup use it
[barrelfish] / usr / pci / pci_service.c
1  /**
2  * \file
3  * \brief PCI service code
4  *
5  * This file exports the PCI service interface for drivers
6  */
7
8 /*
9  * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
10  * All rights reserved.
11  *
12  * This file is distributed under the terms in the attached LICENSE file.
13  * If you do not find this file, copies can be found by writing to:
14  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include <barrelfish/barrelfish.h>
21 #include <barrelfish/nameservice_client.h>
22 #include <barrelfish/sys_debug.h>
23
24 #include <if/pci_defs.h>
25 #include <acpi_client/acpi_client.h>
26 #include <mm/mm.h>
27 //#include "pci_confspace.h"
28
29 #include "pci.h"
30 #include "pci_debug.h"
31
32 /*****************************************************************
33  * Data types:
34  *****************************************************************/
35
36 /* Per-client state
37  * XXX: this assumes only one driver per client */
38 struct client_state {
39 //    struct device_mem *bar_info;
40     uint8_t initialized;
41     int nr_allocated_bars;
42     uint32_t nr_caps_bar[PCI_NBARS];
43     uint32_t bus;
44     uint32_t dev;
45     uint32_t fun;
46     bool pcie;
47     void *cont_st;
48 };
49
50 /*****************************************************************
51  * Event handlers:
52  *****************************************************************/
53 /*
54     cc->bus = cc->dev = cc->fun = 0;
55 */
56
57 static void init_pci_device_handler(struct pci_binding *b,
58                                     uint32_t class_code, uint32_t sub_class,
59                                     uint32_t prog_if, uint32_t vendor_id,
60                                     uint32_t device_id,
61                                     uint32_t bus, uint32_t dev, uint32_t fun)
62 {
63     struct client_state *cc = (struct client_state *) b->st;
64     errval_t err;
65
66
67     err = device_init(class_code, sub_class, prog_if, vendor_id, device_id,
68                       &bus, &dev, &fun, &(cc->pcie), &(cc->nr_allocated_bars));
69
70     cc->bus = bus;
71     cc->dev = dev;
72     cc->fun = fun;
73
74     for (int i = 0; i < cc->nr_allocated_bars; i++) {
75         cc->nr_caps_bar[i] = pci_get_nr_caps_for_bar(bus, dev, fun, i);
76     }
77
78     if (err_is_fail(err)) {
79         err = b->tx_vtbl.init_pci_device_response(b, NOP_CONT, err, 0,
80                                                   cc->nr_caps_bar);
81
82     } else {
83         err = b->tx_vtbl.init_pci_device_response(b, NOP_CONT, err,
84                                                   cc->nr_allocated_bars,
85                                                   cc->nr_caps_bar);
86     }
87     assert(err_is_ok(err));
88 }
89
90 static void irq_enable_handler(struct pci_binding *b)
91 {
92     struct client_state *cc = (struct client_state *) b->st;
93     if(!cc->initialized){
94         b->tx_vtbl.irq_enable_response(b, NOP_CONT, PCI_ERR_DEVICE_NOT_INIT);
95         return;
96     }
97
98     pci_enable_interrupt_for_device(cc->bus, cc->dev, cc->fun, cc->pcie);
99     b->tx_vtbl.irq_enable_response(b, NOP_CONT, SYS_ERR_OK);
100 }
101
102 static void init_legacy_device_handler(struct pci_binding *b,
103                                        uint16_t iomin, uint16_t iomax,
104                                        uint8_t irq, coreid_t coreid,
105                                        uint32_t vector)
106 {
107     struct capref iocap = NULL_CAP;
108     errval_t e = SYS_ERR_OK;
109
110     PCI_DEBUG("pci: init_legacy_device_handler: called.\n");
111
112     /* TODO: make sure nobody else has claimed iomin-iomax range */
113
114     /* construct iocap for this region */
115     if (iomin != 0 || iomax != 0) {
116         e = slot_alloc(&iocap);
117         if (err_is_fail(e)) {
118             e = err_push(e, LIB_ERR_SLOT_ALLOC);
119             goto reply;
120         }
121
122         e = cap_mint(iocap, cap_io, iomin, iomax);
123         if (err_is_fail(e)) {
124             e = err_push(e, PCI_ERR_MINT_IOCAP);
125             goto reply;
126         }
127     }
128
129     /* determine IOAPIC INTI for given GSI and map to core */
130     if (vector != (uint32_t)-1) {
131
132         struct acpi_rpc_client* cl = get_acpi_rpc_client();
133         errval_t ret_error;
134         e = cl->vtbl.enable_and_route_interrupt(cl, irq, coreid, vector, &ret_error);
135         assert(err_is_ok(e));
136         if (err_is_fail(ret_error)) {
137             DEBUG_ERR(e, "failed to route interrupt %d -> %d\n", irq, vector);
138             e = err_push(e, PCI_ERR_ROUTING_IRQ);
139             goto reply;
140         }
141     }
142
143     /* send reply */
144 reply:
145     e = b->tx_vtbl.init_legacy_device_response(b, NOP_CONT, e,
146                                                err_is_ok(e) ? iocap : NULL_CAP);
147     if (err_is_fail(e)) {
148         DEBUG_ERR(e, "failed to send reply");
149     }
150
151     PCI_DEBUG("pci: init_legacy_device_handler: terminated.\n");
152 }
153
154 static void get_bar_cap_response_resend(void *arg);
155
156 static void get_bar_cap_response_cont(struct pci_binding *b, errval_t err,
157                                   struct capref cap, uint8_t type, uint8_t bar_nr)
158 {
159     errval_t e;
160     e = b->tx_vtbl.get_bar_cap_response(b, NOP_CONT, err, cap, type, bar_nr);
161     if(err_is_fail(e)) {
162         if(err_no(e) == FLOUNDER_ERR_TX_BUSY) {
163             struct client_state *st = b->st;
164             struct pci_get_bar_cap_response__args *me = malloc(sizeof(*me));
165             assert(me != NULL);
166             me->err = err;
167             me->cap = cap;
168             me->type = type;
169             me->bar_nr = bar_nr;
170             st->cont_st = me;
171
172             e = b->register_send(b, get_default_waitset(),
173                                  MKCONT(get_bar_cap_response_resend, b));
174             assert(err_is_ok(e));
175         } else {
176             USER_PANIC_ERR(e, "get_bar_cap_response");
177         }
178     }
179 }
180
181 static void get_bar_cap_response_resend(void *arg)
182 {
183     struct pci_binding *b = arg;
184     struct client_state *st = b->st;
185     struct pci_get_bar_cap_response__args *a = st->cont_st;
186     get_bar_cap_response_cont(b, a->err, a->cap, a->type, a->bar_nr);
187     free(a);
188 }
189
190 static void get_irq_cap_handler(struct pci_binding *b, uint16_t idx){
191     // TODO: This method hands out caps very generous.
192     errval_t err;
193     struct capref cap;
194     slot_alloc(&cap);
195     err = sys_debug_create_irq_src_cap(cap, idx);
196     b->tx_vtbl.get_irq_cap_response(b, NOP_CONT, err, cap);
197 }
198
199 static void get_bar_cap_handler(struct pci_binding *b, uint32_t idx,
200                             uint32_t cap_nr)
201 {
202     struct client_state *st = b->st;
203     assert(st != NULL);
204     errval_t e;
205
206     if (idx >= st->nr_allocated_bars) {
207         e = b->tx_vtbl.get_bar_cap_response(b, NOP_CONT, PCI_ERR_WRONG_INDEX,
208                                         NULL_CAP, 0, 0);
209         assert(err_is_ok(e));
210     } else {
211         struct capref cap = pci_get_bar_cap_for_device(st->bus, st->dev,
212                                                    st->fun, idx, cap_nr);
213         uint8_t type = pci_get_bar_cap_type_for_device(st->bus, st->dev,
214                                                    st->fun, idx);
215         uint8_t bar_nr = pci_get_bar_nr_for_index(st->bus, st->dev,
216                                                    st->fun, idx);
217 /*
218 XXX: I/O-Cap??
219         uint8_t type = st->bar_info[idx].type;
220         struct capref cap = NULL_CAP;
221
222         if(type == 0) {
223             cap = st->bar_info[idx].frame_cap;
224         } else {
225             cap = st->bar_info[idx].io_cap;
226         }
227 */
228
229         get_bar_cap_response_cont(b, SYS_ERR_OK, cap, type, bar_nr);
230     }
231 }
232 /*
233 static void get_vbe_bios_cap(struct pci_binding *b)
234 {
235     errval_t err;
236     err = b->tx_vtbl.get_vbe_bios_cap_response(b, NOP_CONT, SYS_ERR_OK, biosmem,
237                                                1UL << BIOS_BITS);
238     assert(err_is_ok(err));
239 }*/
240
241 static void read_conf_header_handler(struct pci_binding *b, uint32_t dword)
242 {
243
244     struct client_state *cc = (struct client_state *) b->st;
245     struct pci_address addr = {
246         .bus= cc->bus,
247         .device=cc->dev,
248         .function=cc->fun,
249     };
250     PCI_DEBUG("Read config header from %u:%u:%u\n",addr.bus, addr.device, addr.function);
251     uint32_t val = pci_read_conf_header(&addr, dword);
252
253     errval_t err;
254     err = b->tx_vtbl.read_conf_header_response(b, NOP_CONT, SYS_ERR_OK, val);
255     assert(err_is_ok(err));
256 }
257
258 static void reregister_interrupt_handler(struct pci_binding *b,
259                                     uint32_t class_code, uint32_t sub_class,
260                                     uint32_t prog_if, uint32_t vendor_id,
261                                     uint32_t device_id,
262                                     uint32_t bus, uint32_t dev, uint32_t fun,
263                                     coreid_t coreid, uint32_t vector)
264 {
265     errval_t err;
266     err = device_reregister_interrupt(coreid, vector,
267                       class_code, sub_class, prog_if, vendor_id, device_id,
268                       &bus, &dev, &fun);
269     err = b->tx_vtbl.reregister_interrupt_response(b, NOP_CONT, err);
270     assert(err_is_ok(err));
271 }
272
273 static void write_conf_header_handler(struct pci_binding *b, uint32_t dword, uint32_t val)
274 {
275     struct client_state *cc = (struct client_state *) b->st;
276     struct pci_address addr = {
277         .bus= cc->bus,
278         .device=cc->dev,
279         .function=cc->fun,
280     };
281     PCI_DEBUG("Write config header from %u:%u:%u\n",addr.bus, addr.device, addr.function);
282     pci_write_conf_header(&addr, dword, val);
283
284     errval_t err;
285     err = b->tx_vtbl.write_conf_header_response(b, NOP_CONT, SYS_ERR_OK);
286     assert(err_is_ok(err));
287 }
288
289 static void msix_enable_addr_handler(struct pci_binding *b, uint8_t bus,
290                                       uint8_t dev, uint8_t fun)
291 {
292     struct client_state *cc = (struct client_state *) b->st;
293     struct pci_address addr;
294
295     /* XXX: find another way to do this */
296
297     if (bus == cc->bus && dev == cc->dev) {
298         addr.bus= bus;
299         addr.device=dev;
300         addr.function=fun;
301     } else {
302         addr.bus= cc->bus;
303         addr.device=cc->dev;
304         addr.function=fun;
305     }
306
307     errval_t err;
308     uint16_t count;
309
310     debug_printf("enabling MSI-X for device (%u, %u, %u)\n", addr.bus,
311                  addr.device, addr.function);
312
313     err = pci_msix_enable(&addr, &count);
314     err = b->tx_vtbl.msix_enable_response(b, NOP_CONT, err, count);
315     assert(err_is_ok(err));
316 }
317
318 static void msix_enable_handler(struct pci_binding *b)
319 {
320     struct client_state *cc = (struct client_state *) b->st;
321     msix_enable_addr_handler(b, cc->bus, cc->dev, cc->fun);
322 }
323
324 static void msix_vector_init_addr_handler(struct pci_binding *b, uint8_t bus,
325                                           uint8_t dev, uint8_t fun, uint16_t idx,
326                                           uint8_t destination, uint8_t vector)
327 {
328     struct client_state *cc = (struct client_state *) b->st;
329     struct pci_address addr;
330
331     /* XXX: find another way to do this */
332
333     if (bus == cc->bus && dev == cc->dev) {
334         addr.bus= bus;
335         addr.device=dev;
336         addr.function=fun;
337     } else {
338         addr.bus= cc->bus;
339         addr.device=cc->dev;
340         addr.function=fun;
341     }
342
343     debug_printf("initialize MSI-X vector for device (%u, %u, %u)\n", addr.bus,
344                      addr.device, addr.function);
345
346     errval_t err;
347
348     err = pci_msix_vector_init(&addr, idx, destination, vector);
349     err = b->tx_vtbl.msix_vector_init_response(b, NOP_CONT, err);
350     assert(err_is_ok(err));
351 }
352
353 static void msix_vector_init_handler(struct pci_binding *b, uint16_t idx,
354                                      uint8_t destination, uint8_t vector)
355 {
356     struct client_state *cc = (struct client_state *) b->st;
357
358     msix_vector_init_addr_handler(b, cc->bus, cc->dev, cc->fun, idx, destination,
359                                   vector);
360 }
361
362 struct pci_rx_vtbl pci_rx_vtbl = {
363     .init_pci_device_call = init_pci_device_handler,
364     .init_legacy_device_call = init_legacy_device_handler,
365     .get_bar_cap_call = get_bar_cap_handler,
366     .get_irq_cap_call = get_irq_cap_handler,
367     .reregister_interrupt_call = reregister_interrupt_handler,
368     //.get_vbe_bios_cap_call = get_vbe_bios_cap,
369     .read_conf_header_call = read_conf_header_handler,
370     .write_conf_header_call = write_conf_header_handler,
371     .irq_enable_call = irq_enable_handler,
372
373     .msix_enable_call = msix_enable_handler,
374     .msix_enable_addr_call = msix_enable_addr_handler,
375     .msix_vector_init_call = msix_vector_init_handler,
376     .msix_vector_init_addr_call = msix_vector_init_addr_handler,
377 };
378
379 static void export_callback(void *st, errval_t err, iref_t iref)
380 {
381     assert(err_is_ok(err));
382
383     err = nameservice_register("pci", iref);
384     if (err_is_fail(err)) {
385         USER_PANIC_ERR(err, "nameservice_register failed");
386     }
387 }
388
389 static errval_t connect_callback(void *cst, struct pci_binding *b)
390 {
391     struct client_state *st = malloc(sizeof(struct client_state));
392     assert(st != NULL);
393
394     b->rx_vtbl = pci_rx_vtbl;
395     b->st = st;
396 //    st->bar_info = 0;
397     st->nr_allocated_bars = 0;
398     for (int i = 0; i < PCI_NBARS; i++) {
399         st->nr_caps_bar[i] = 0;
400     }
401
402     return SYS_ERR_OK;
403 }
404
405 /*****************************************************************
406  * Boots up the PCI server:
407  *****************************************************************/
408
409 void pci_init(void)
410 {
411     PCI_DEBUG("pci: pci_init: called\n");
412
413     PCI_DEBUG("pci: pci_init: launch listening\n");
414     errval_t r = pci_export(NULL, export_callback, connect_callback,
415                             get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
416     assert(err_is_ok(r));
417
418     PCI_DEBUG("pci: pci_init: terminated\n");
419 }