3 * \brief PCI service client-side logic
7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
17 #include <barrelfish/barrelfish.h>
18 #include <barrelfish/nameservice_client.h>
19 #include <barrelfish/dispatch.h>
20 #include <barrelfish/inthandler.h>
22 #include <pci/pci_client_debug.h>
23 #include <if/pci_defs.h>
24 #include <if/pci_rpcclient_defs.h>
25 #include <acpi_client/acpi_client.h>
27 #define INVALID_VECTOR ((uint32_t)-1)
29 static struct pci_rpc_client *pci_client = NULL;
31 errval_t pci_reregister_irq_for_device(uint32_t class, uint32_t subclass, uint32_t prog_if,
32 uint32_t vendor, uint32_t device,
33 uint32_t bus, uint32_t dev, uint32_t fun,
34 interrupt_handler_fn handler,
36 interrupt_handler_fn reloc_handler,
37 void *reloc_handler_arg)
39 uint32_t vector = INVALID_VECTOR;
42 if (handler != NULL && reloc_handler != NULL) {
43 // register movable interrupt
44 err = inthandler_setup_movable(handler, handler_arg, reloc_handler,
45 reloc_handler_arg, &vector);
46 if (err_is_fail(err)) {
50 assert(vector != INVALID_VECTOR);
51 } else if (handler != NULL) {
52 // register non-movable interrupt
53 err = inthandler_setup(handler, handler_arg, &vector);
54 if (err_is_fail(err)) {
58 assert(vector != INVALID_VECTOR);
61 err = pci_client->vtbl.
62 reregister_interrupt(pci_client, class, subclass, prog_if, vendor,
63 device, bus, dev, fun, disp_get_current_core_id(),
65 if (err_is_fail(err)) {
67 } else if (err_is_fail(msgerr)) {
73 errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, uint32_t class,
74 uint32_t subclass, uint32_t prog_if,
75 uint32_t vendor, uint32_t device,
76 uint32_t bus, uint32_t dev, uint32_t fun,
77 interrupt_handler_fn handler,
79 interrupt_handler_fn reloc_handler,
80 void *reloc_handler_arg)
82 pci_caps_per_bar_t *caps_per_bar = NULL;
86 err = pci_client->vtbl.
87 init_pci_device(pci_client, class, subclass, prog_if, vendor,
88 device, bus, dev, fun, &msgerr,
89 &nbars, &caps_per_bar);
90 if (err_is_fail(err)) {
92 } else if (err_is_fail(msgerr)) {
97 struct capref irq_src_cap;
99 // Get vector 0 of the device.
100 // For backward compatibility with function interface.
101 err = pci_client->vtbl.get_irq_cap(pci_client, 0, &msgerr, &irq_src_cap);
102 if (err_is_fail(err) || err_is_fail(msgerr)) {
103 if (err_is_ok(err)) {
106 DEBUG_ERR(err, "requesting cap for IRQ 0 of device");
110 uint32_t gsi = INVALID_VECTOR;
111 err = invoke_irq_get_vector(irq_src_cap, &gsi);
112 if (err_is_fail(err)) {
113 DEBUG_ERR(err, "Could not lookup GSI vector");
116 PCI_CLIENT_DEBUG("Got irq cap, gsi: %"PRIu32"\n", gsi);
118 // Get irq_dest_cap from monitor
119 struct capref irq_dest_cap;
120 err = alloc_dest_irq_cap(&irq_dest_cap);
121 if(err_is_fail(err)){
122 DEBUG_ERR(err, "Could not allocate dest irq cap");
125 uint32_t irq_dest_vec = INVALID_VECTOR;
126 err = invoke_irqvector_get_vector(irq_dest_cap, &irq_dest_vec);
127 if (err_is_fail(err)) {
128 DEBUG_ERR(err, "Could not lookup irq vector");
131 PCI_CLIENT_DEBUG("Got dest cap, vector: %"PRIu32"\n", irq_dest_vec);
135 // TODO: Instead of getting the vectors of each cap and set up routing,
136 // pass both to a routing service and let the service handle the setup.
137 struct acpi_rpc_client* cl = get_acpi_rpc_client();
139 err = cl->vtbl.enable_and_route_interrupt(cl, gsi, disp_get_core_id(), irq_dest_vec, &ret_error);
140 assert(err_is_ok(err));
141 if (err_is_fail(ret_error)) {
142 DEBUG_ERR(ret_error, "failed to route interrupt %d -> %d\n", gsi, irq_dest_vec);
143 return err_push(ret_error, PCI_ERR_ROUTING_IRQ);
146 // Connect endpoint to handler
148 err = inthandler_setup_movable_cap(irq_dest_cap, handler, handler_arg,
149 reloc_handler, reloc_handler_arg);
150 if (err_is_fail(err)) {
156 assert(nbars > 0); // otherwise we should have received an error!
159 struct device_mem *bars = calloc(nbars, sizeof(struct device_mem));
160 assert(bars != NULL);
162 // request caps for all bars of device
163 for (int nb = 0; nb < nbars; nb++) {
164 struct device_mem *bar = &bars[nb];
166 int ncaps = (*caps_per_bar)[nb];
168 bar->nr_caps = ncaps;
169 bar->frame_cap = malloc(ncaps * sizeof(struct capref)); // FIXME: leak
170 assert(bar->frame_cap != NULL);
173 for (int nc = 0; nc < ncaps; nc++) {
177 err = pci_client->vtbl.get_bar_cap(pci_client, nb, nc, &msgerr, &cap,
178 &type, &bar->bar_nr);
179 if (err_is_fail(err) || err_is_fail(msgerr)) {
180 if (err_is_ok(err)) {
183 DEBUG_ERR(err, "requesting cap %d for BAR %d of device", nc, nb);
187 if (type == 0) { // Frame cap BAR
188 bar->frame_cap[nc] = cap;
190 struct frame_identity id = { .base = 0, .bits = 0 };
191 invoke_frame_identify(cap, &id);
192 bar->paddr = id.base;
194 bar->bytes = (1ul << id.bits) * ncaps;
198 err = cap_copy(cap_io, cap);
199 if(err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
200 DEBUG_ERR(err, "cap_copy for IO cap");
207 // initialize the device. We have all the caps now
208 init_func(bars, nbars);
217 errval_t pci_register_driver_irq(pci_driver_init_fn init_func, uint32_t class,
218 uint32_t subclass, uint32_t prog_if,
219 uint32_t vendor, uint32_t device,
220 uint32_t bus, uint32_t dev, uint32_t fun,
221 interrupt_handler_fn handler,
224 return pci_register_driver_movable_irq(init_func, class, subclass,
225 prog_if, vendor, device, bus, dev, fun, handler, handler_arg,
230 errval_t pci_register_driver_noirq(pci_driver_init_fn init_func, uint32_t class,
231 uint32_t subclass, uint32_t prog_if,
232 uint32_t vendor, uint32_t device,
233 uint32_t bus, uint32_t dev, uint32_t fun)
235 return pci_register_driver_irq(init_func, class, subclass, prog_if, vendor,
236 device, bus, dev, fun, NULL, NULL);
239 errval_t pci_register_legacy_driver_irq(legacy_driver_init_fn init_func,
240 uint16_t iomin, uint16_t iomax, int irq,
241 interrupt_handler_fn handler,
244 errval_t err, msgerr;
247 uint32_t vector = INVALID_VECTOR;
248 err = inthandler_setup(handler, handler_arg, &vector);
249 if (err_is_fail(err)) {
250 DEBUG_ERR(err, "inthandler_setup()\n");
254 err = pci_client->vtbl.init_legacy_device(pci_client, iomin, iomax, irq,
255 disp_get_core_id(), vector,
257 if (err_is_fail(err)) {
258 DEBUG_ERR(err, "pci_client->init_legacy_device()\n");
260 } else if (err_is_fail(msgerr)) {
261 DEBUG_ERR(msgerr, "pci_client->init_legacy_device()\n");
265 /* copy IO cap to default location */
266 err = cap_copy(cap_io, iocap);
267 if (err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
268 DEBUG_ERR(err, "failed to copy legacy io cap to default slot\n");
271 err = cap_destroy(iocap);
272 assert(err_is_ok(err));
280 errval_t pci_setup_inthandler(interrupt_handler_fn handler, void *handler_arg,
284 uint32_t vector = INVALID_VECTOR;
286 err = inthandler_setup(handler, handler_arg, &vector);
287 if (err_is_ok(err)) {
288 *ret_vector = vector + 32; // FIXME: HACK
293 errval_t pci_read_conf_header(uint32_t dword, uint32_t *val)
295 errval_t err, msgerr;
296 err = pci_client->vtbl.read_conf_header(pci_client, dword, &msgerr, val);
297 return err_is_fail(err) ? err : msgerr;
300 errval_t pci_write_conf_header(uint32_t dword, uint32_t val)
302 errval_t err, msgerr;
303 err = pci_client->vtbl.write_conf_header(pci_client, dword, val, &msgerr);
304 return err_is_fail(err) ? err : msgerr;
307 errval_t pci_msix_enable_addr(struct pci_address *addr, uint16_t *count)
309 errval_t err, msgerr;
311 err = pci_client->vtbl.msix_enable(pci_client, &msgerr, count);
313 err = pci_client->vtbl.msix_enable_addr(pci_client, addr->bus, addr->device,
314 addr->function, &msgerr, count);
316 return err_is_fail(err) ? err : msgerr;
319 errval_t pci_msix_enable(uint16_t *count)
321 return pci_msix_enable_addr(NULL, count);
324 errval_t pci_msix_vector_init_addr(struct pci_address *addr, uint16_t idx,
325 uint8_t destination, uint8_t vector)
327 errval_t err, msgerr;
329 err = pci_client->vtbl.msix_vector_init(pci_client, idx, destination,
332 err = pci_client->vtbl.msix_vector_init_addr(pci_client, addr->bus,
333 addr->device, addr->function,
338 return err_is_fail(err) ? err : msgerr;
341 errval_t pci_msix_vector_init(uint16_t idx, uint8_t destination,
344 return pci_msix_vector_init_addr(NULL, idx, destination, vector);
347 static void bind_cont(void *st, errval_t err, struct pci_binding *b)
349 errval_t *reterr = st;
350 if (err_is_ok(err)) {
351 struct pci_rpc_client *r = malloc(sizeof(*r));
353 err = pci_rpc_client_init(r, b);
354 if (err_is_ok(err)) {
363 errval_t pci_client_connect(void)
366 errval_t err, err2 = SYS_ERR_OK;
368 err = connect_to_acpi();
369 if(err_is_fail(err)){
373 /* Connect to the pci server */
374 err = nameservice_blocking_lookup("pci", &iref);
375 if (err_is_fail(err)) {
381 /* Setup flounder connection with pci server */
382 err = pci_bind(iref, bind_cont, &err2, get_default_waitset(),
383 IDC_BIND_FLAG_RPC_CAP_TRANSFER);
384 if (err_is_fail(err)) {
388 /* XXX: Wait for connection establishment */
389 while (pci_client == NULL && err2 == SYS_ERR_OK) {
390 messages_wait_and_handle_next();