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 <if/acpi_rpcclient_defs.h>
26 #include <acpi_client/acpi_client.h>
28 #define INVALID_VECTOR ((uint32_t)-1)
30 static struct pci_rpc_client *pci_client = NULL;
32 errval_t pci_reregister_irq_for_device(uint32_t class, uint32_t subclass, uint32_t prog_if,
33 uint32_t vendor, uint32_t device,
34 uint32_t bus, uint32_t dev, uint32_t fun,
35 interrupt_handler_fn handler,
37 interrupt_handler_fn reloc_handler,
38 void *reloc_handler_arg)
40 uint32_t vector = INVALID_VECTOR;
43 if (handler != NULL && reloc_handler != NULL) {
44 // register movable interrupt
45 err = inthandler_setup_movable(handler, handler_arg, reloc_handler,
46 reloc_handler_arg, &vector);
47 if (err_is_fail(err)) {
51 assert(vector != INVALID_VECTOR);
52 } else if (handler != NULL) {
53 // register non-movable interrupt
54 err = inthandler_setup(handler, handler_arg, &vector);
55 if (err_is_fail(err)) {
59 assert(vector != INVALID_VECTOR);
62 err = pci_client->vtbl.
63 reregister_interrupt(pci_client, class, subclass, prog_if, vendor,
64 device, bus, dev, fun, disp_get_current_core_id(),
66 if (err_is_fail(err)) {
68 } else if (err_is_fail(msgerr)) {
74 errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, uint32_t class,
75 uint32_t subclass, uint32_t prog_if,
76 uint32_t vendor, uint32_t device,
77 uint32_t bus, uint32_t dev, uint32_t fun,
78 interrupt_handler_fn handler,
80 interrupt_handler_fn reloc_handler,
81 void *reloc_handler_arg)
83 pci_caps_per_bar_t caps_per_bar;
87 err = pci_client->vtbl.
88 init_pci_device(pci_client, class, subclass, prog_if, vendor,
89 device, bus, dev, fun, &msgerr,
90 &nbars, caps_per_bar, caps_per_bar + 1, caps_per_bar + 2,
91 caps_per_bar + 3, caps_per_bar + 4, caps_per_bar + 5);
92 if (err_is_fail(err)) {
94 } else if (err_is_fail(msgerr)) {
98 struct capref irq_src_cap;
100 // Get vector 0 of the device.
101 // For backward compatibility with function interface.
102 err = pci_client->vtbl.get_irq_cap(pci_client, 0, &msgerr, &irq_src_cap);
103 if (err_is_fail(err) || err_is_fail(msgerr)) {
104 if (err_is_ok(err)) {
107 DEBUG_ERR(err, "requesting cap for IRQ 0 of device");
111 uint32_t gsi = INVALID_VECTOR;
112 err = invoke_irqsrc_get_vector(irq_src_cap, &gsi);
113 if (err_is_fail(err)) {
114 DEBUG_ERR(err, "Could not lookup GSI vector");
117 PCI_CLIENT_DEBUG("Got irqsrc cap, gsi: %"PRIu32"\n", gsi);
119 // Get irq_dest_cap from monitor
120 struct capref irq_dest_cap;
121 err = alloc_dest_irq_cap(&irq_dest_cap);
122 if(err_is_fail(err)){
123 DEBUG_ERR(err, "Could not allocate dest irq cap");
126 uint32_t irq_dest_vec = INVALID_VECTOR;
127 err = invoke_irqdest_get_vector(irq_dest_cap, &irq_dest_vec);
128 if (err_is_fail(err)) {
129 DEBUG_ERR(err, "Could not lookup irq vector");
132 PCI_CLIENT_DEBUG("Got dest cap, vector: %"PRIu32"\n", irq_dest_vec);
136 // TODO: Instead of getting the vectors of each cap and set up routing,
137 // pass both to a routing service and let the service handle the setup.
138 struct acpi_rpc_client* cl = get_acpi_rpc_client();
140 err = cl->vtbl.enable_and_route_interrupt(cl, gsi, disp_get_core_id(), irq_dest_vec, &ret_error);
141 assert(err_is_ok(err));
142 if (err_is_fail(ret_error)) {
143 DEBUG_ERR(ret_error, "failed to route interrupt %d -> %d\n", gsi, irq_dest_vec);
144 return err_push(ret_error, PCI_ERR_ROUTING_IRQ);
147 // Connect endpoint to handler
149 err = inthandler_setup_movable_cap(irq_dest_cap, handler, handler_arg,
150 reloc_handler, reloc_handler_arg);
151 if (err_is_fail(err)) {
157 assert(nbars > 0); // otherwise we should have received an error!
160 struct device_mem *bars = calloc(nbars, sizeof(struct device_mem));
161 assert(bars != NULL);
163 // request caps for all bars of device
164 for (int nb = 0; nb < nbars; nb++) {
165 struct device_mem *bar = &bars[nb];
167 int ncaps = (caps_per_bar)[nb];
169 bar->nr_caps = ncaps;
170 bar->frame_cap = malloc(ncaps * sizeof(struct capref)); // FIXME: leak
171 assert(bar->frame_cap != NULL);
174 for (int nc = 0; nc < ncaps; nc++) {
178 err = pci_client->vtbl.get_bar_cap(pci_client, nb, nc, &msgerr, &cap,
179 &type, &bar->bar_nr);
180 if (err_is_fail(err) || err_is_fail(msgerr)) {
181 if (err_is_ok(err)) {
184 DEBUG_ERR(err, "requesting cap %d for BAR %d of device", nc, nb);
188 if (type == 0) { // Frame cap BAR
189 bar->frame_cap[nc] = cap;
191 struct frame_identity id = { .base = 0, .bytes = 0 };
192 err = invoke_frame_identify(cap, &id);
193 if (err_is_fail(err)) {
194 USER_PANIC_ERR(err, "frame identify failed.");
196 bar->paddr = id.base;
197 bar->bits = log2ceil(id.bytes);
198 bar->bytes = id.bytes * ncaps;
202 err = cap_copy(cap_io, cap);
203 if(err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
204 DEBUG_ERR(err, "cap_copy for IO cap");
211 // initialize the device. We have all the caps now
212 PCI_CLIENT_DEBUG("Succesfully done with pci init.\n");
213 init_func(bars, nbars);
221 errval_t pci_register_driver_irq(pci_driver_init_fn init_func, uint32_t class,
222 uint32_t subclass, uint32_t prog_if,
223 uint32_t vendor, uint32_t device,
224 uint32_t bus, uint32_t dev, uint32_t fun,
225 interrupt_handler_fn handler,
228 return pci_register_driver_movable_irq(init_func, class, subclass,
229 prog_if, vendor, device, bus, dev, fun, handler, handler_arg,
234 errval_t pci_register_driver_noirq(pci_driver_init_fn init_func, uint32_t class,
235 uint32_t subclass, uint32_t prog_if,
236 uint32_t vendor, uint32_t device,
237 uint32_t bus, uint32_t dev, uint32_t fun)
239 return pci_register_driver_irq(init_func, class, subclass, prog_if, vendor,
240 device, bus, dev, fun, NULL, NULL);
243 errval_t pci_register_legacy_driver_irq(legacy_driver_init_fn init_func,
244 uint16_t iomin, uint16_t iomax, int irq,
245 interrupt_handler_fn handler,
248 errval_t err, msgerr;
251 uint32_t vector = INVALID_VECTOR;
252 err = inthandler_setup(handler, handler_arg, &vector);
253 if (err_is_fail(err)) {
254 DEBUG_ERR(err, "inthandler_setup()\n");
258 err = pci_client->vtbl.init_legacy_device(pci_client, iomin, iomax, irq,
259 disp_get_core_id(), vector,
261 if (err_is_fail(err)) {
262 DEBUG_ERR(err, "pci_client->init_legacy_device()\n");
264 } else if (err_is_fail(msgerr)) {
265 DEBUG_ERR(msgerr, "pci_client->init_legacy_device()\n");
269 /* copy IO cap to default location */
270 err = cap_copy(cap_io, iocap);
271 if (err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
272 DEBUG_ERR(err, "failed to copy legacy io cap to default slot\n");
275 err = cap_destroy(iocap);
276 assert(err_is_ok(err));
284 errval_t pci_setup_inthandler(interrupt_handler_fn handler, void *handler_arg,
288 uint32_t vector = INVALID_VECTOR;
290 err = inthandler_setup(handler, handler_arg, &vector);
291 if (err_is_ok(err)) {
292 *ret_vector = vector + 32; // FIXME: HACK
297 errval_t pci_read_conf_header(uint32_t dword, uint32_t *val)
299 errval_t err, msgerr;
300 err = pci_client->vtbl.read_conf_header(pci_client, dword, &msgerr, val);
301 return err_is_fail(err) ? err : msgerr;
304 errval_t pci_write_conf_header(uint32_t dword, uint32_t val)
306 errval_t err, msgerr;
307 err = pci_client->vtbl.write_conf_header(pci_client, dword, val, &msgerr);
308 return err_is_fail(err) ? err : msgerr;
311 errval_t pci_msix_enable_addr(struct pci_address *addr, uint16_t *count)
313 errval_t err, msgerr;
315 err = pci_client->vtbl.msix_enable(pci_client, &msgerr, count);
317 err = pci_client->vtbl.msix_enable_addr(pci_client, addr->bus, addr->device,
318 addr->function, &msgerr, count);
320 return err_is_fail(err) ? err : msgerr;
323 errval_t pci_msix_enable(uint16_t *count)
325 return pci_msix_enable_addr(NULL, count);
328 errval_t pci_msix_vector_init_addr(struct pci_address *addr, uint16_t idx,
329 uint8_t destination, uint8_t vector)
331 errval_t err, msgerr;
333 err = pci_client->vtbl.msix_vector_init(pci_client, idx, destination,
336 err = pci_client->vtbl.msix_vector_init_addr(pci_client, addr->bus,
337 addr->device, addr->function,
342 return err_is_fail(err) ? err : msgerr;
345 errval_t pci_msix_vector_init(uint16_t idx, uint8_t destination,
348 return pci_msix_vector_init_addr(NULL, idx, destination, vector);
351 static void bind_cont(void *st, errval_t err, struct pci_binding *b)
353 errval_t *reterr = st;
354 if (err_is_ok(err)) {
355 struct pci_rpc_client *r = malloc(sizeof(*r));
357 err = pci_rpc_client_init(r, b);
358 if (err_is_ok(err)) {
367 errval_t pci_client_connect(void)
370 errval_t err, err2 = SYS_ERR_OK;
372 err = connect_to_acpi();
373 if(err_is_fail(err)){
377 /* Connect to the pci server */
378 err = nameservice_blocking_lookup("pci", &iref);
379 if (err_is_fail(err)) {
385 /* Setup flounder connection with pci server */
386 err = pci_bind(iref, bind_cont, &err2, get_default_waitset(),
387 IDC_BIND_FLAG_RPC_CAP_TRANSFER);
388 if (err_is_fail(err)) {
392 /* XXX: Wait for connection establishment */
393 while (pci_client == NULL && err2 == SYS_ERR_OK) {
394 messages_wait_and_handle_next();