3 * \brief PCI service code
5 * This file exports the PCI service interface for drivers
9 * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
10 * All rights reserved.
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.
20 #include <barrelfish/barrelfish.h>
21 #include <barrelfish/nameservice_client.h>
22 #include <barrelfish/sys_debug.h>
24 #include <if/pci_defs.h>
25 #include <if/acpi_rpcclient_defs.h>
27 #include <acpi_client/acpi_client.h>
29 //#include "pci_confspace.h"
32 #include "pci_debug.h"
34 /*****************************************************************
36 *****************************************************************/
39 * XXX: this assumes only one driver per client */
41 // struct device_mem *bar_info;
43 int nr_allocated_bars;
44 uint32_t nr_caps_bar[PCI_NBARS];
52 /*****************************************************************
54 *****************************************************************/
56 cc->bus = cc->dev = cc->fun = 0;
59 static void init_pci_device_handler(struct pci_binding *b,
60 uint32_t class_code, uint32_t sub_class,
61 uint32_t prog_if, uint32_t vendor_id,
63 uint32_t bus, uint32_t dev, uint32_t fun)
65 struct client_state *cc = (struct client_state *) b->st;
69 err = device_init(class_code, sub_class, prog_if, vendor_id, device_id,
70 &bus, &dev, &fun, &(cc->pcie), &(cc->nr_allocated_bars));
76 for (int i = 0; i < cc->nr_allocated_bars; i++) {
77 cc->nr_caps_bar[i] = pci_get_nr_caps_for_bar(bus, dev, fun, i);
80 if (err_is_fail(err)) {
81 err = b->tx_vtbl.init_pci_device_response(b, NOP_CONT, err, 0,
90 err = b->tx_vtbl.init_pci_device_response(b, NOP_CONT, err,
91 cc->nr_allocated_bars,
100 assert(err_is_ok(err));
103 static void irq_enable_handler(struct pci_binding *b)
105 struct client_state *cc = (struct client_state *) b->st;
106 if(!cc->initialized){
107 b->tx_vtbl.irq_enable_response(b, NOP_CONT, PCI_ERR_DEVICE_NOT_INIT);
111 pci_enable_interrupt_for_device(cc->bus, cc->dev, cc->fun, cc->pcie);
112 b->tx_vtbl.irq_enable_response(b, NOP_CONT, SYS_ERR_OK);
115 static void init_legacy_device_handler(struct pci_binding *b,
116 uint16_t iomin, uint16_t iomax,
117 uint8_t irq, coreid_t coreid,
120 struct capref iocap = NULL_CAP;
121 errval_t e = SYS_ERR_OK;
123 PCI_DEBUG("pci: init_legacy_device_handler: called. irq:%"PRIu8", coreid:%"PRIuCOREID", vector:%"PRIu32"\n", irq, coreid, vector);
125 /* TODO: make sure nobody else has claimed iomin-iomax range */
127 /* construct iocap for this region */
128 if (iomin != 0 || iomax != 0) {
129 e = slot_alloc(&iocap);
130 if (err_is_fail(e)) {
131 e = err_push(e, LIB_ERR_SLOT_ALLOC);
135 e = cap_mint(iocap, cap_io, iomin, iomax);
136 if (err_is_fail(e)) {
137 e = err_push(e, PCI_ERR_MINT_IOCAP);
142 /* determine IOAPIC INTI for given GSI and map to core */
143 if (vector != (uint32_t)-1) {
145 struct acpi_rpc_client* cl = get_acpi_rpc_client();
147 e = cl->vtbl.enable_and_route_interrupt(cl, irq, coreid, vector, &ret_error);
148 assert(err_is_ok(e));
149 if (err_is_fail(ret_error)) {
150 DEBUG_ERR(e, "failed to route interrupt %d -> %d\n", irq, vector);
151 e = err_push(e, PCI_ERR_ROUTING_IRQ);
158 e = b->tx_vtbl.init_legacy_device_response(b, NOP_CONT, e,
159 err_is_ok(e) ? iocap : NULL_CAP);
160 if (err_is_fail(e)) {
161 DEBUG_ERR(e, "failed to send reply");
164 PCI_DEBUG("pci: init_legacy_device_handler: terminated.\n");
167 static void get_bar_cap_response_resend(void *arg);
169 static void get_bar_cap_response_cont(struct pci_binding *b, errval_t err,
170 struct capref cap, uint8_t type, uint8_t bar_nr)
173 e = b->tx_vtbl.get_bar_cap_response(b, NOP_CONT, err, cap, type, bar_nr);
175 if(err_no(e) == FLOUNDER_ERR_TX_BUSY) {
176 struct client_state *st = b->st;
177 struct pci_get_bar_cap_response__tx_args *me = malloc(sizeof(*me));
185 e = b->register_send(b, get_default_waitset(),
186 MKCONT(get_bar_cap_response_resend, b));
187 assert(err_is_ok(e));
189 USER_PANIC_ERR(e, "get_bar_cap_response");
194 static void get_bar_cap_response_resend(void *arg)
196 struct pci_binding *b = arg;
197 struct client_state *st = b->st;
198 struct pci_get_bar_cap_response__tx_args *a = st->cont_st;
199 get_bar_cap_response_cont(b, a->err, a->cap, a->type, a->bar_nr);
203 static void get_irq_cap_handler(struct pci_binding *b, uint16_t idx){
204 // TODO: This method works only for non legacy devices
205 // and supports only one interrupt per device at the moment
211 struct client_state *st = b->st;
213 // TODO: This should be part of the routing step
214 int irq = pci_setup_interrupt(st->bus, st->dev, st->fun);
215 PCI_DEBUG("pci: init_device_handler_irq: init interrupt.\n");
217 pci_enable_interrupt_for_device(st->bus, st->dev, st->fun, st->pcie);
219 PCI_DEBUG("pci: Interrupt enabled.\n");
221 err = sys_debug_create_irq_src_cap(cap, irq);
222 if (err_is_fail(err)) {
223 USER_PANIC_ERR(err, "create irq src cap failed.");
226 err = b->tx_vtbl.get_irq_cap_response(b, NOP_CONT, err, cap);
227 if (err_is_fail(err)) {
228 USER_PANIC_ERR(err, "cap response failed.");
232 static void get_bar_cap_handler(struct pci_binding *b, uint32_t idx,
235 struct client_state *st = b->st;
239 if (idx >= st->nr_allocated_bars) {
240 e = b->tx_vtbl.get_bar_cap_response(b, NOP_CONT, PCI_ERR_WRONG_INDEX,
242 assert(err_is_ok(e));
244 struct capref cap = pci_get_bar_cap_for_device(st->bus, st->dev,
245 st->fun, idx, cap_nr);
246 uint8_t type = pci_get_bar_cap_type_for_device(st->bus, st->dev,
248 uint8_t bar_nr = pci_get_bar_nr_for_index(st->bus, st->dev,
252 uint8_t type = st->bar_info[idx].type;
253 struct capref cap = NULL_CAP;
256 cap = st->bar_info[idx].frame_cap;
258 cap = st->bar_info[idx].io_cap;
262 get_bar_cap_response_cont(b, SYS_ERR_OK, cap, type, bar_nr);
266 static void get_vbe_bios_cap(struct pci_binding *b)
269 err = b->tx_vtbl.get_vbe_bios_cap_response(b, NOP_CONT, SYS_ERR_OK, biosmem,
271 assert(err_is_ok(err));
274 static void read_conf_header_handler(struct pci_binding *b, uint32_t dword)
277 struct client_state *cc = (struct client_state *) b->st;
278 struct pci_address addr = {
283 PCI_DEBUG("Read config header from %u:%u:%u\n",addr.bus, addr.device, addr.function);
284 uint32_t val = pci_read_conf_header(&addr, dword);
287 err = b->tx_vtbl.read_conf_header_response(b, NOP_CONT, SYS_ERR_OK, val);
288 assert(err_is_ok(err));
291 static void reregister_interrupt_handler(struct pci_binding *b,
292 uint32_t class_code, uint32_t sub_class,
293 uint32_t prog_if, uint32_t vendor_id,
295 uint32_t bus, uint32_t dev, uint32_t fun,
296 coreid_t coreid, uint32_t vector)
299 err = device_reregister_interrupt(coreid, vector,
300 class_code, sub_class, prog_if, vendor_id, device_id,
302 err = b->tx_vtbl.reregister_interrupt_response(b, NOP_CONT, err);
303 assert(err_is_ok(err));
306 static void write_conf_header_handler(struct pci_binding *b, uint32_t dword, uint32_t val)
308 struct client_state *cc = (struct client_state *) b->st;
309 struct pci_address addr = {
314 PCI_DEBUG("Write config header from %u:%u:%u\n",addr.bus, addr.device, addr.function);
315 pci_write_conf_header(&addr, dword, val);
318 err = b->tx_vtbl.write_conf_header_response(b, NOP_CONT, SYS_ERR_OK);
319 assert(err_is_ok(err));
322 static void msix_enable_addr_handler(struct pci_binding *b, uint8_t bus,
323 uint8_t dev, uint8_t fun)
325 struct client_state *cc = (struct client_state *) b->st;
326 struct pci_address addr;
328 /* XXX: find another way to do this */
330 if (bus == cc->bus && dev == cc->dev) {
343 debug_printf("enabling MSI-X for device (%u, %u, %u)\n", addr.bus,
344 addr.device, addr.function);
346 err = pci_msix_enable(&addr, &count);
347 err = b->tx_vtbl.msix_enable_response(b, NOP_CONT, err, count);
348 assert(err_is_ok(err));
351 static void msix_enable_handler(struct pci_binding *b)
353 struct client_state *cc = (struct client_state *) b->st;
354 msix_enable_addr_handler(b, cc->bus, cc->dev, cc->fun);
357 static void msix_vector_init_addr_handler(struct pci_binding *b, uint8_t bus,
358 uint8_t dev, uint8_t fun, uint16_t idx,
359 uint8_t destination, uint8_t vector)
361 struct client_state *cc = (struct client_state *) b->st;
362 struct pci_address addr;
364 /* XXX: find another way to do this */
366 if (bus == cc->bus && dev == cc->dev) {
376 debug_printf("initialize MSI-X vector for device (%u, %u, %u)\n", addr.bus,
377 addr.device, addr.function);
381 err = pci_msix_vector_init(&addr, idx, destination, vector);
382 err = b->tx_vtbl.msix_vector_init_response(b, NOP_CONT, err);
383 assert(err_is_ok(err));
386 static void msix_vector_init_handler(struct pci_binding *b, uint16_t idx,
387 uint8_t destination, uint8_t vector)
389 struct client_state *cc = (struct client_state *) b->st;
391 msix_vector_init_addr_handler(b, cc->bus, cc->dev, cc->fun, idx, destination,
395 struct pci_rx_vtbl pci_rx_vtbl = {
396 .init_pci_device_call = init_pci_device_handler,
397 .init_legacy_device_call = init_legacy_device_handler,
398 .get_bar_cap_call = get_bar_cap_handler,
399 .get_irq_cap_call = get_irq_cap_handler,
400 .reregister_interrupt_call = reregister_interrupt_handler,
401 //.get_vbe_bios_cap_call = get_vbe_bios_cap,
402 .read_conf_header_call = read_conf_header_handler,
403 .write_conf_header_call = write_conf_header_handler,
404 .irq_enable_call = irq_enable_handler,
406 .msix_enable_call = msix_enable_handler,
407 .msix_enable_addr_call = msix_enable_addr_handler,
408 .msix_vector_init_call = msix_vector_init_handler,
409 .msix_vector_init_addr_call = msix_vector_init_addr_handler,
412 static void export_callback(void *st, errval_t err, iref_t iref)
414 assert(err_is_ok(err));
416 err = nameservice_register("pci", iref);
417 if (err_is_fail(err)) {
418 USER_PANIC_ERR(err, "nameservice_register failed");
422 static errval_t connect_callback(void *cst, struct pci_binding *b)
424 struct client_state *st = malloc(sizeof(struct client_state));
427 b->rx_vtbl = pci_rx_vtbl;
430 st->nr_allocated_bars = 0;
431 for (int i = 0; i < PCI_NBARS; i++) {
432 st->nr_caps_bar[i] = 0;
438 /*****************************************************************
439 * Boots up the PCI server:
440 *****************************************************************/
444 PCI_DEBUG("pci: pci_init: called\n");
446 PCI_DEBUG("pci: pci_init: launch listening\n");
447 errval_t r = pci_export(NULL, export_callback, connect_callback,
448 get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
449 assert(err_is_ok(r));
451 PCI_DEBUG("pci: pci_init: terminated\n");