// errors in PCI/device handling
errors pci PCI_ERR_ {
+ failure DEVICE_NOT_INIT "Device not initialized",
failure IOAPIC_INIT "Failed in ioapic_init()",
failure MINT_IOCAP "Failed to mint IO cap",
failure ROUTING_IRQ "Failed while routing interrupt",
acpi_interface_debug :: Bool
acpi_interface_debug = False
+acpi_service_debug :: Bool
+acpi_service_debug = False
+
acpi_server_debug :: Bool
acpi_server_debug = False
/* write PCI conf header */
rpc write_conf_header(in uint32 dword, in uint32 val, out errval err);
+
+ /* Enable (legacy) interrupt */
+ rpc irq_enable(out errval err);
/* Enable MSI-X for the specified PCI device. */
rpc msix_enable_addr(in uint8 bus, in uint8 dev, in uint8 fn,
get_cap_addr(guest_control_cap)).error;
}
-static inline errval_t invoke_irq_connect(struct capref irqcap, struct capref epcap)
+static inline errval_t invoke_irqvector_connect(struct capref irqcap, struct capref epcap)
{
- struct sysret ret = cap_invoke2(irqcap, IRQCmd_Connect, get_cap_addr(epcap));
+ struct sysret ret = cap_invoke2(irqcap, IRQVectorCmd_Connect, get_cap_addr(epcap));
+ return ret.error;
+}
+
+static inline errval_t invoke_irqvector_get_vector(struct capref irqcap, uint32_t * out_vec)
+{
+ struct sysret ret = cap_invoke1(irqcap, IRQVectorCmd_GetVector);
+ *out_vec = ret.value;
return ret.error;
}
#define BARRELFISH_SYS_DEBUG_H
#include <sys/cdefs.h>
+#include <barrelfish/caddr.h>
__BEGIN_DECLS
errval_t sys_debug_hardware_timer_hertz_read(uintptr_t* ret);
errval_t sys_debug_hardware_global_timer_read(uint64_t *ret);
errval_t sys_debug_get_apic_ticks_per_sec(uint32_t *ret);
+errval_t sys_debug_create_irq_src_cap(struct capref cap, uint16_t gsi);
#ifdef ENABLE_FEIGN_FRAME_CAP
errval_t sys_debug_feign_frame_cap(struct capref slot, lpaddr_t base,
};
/**
- * IRQ commands.
+ * IRQ Vector commands.
+ */
+
+enum irqvector_cmd {
+ IRQVectorCmd_Connect, ///< Connect this capability to a messaging channel
+ IRQVectorCmd_GetVector ///< Return the local interrupt vector
+};
+
+/**
+ * IRQ Vector commands.
*/
enum irq_cmd {
- IRQCmd_Connect, ///< Connect this capability to a messaging channel
- IRQCmd_GetVector ///< Return the local interrupt vector
+ IRQCmd_GetVector ///< Return vector and controller saved in this cap.
};
DEBUG_GET_APIC_TICKS_PER_SEC,
DEBUG_FEIGN_FRAME_CAP,
DEBUG_TRACE_PMEM_CTRL,
- DEBUG_GET_APIC_ID
+ DEBUG_GET_APIC_ID,
+ DEBUG_CREATE_IRQ_SRC_CAP
};
#endif //BARRELFISH_KPI_SYS_DEBUG_H
--- /dev/null
+#ifndef PCI_CLIENT_DEBUG_H
+#define PCI_CLIENT_DEBUG_H
+
+#if defined(PCI_CLIENT_DEBUG) || defined(GLOBAL_DEBUG)
+#define PCI_CLIENT_DEBUG(x...) printf("pci_client: " x)
+#else
+#define PCI_CLIENT_DEBUG(x...) ((void)0)
+#endif
+
+#endif
assert(irq >= 0 && irq < NDISPATCH);
struct kcb *k = kcb_current;
do {
- if (k->irq_dest_caps[irq].cap.type == ObjType_IRQVector) {
+ if (k->irq_dest_caps[irq] != NULL) {
+ assert(k->irq_dest_caps[irq]->cap.type == ObjType_IRQVector);
break;
}
k = k->next;
switch_kcb(k);
}
// from here: kcb_current is the kcb for which the interrupt was intended
- struct capability *cap = &kcb_current->irq_dest_caps[irq].cap;
+ struct capability *cap = &kcb_current->irq_dest_caps[irq]->cap;
// Return on null cap (unhandled interrupt)
if(cap->type == ObjType_Null) {
struct kcb *k = kcb_current;
bool found_free = true;
do {
- if (k->irq_dest_caps[i].cap.type == ObjType_IRQVector) {
+ if (k->irq_dest_caps[i] != NULL) {
found_free = false;
break;
}
*outvec = -1;
return SYS_ERR_IRQ_NO_FREE_VECTOR;
} else {
- //TODO Luki: Somehow we must put here a cap in the table
*outvec = i;
return SYS_ERR_OK;
}
}
+errval_t irq_debug_create_src_cap(uint8_t dcn_vbits, capaddr_t dcn, capaddr_t out_cap_addr, uint16_t gsi)
+{
+ // This method is a hack to forge a irq src cap for the given GSI targeting the ioapic
+ errval_t err;
+ struct cte out_cap;
+ memset(&out_cap, 0, sizeof(struct cte));
+
+ out_cap.cap.type = ObjType_IRQ;
+ out_cap.cap.u.irq.line = gsi;
+ const uint32_t ioapic_controller_id = 2;
+ out_cap.cap.u.irq.controller = ioapic_controller_id;
+
+ struct cte * cn;
+ err = caps_lookup_slot(&dcb_current->cspace.cap, dcn, dcn_vbits, &cn, CAPRIGHTS_WRITE);
+ if(err_is_fail(err)){
+ return err;
+ }
+ err = caps_copy_to_cnode(cn, out_cap_addr, &out_cap, 0, 0, 0);
+ if(err_is_fail(err)){
+ return err;
+ }
+
+ return SYS_ERR_OK;
+}
+
errval_t irq_table_alloc_dest_cap(uint8_t dcn_vbits, capaddr_t dcn, capaddr_t out_cap_addr)
{
errval_t err;
// TODO Luki: Figure out why it was working with i=0 before
for (i = 1; i < NDISPATCH; i++) {
//struct kcb * k = kcb_current;
- assert(kcb_current->irq_dest_caps[i].cap.type == ObjType_Null ||
- kcb_current->irq_dest_caps[i].cap.type == ObjType_IRQVector);
+ assert(kcb_current->irq_dest_caps[i] == NULL ||
+ kcb_current->irq_dest_caps[i]->cap.type == ObjType_IRQVector);
//TODO Luki: iterate over kcb
- if (kcb_current->irq_dest_caps[i].cap.type != ObjType_IRQVector) {
+ if (kcb_current->irq_dest_caps[i] == NULL) {
break;
}
}
if(err_is_fail(err)){
return err;
}
- err = caps_copy_to_cnode(cn, out_cap_addr, &out_cap, 0, 0, 0);
+ // The following lines equal
+ // caps_copy_to_cnode(cn, out_cap_addr, &out_cap, 0, 0, 0);
+ assert(cn->cap.type == ObjType_CNode);
+ struct cte *dest_cte;
+ dest_cte = caps_locate_slot(cn->cap.u.cnode.cnode, out_cap_addr);
+ err = caps_copy_to_cte(dest_cte, &out_cap, 0, 0, 0);
if(err_is_fail(err)){
return err;
}
+
+ // Link dest_cte in
+ kcb_current->irq_dest_caps[i] = dest_cte;
+
return SYS_ERR_OK;
}
}
errval_t err;
struct cte *endpoint;
+ printk(LOG_ERR, "Entering irq_connect\n");
+
// Lookup & check message endpoint cap
err = caps_lookup_slot(&dcb_current->cspace.cap, endpoint_adr,
CPTR_BITS, &endpoint, CAPRIGHTS_WRITE);
//TODO Luki: Check if this stuff is correct with multiple kcbs
uintptr_t msg[] = { 1 };
for (int i = 0; i < NDISPATCH; i++) {
- struct capability * dest_cap = &kcb->irq_dest_caps[i].cap;
+ struct capability * dest_cap = &(kcb->irq_dest_caps[i]->cap);
if (dest_cap->type == ObjType_IRQVector) {
struct capability * ep_cap = dest_cap->u.irqvector.ep;
if (ep_cap) {
}
}
// Remove endpoint. Domains must re-register by calling connect again.
- kcb->irq_dest_caps[i].cap.u.irqvector.ep->type = ObjType_Null;
+ kcb->irq_dest_caps[i]->cap.u.irqvector.ep->type = ObjType_Null;
}
}
return SYS_ERR_OK;
return SYSRET(SYS_ERR_OK);
}
-static struct sysret handle_irq_get_vector(struct capability *to, int cmd,
+static struct sysret handle_irq_get_vector(struct capability * to, int cmd,
+ uintptr_t *args)
+{
+ struct sysret ret;
+ ret.error = SYS_ERR_OK;
+ ret.value = to->u.irq.line;
+ return ret;
+
+}
+
+static struct sysret handle_irqvector_get_vector(struct capability *to, int cmd,
uintptr_t *args)
{
struct sysret ret;
return ret;
}
-static struct sysret handle_irq_connect(struct capability *to, int cmd,
+static struct sysret handle_irqvector_connect(struct capability *to, int cmd,
uintptr_t *args)
{
return SYSRET(irq_connect(to, args[0]));
[IPICmd_Send_Start] = kernel_send_start_ipi,
[IPICmd_Send_Init] = kernel_send_init_ipi,
},
+ [ObjType_IRQ] = {
+ [IRQCmd_GetVector] = handle_irq_get_vector
+ },
[ObjType_IRQVector] = {
- [IRQCmd_Connect] = handle_irq_connect,
- [IRQCmd_GetVector] = handle_irq_get_vector
+ [IRQVectorCmd_Connect] = handle_irqvector_connect,
+ [IRQVectorCmd_GetVector] = handle_irqvector_get_vector
},
[ObjType_IRQTable] = {
[IRQTableCmd_Alloc] = handle_irq_table_alloc,
retval.value = apic_get_id();
break;
+ case DEBUG_CREATE_IRQ_SRC_CAP:
+ retval.error = irq_debug_create_src_cap(arg1, args[0], args[1], args[2]);
+ break;
+
default:
printk(LOG_ERR, "invalid sys_debug msg type\n");
}
struct kcb;
errval_t irq_table_notify_domains(struct kcb *kcb);
errval_t irq_table_alloc_dest_cap(uint8_t dcn_vbits, capaddr_t dcn, capaddr_t out_cap_addr);
+errval_t irq_debug_create_src_cap(uint8_t dcn_vbits, capaddr_t dcn, capaddr_t out_cap_addr, uint16_t gsi);
#endif
//driver whose kernel_now > this kcb's kernel_off.
int64_t kernel_off;
- struct cte irq_dest_caps[NDISPATCH];
+ struct cte * irq_dest_caps[NDISPATCH];
// TODO: maybe add a shared part which can replace struct core_data?
};
}
for (int i = 0; i < NDISPATCH; i++) {
- struct capability *cap = &kcb->irq_dest_caps[i].cap;
+ struct capability *cap = &kcb->irq_dest_caps[i]->cap;
assert(cap->type != ObjType_EndPoint); // Now we store IRQVector caps here
if (cap->type == ObjType_IRQVector) {
struct capability * ep = cap->u.irqvector.ep;
return sr.error;
}
+errval_t sys_debug_create_irq_src_cap(struct capref cap, uint16_t gsi)
+{
+ uint8_t dcn_vbits = get_cnode_valid_bits(cap);
+ capaddr_t dcn_addr = get_cnode_addr(cap);
+
+ struct sysret sr = syscall6(SYSCALL_DEBUG, DEBUG_CREATE_IRQ_SRC_CAP, dcn_vbits, dcn_addr,
+ cap.slot, gsi);
+ return sr.error;
+}
+
errval_t sys_debug_get_apic_id(uint8_t *ret)
{
struct sysret sr = syscall2(SYSCALL_DEBUG, DEBUG_GET_APIC_ID);
}
// Connect dest_cap with endpoint
- invoke_irq_connect(dest_cap, epcap);
+ invoke_irqvector_connect(dest_cap, epcap);
return SYS_ERR_OK;
return err_push(err, LIB_ERR_ENDPOINT_CREATE);
}
- err = invoke_irq_connect(irq_dest_cap, epcap);
+ err = invoke_irqvector_connect(irq_dest_cap, epcap);
if (err_is_fail(err)) {
DEBUG_ERR(err, "Could not connect irq_cap and endpoint");
return err;
}
- err = invoke_irq_get_vector(irq_dest_cap, ret_vector);
+ err = invoke_irqvector_get_vector(irq_dest_cap, ret_vector);
if (err_is_fail(err)) {
DEBUG_ERR(err, "Could not lookup irq vector");
return err;
flounderBindings = [ "pci" ],
flounderExtraBindings = [ ("pci", ["rpcclient"]) ],
flounderExtraDefs = [ ("monitor_blocking",["rpcclient"]) ],
- architectures = [ "x86_64", "x86_32" ]
+ architectures = [ "x86_64", "x86_32" ],
+ addLibraries = libDeps [ "acpi_client" ]
},
-- XXX: This library is a bit weird right now.
#include <stdio.h>
#include <barrelfish/barrelfish.h>
#include <pci/mem.h>
-
-#if 0
-#define PCI_DEBUG(x...) printf("pci_client: " x)
-#else
-#define PCI_DEBUG(x...) ((void)0)
-#endif
+#include <pci/pci_client_debug.h>
errval_t map_device(struct device_mem *mem)
{
return SYS_ERR_OK; // XXX
}
- PCI_DEBUG("map_device: %lu\n", mem->bytes);
+ PCI_CLIENT_DEBUG("map_device: %lu\n", mem->bytes);
size_t offset = 0;
size_t cap_size = mem->bytes / mem->nr_caps;
}
for (int i = 0; i < mem->nr_caps; i++) {
- PCI_DEBUG("mem: map in cap nr %d\n", i);
+ PCI_CLIENT_DEBUG("mem: map in cap nr %d\n", i);
err = mem->memobj->f.fill(mem->memobj, offset, mem->frame_cap[i],
cap_size);
if (err_is_fail(err)) {
DEBUG_ERR(err, "memobj->f.fill failed");
return err_push(err, LIB_ERR_MEMOBJ_FILL);
}
- PCI_DEBUG("offset = %lu\n", offset);
+ PCI_CLIENT_DEBUG("offset = %lu\n", offset);
err = mem->memobj->f.pagefault(mem->memobj, mem->vregion, offset, 0);
if (err_is_fail(err)) {
DEBUG_ERR(err, "memobj->f.pagefault failed");
#include <barrelfish/dispatch.h>
#include <barrelfish/inthandler.h>
#include <pci/pci.h>
+#include <pci/pci_client_debug.h>
#include <if/pci_defs.h>
#include <if/pci_rpcclient_defs.h>
+#include <acpi_client/acpi_client.h>
#define INVALID_VECTOR ((uint32_t)-1)
struct capref irq_src_cap;
- // Get IRQ 0. For backward compatability with function interface
+ // Get vector 0 of the device.
+ // For backward compatibility with function interface.
err = pci_client->vtbl.get_irq_cap(pci_client, 0, &msgerr, &irq_src_cap);
if (err_is_fail(err) || err_is_fail(msgerr)) {
if (err_is_ok(err)) {
err = msgerr;
}
- DEBUG_ERR(err, "requesting cap for IRQ %d of device", 0);
+ DEBUG_ERR(err, "requesting cap for IRQ 0 of device");
goto out;
}
+ uint32_t gsi = INVALID_VECTOR;
+ err = invoke_irq_get_vector(irq_src_cap, &gsi);
+ if (err_is_fail(err)) {
+ DEBUG_ERR(err, "Could not lookup GSI vector");
+ return err;
+ }
+ PCI_CLIENT_DEBUG("Got irq cap, gsi: %"PRIu32"\n", gsi);
+
// Get irq_dest_cap from monitor
struct capref irq_dest_cap;
err = alloc_dest_irq_cap(&irq_dest_cap);
DEBUG_ERR(err, "Could not allocate dest irq cap");
goto out;
}
+ uint32_t irq_dest_vec = INVALID_VECTOR;
+ err = invoke_irqvector_get_vector(irq_dest_cap, &irq_dest_vec);
+ if (err_is_fail(err)) {
+ DEBUG_ERR(err, "Could not lookup irq vector");
+ return err;
+ }
+ PCI_CLIENT_DEBUG("Got dest cap, vector: %"PRIu32"\n", irq_dest_vec);
// Setup routing
- // TODO
+ // TODO: Instead of getting the vectors of each cap and set up routing,
+ // pass both to a routing service and let the service handle the setup.
+ struct acpi_rpc_client* cl = get_acpi_rpc_client();
+ errval_t ret_error;
+ err = cl->vtbl.enable_and_route_interrupt(cl, gsi, disp_get_core_id(), irq_dest_vec, &ret_error);
+ assert(err_is_ok(err));
+ if (err_is_fail(ret_error)) {
+ DEBUG_ERR(ret_error, "failed to route interrupt %d -> %d\n", gsi, irq_dest_vec);
+ return err_push(ret_error, PCI_ERR_ROUTING_IRQ);
+ }
// Connect endpoint to handler
if(handler != NULL){
- err = inthandler_setup_movable_cap(irq_dest_cap, handler, handler_arg, reloc_handler,
- reloc_handler_arg);
+ err = inthandler_setup_movable_cap(irq_dest_cap, handler, handler_arg,
+ reloc_handler, reloc_handler_arg);
if (err_is_fail(err)) {
return err;
}
iref_t iref;
errval_t err, err2 = SYS_ERR_OK;
+ err = connect_to_acpi();
+ if(err_is_fail(err)){
+ return err;
+ }
+
/* Connect to the pci server */
err = nameservice_blocking_lookup("pci", &iref);
if (err_is_fail(err)) {
uint32_t *bus,
uint32_t *dev,
uint32_t *fun,
+ bool *pcie,
int *nr_allocated_bars)
{
*nr_allocated_bars = 0;
char s_bus[10], s_dev[10], s_fun[10], s_vendor_id[10], s_device_id[10];
char s_class_code[10], s_sub_class[10], s_prog_if[10];
char s_pcie[5];
- bool pcie;
int error_code;
int bar_nr;
pciaddr_t bar_base, bar_high;
return err_push(err, PCI_ERR_DEVICE_INIT);
}
if (strncmp(s_pcie, "pcie", strlen("pcie")) == 0) {
- pcie = true;
+ *pcie = true;
} else {
- pcie = false;
+ *pcie = false;
}
PCI_DEBUG("device_init(): Found device at %u:%u:%u\n", *bus, *dev, *fun);
PCI_DEBUG("device_init(): Allocated caps for %d BARs\n", *nr_allocated_bars);
PCI_DEBUG("enable busmaster for device (%u, %u, %u)...\n", *bus, *dev, *fun);
- enable_busmaster(*bus, *dev, *fun, pcie);
+ enable_busmaster(*bus, *dev, *fun, *pcie);
return SYS_ERR_OK;
}
void pci_init(void);
void pci_init_datastructures(void);
-errval_t device_init(uint32_t class_code, uint32_t sub_class, uint32_t prog_if,
- uint32_t vendor_id, uint32_t device_id,
- uint32_t *bus, uint32_t *dev,uint32_t *fun,
+errval_t device_init(uint32_t class_code,
+ uint32_t sub_class,
+ uint32_t prog_if,
+ uint32_t vendor_id,
+ uint32_t device_id,
+ uint32_t *bus,
+ uint32_t *dev,
+ uint32_t *fun,
+ bool *pcie,
int *nr_allocated_bars);
errval_t device_reregister_interrupt(uint8_t coreid, int vector,
uint32_t class_code, uint32_t sub_class, uint32_t prog_if,
* XXX: this assumes only one driver per client */
struct client_state {
// struct device_mem *bar_info;
+ uint8_t initialized;
int nr_allocated_bars;
uint32_t nr_caps_bar[PCI_NBARS];
uint32_t bus;
uint32_t dev;
uint32_t fun;
+ bool pcie;
void *cont_st;
};
err = device_init(class_code, sub_class, prog_if, vendor_id, device_id,
- &bus, &dev, &fun, &(cc->nr_allocated_bars));
+ &bus, &dev, &fun, &(cc->pcie), &(cc->nr_allocated_bars));
cc->bus = bus;
cc->dev = dev;
assert(err_is_ok(err));
}
+static void irq_enable_handler(struct pci_binding *b)
+{
+ struct client_state *cc = (struct client_state *) b->st;
+ if(!cc->initialized){
+ b->tx_vtbl.irq_enable_response(b, NOP_CONT, PCI_ERR_DEVICE_NOT_INIT);
+ return;
+ }
+
+ pci_enable_interrupt_for_device(cc->bus, cc->dev, cc->fun, cc->pcie);
+ b->tx_vtbl.irq_enable_response(b, NOP_CONT, SYS_ERR_OK);
+}
+
static void init_legacy_device_handler(struct pci_binding *b,
uint16_t iomin, uint16_t iomax,
uint8_t irq, coreid_t coreid,
free(a);
}
+static void get_irq_cap_handler(struct pci_binding *b, uint16_t idx){
+ // TODO: This method hands out caps very generous.
+ errval_t err;
+ struct capref cap;
+ slot_alloc(&cap);
+ err = sys_debug_create_irq_src_cap(cap, idx);
+ b->tx_vtbl.get_irq_cap_response(b, NOP_CONT, err, cap);
+}
+
static void get_bar_cap_handler(struct pci_binding *b, uint32_t idx,
uint32_t cap_nr)
{
.init_pci_device_call = init_pci_device_handler,
.init_legacy_device_call = init_legacy_device_handler,
.get_bar_cap_call = get_bar_cap_handler,
+ .get_irq_cap_call = get_irq_cap_handler,
.reregister_interrupt_call = reregister_interrupt_handler,
//.get_vbe_bios_cap_call = get_vbe_bios_cap,
.read_conf_header_call = read_conf_header_handler,
.write_conf_header_call = write_conf_header_handler,
+ .irq_enable_call = irq_enable_handler,
.msix_enable_call = msix_enable_handler,
.msix_enable_addr_call = msix_enable_addr_handler,