Merge branch 'arrakis'
[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     int nr_allocated_bars;
41     uint32_t nr_caps_bar[PCI_NBARS];
42     uint32_t bus;
43     uint32_t dev;
44     uint32_t fun;
45     void *cont_st;
46 };
47
48 /*****************************************************************
49  * Event handlers:
50  *****************************************************************/
51 /*
52     cc->bus = cc->dev = cc->fun = 0;
53 */
54
55 static void init_pci_device_handler(struct pci_binding *b,
56                                     uint32_t class_code, uint32_t sub_class,
57                                     uint32_t prog_if, uint32_t vendor_id,
58                                     uint32_t device_id,
59                                     uint32_t bus, uint32_t dev, uint32_t fun,
60                                     coreid_t coreid, uint32_t vector)
61 {
62     bool enable_irq = (vector != (uint32_t)-1);
63     struct client_state *cc = (struct client_state *) b->st;
64     errval_t err;
65
66     err = device_init(enable_irq, coreid, vector,
67                       class_code, sub_class, prog_if, vendor_id, device_id,
68                       &bus, &dev, &fun, &(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     } else {
82         err = b->tx_vtbl.init_pci_device_response(b, NOP_CONT, err,
83                                                   cc->nr_allocated_bars,
84                                                   cc->nr_caps_bar);
85     }
86     assert(err_is_ok(err));
87 }
88
89 static void init_legacy_device_handler(struct pci_binding *b,
90                                        uint16_t iomin, uint16_t iomax,
91                                        uint8_t irq, coreid_t coreid,
92                                        uint32_t vector)
93 {
94     struct capref iocap = NULL_CAP;
95     errval_t e = SYS_ERR_OK;
96
97     PCI_DEBUG("pci: init_legacy_device_handler: called.\n");
98
99     /* TODO: make sure nobody else has claimed iomin-iomax range */
100
101     /* construct iocap for this region */
102     if (iomin != 0 || iomax != 0) {
103         e = slot_alloc(&iocap);
104         if (err_is_fail(e)) {
105             e = err_push(e, LIB_ERR_SLOT_ALLOC);
106             goto reply;
107         }
108
109         e = cap_mint(iocap, cap_io, iomin, iomax);
110         if (err_is_fail(e)) {
111             e = err_push(e, PCI_ERR_MINT_IOCAP);
112             goto reply;
113         }
114     }
115
116     /* determine IOAPIC INTI for given GSI and map to core */
117     if (vector != (uint32_t)-1) {
118
119         struct acpi_rpc_client* cl = get_acpi_rpc_client();
120         errval_t ret_error;
121         e = cl->vtbl.enable_and_route_interrupt(cl, irq, coreid, vector, &ret_error);
122         assert(err_is_ok(e));
123         if (err_is_fail(ret_error)) {
124             DEBUG_ERR(e, "failed to route interrupt %d -> %d\n", irq, vector);
125             e = err_push(e, PCI_ERR_ROUTING_IRQ);
126             goto reply;
127         }
128     }
129
130     /* send reply */
131 reply:
132     e = b->tx_vtbl.init_legacy_device_response(b, NOP_CONT, e,
133                                                err_is_ok(e) ? iocap : NULL_CAP);
134     if (err_is_fail(e)) {
135         DEBUG_ERR(e, "failed to send reply");
136     }
137
138     PCI_DEBUG("pci: init_legacy_device_handler: terminated.\n");
139 }
140
141 static void get_cap_response_resend(void *arg);
142
143 static void get_cap_response_cont(struct pci_binding *b, errval_t err,
144                                   struct capref cap, uint8_t type, uint8_t bar_nr)
145 {
146     errval_t e;
147     e = b->tx_vtbl.get_cap_response(b, NOP_CONT, err, cap, type, bar_nr);
148     if(err_is_fail(e)) {
149         if(err_no(e) == FLOUNDER_ERR_TX_BUSY) {
150             struct client_state *st = b->st;
151             struct pci_get_cap_response__args *me = malloc(sizeof(*me));
152             assert(me != NULL);
153             me->err = err;
154             me->cap = cap;
155             me->type = type;
156             me->bar_nr = bar_nr;
157             st->cont_st = me;
158
159             e = b->register_send(b, get_default_waitset(),
160                                  MKCONT(get_cap_response_resend, b));
161             assert(err_is_ok(e));
162         } else {
163             USER_PANIC_ERR(e, "get_cap_response");
164         }
165     }
166 }
167
168 static void get_cap_response_resend(void *arg)
169 {
170     struct pci_binding *b = arg;
171     struct client_state *st = b->st;
172     struct pci_get_cap_response__args *a = st->cont_st;
173     get_cap_response_cont(b, a->err, a->cap, a->type, a->bar_nr);
174     free(a);
175 }
176
177 static void get_cap_handler(struct pci_binding *b, uint32_t idx,
178                             uint32_t cap_nr)
179 {
180     struct client_state *st = b->st;
181     assert(st != NULL);
182     errval_t e;
183
184     if (idx >= st->nr_allocated_bars) {
185         e = b->tx_vtbl.get_cap_response(b, NOP_CONT, PCI_ERR_WRONG_INDEX,
186                                         NULL_CAP, 0, 0);
187         assert(err_is_ok(e));
188     } else {
189         struct capref cap = pci_get_cap_for_device(st->bus, st->dev,
190                                                    st->fun, idx, cap_nr);
191         uint8_t type = pci_get_cap_type_for_device(st->bus, st->dev,
192                                                    st->fun, idx);
193         uint8_t bar_nr = pci_get_bar_nr_for_index(st->bus, st->dev,
194                                                    st->fun, idx);
195 /*
196 XXX: I/O-Cap??
197         uint8_t type = st->bar_info[idx].type;
198         struct capref cap = NULL_CAP;
199
200         if(type == 0) {
201             cap = st->bar_info[idx].frame_cap;
202         } else {
203             cap = st->bar_info[idx].io_cap;
204         }
205 */
206
207         get_cap_response_cont(b, SYS_ERR_OK, cap, type, bar_nr);
208     }
209 }
210 /*
211 static void get_vbe_bios_cap(struct pci_binding *b)
212 {
213     errval_t err;
214     err = b->tx_vtbl.get_vbe_bios_cap_response(b, NOP_CONT, SYS_ERR_OK, biosmem,
215                                                1UL << BIOS_BITS);
216     assert(err_is_ok(err));
217 }*/
218
219 static void read_conf_header_handler(struct pci_binding *b, uint32_t dword)
220 {
221
222     struct client_state *cc = (struct client_state *) b->st;
223     struct pci_address addr = {
224         .bus= cc->bus,
225         .device=cc->dev,
226         .function=cc->fun,
227     };
228     PCI_DEBUG("Read config header from %u:%u:%u\n",addr.bus, addr.device, addr.function);
229     uint32_t val = pci_read_conf_header(&addr, dword);
230
231     errval_t err;
232     err = b->tx_vtbl.read_conf_header_response(b, NOP_CONT, SYS_ERR_OK, val);
233     assert(err_is_ok(err));
234 }
235
236 static void reregister_interrupt_handler(struct pci_binding *b,
237                                     uint32_t class_code, uint32_t sub_class,
238                                     uint32_t prog_if, uint32_t vendor_id,
239                                     uint32_t device_id,
240                                     uint32_t bus, uint32_t dev, uint32_t fun,
241                                     coreid_t coreid, uint32_t vector)
242 {
243     errval_t err;
244     err = device_reregister_interrupt(coreid, vector,
245                       class_code, sub_class, prog_if, vendor_id, device_id,
246                       &bus, &dev, &fun);
247     err = b->tx_vtbl.reregister_interrupt_response(b, NOP_CONT, err);
248     assert(err_is_ok(err));
249 }
250
251 static void write_conf_header_handler(struct pci_binding *b, uint32_t dword, uint32_t val)
252 {
253     struct client_state *cc = (struct client_state *) b->st;
254     struct pci_address addr = {
255         .bus= cc->bus,
256         .device=cc->dev,
257         .function=cc->fun,
258     };
259     PCI_DEBUG("Write config header from %u:%u:%u\n",addr.bus, addr.device, addr.function);
260     pci_write_conf_header(&addr, dword, val);
261
262     errval_t err;
263     err = b->tx_vtbl.write_conf_header_response(b, NOP_CONT, SYS_ERR_OK);
264     assert(err_is_ok(err));
265 }
266
267 static void msix_enable_addr_handler(struct pci_binding *b, uint8_t bus,
268                                       uint8_t dev, uint8_t fun)
269 {
270     struct client_state *cc = (struct client_state *) b->st;
271     struct pci_address addr;
272
273     /* XXX: find another way to do this */
274
275     if (bus == cc->bus && dev == cc->dev) {
276         addr.bus= bus;
277         addr.device=dev;
278         addr.function=fun;
279     } else {
280         addr.bus= cc->bus;
281         addr.device=cc->dev;
282         addr.function=fun;
283     }
284
285     errval_t err;
286     uint16_t count;
287
288     debug_printf("enabling MSI-X for device (%u, %u, %u)\n", addr.bus,
289                  addr.device, addr.function);
290
291     err = pci_msix_enable(&addr, &count);
292     err = b->tx_vtbl.msix_enable_response(b, NOP_CONT, err, count);
293     assert(err_is_ok(err));
294 }
295
296 static void msix_enable_handler(struct pci_binding *b)
297 {
298     struct client_state *cc = (struct client_state *) b->st;
299     msix_enable_addr_handler(b, cc->bus, cc->dev, cc->fun);
300 }
301
302 static void msix_vector_init_addr_handler(struct pci_binding *b, uint8_t bus,
303                                           uint8_t dev, uint8_t fun, uint16_t idx,
304                                           uint8_t destination, uint8_t vector)
305 {
306     struct client_state *cc = (struct client_state *) b->st;
307     struct pci_address addr;
308
309     /* XXX: find another way to do this */
310
311     if (bus == cc->bus && dev == cc->dev) {
312         addr.bus= bus;
313         addr.device=dev;
314         addr.function=fun;
315     } else {
316         addr.bus= cc->bus;
317         addr.device=cc->dev;
318         addr.function=fun;
319     }
320
321     debug_printf("initialize MSI-X vector for device (%u, %u, %u)\n", addr.bus,
322                      addr.device, addr.function);
323
324     errval_t err;
325
326     err = pci_msix_vector_init(&addr, idx, destination, vector);
327     err = b->tx_vtbl.msix_vector_init_response(b, NOP_CONT, err);
328     assert(err_is_ok(err));
329 }
330
331 static void msix_vector_init_handler(struct pci_binding *b, uint16_t idx,
332                                      uint8_t destination, uint8_t vector)
333 {
334     struct client_state *cc = (struct client_state *) b->st;
335
336     msix_vector_init_addr_handler(b, cc->bus, cc->dev, cc->fun, idx, destination,
337                                   vector);
338 }
339
340 struct pci_rx_vtbl pci_rx_vtbl = {
341     .init_pci_device_call = init_pci_device_handler,
342     .init_legacy_device_call = init_legacy_device_handler,
343     .get_cap_call = get_cap_handler,
344     .reregister_interrupt_call = reregister_interrupt_handler,
345     //.get_vbe_bios_cap_call = get_vbe_bios_cap,
346     .read_conf_header_call = read_conf_header_handler,
347     .write_conf_header_call = write_conf_header_handler,
348
349     .msix_enable_call = msix_enable_handler,
350     .msix_enable_addr_call = msix_enable_addr_handler,
351     .msix_vector_init_call = msix_vector_init_handler,
352     .msix_vector_init_addr_call = msix_vector_init_addr_handler,
353 };
354
355 static void export_callback(void *st, errval_t err, iref_t iref)
356 {
357     assert(err_is_ok(err));
358
359     err = nameservice_register("pci", iref);
360     if (err_is_fail(err)) {
361         USER_PANIC_ERR(err, "nameservice_register failed");
362     }
363 }
364
365 static errval_t connect_callback(void *cst, struct pci_binding *b)
366 {
367     struct client_state *st = malloc(sizeof(struct client_state));
368     assert(st != NULL);
369
370     b->rx_vtbl = pci_rx_vtbl;
371     b->st = st;
372 //    st->bar_info = 0;
373     st->nr_allocated_bars = 0;
374     for (int i = 0; i < PCI_NBARS; i++) {
375         st->nr_caps_bar[i] = 0;
376     }
377
378     return SYS_ERR_OK;
379 }
380
381 /*****************************************************************
382  * Boots up the PCI server:
383  *****************************************************************/
384
385 void pci_init(void)
386 {
387     PCI_DEBUG("pci: pci_init: called\n");
388
389     PCI_DEBUG("pci: pci_init: launch listening\n");
390     errval_t r = pci_export(NULL, export_callback, connect_callback,
391                             get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
392     assert(err_is_ok(r));
393
394     PCI_DEBUG("pci: pci_init: terminated\n");
395 }