1#include <pci/pci_driver_client.h> 2#include <pci/pci_driver_client_debug.h> 3#include <if/pci_driver_client_defs.h> 4#include <barrelfish/capabilities.h> 5#include <barrelfish/debug.h> 6#include <int_route/int_route_client.h> 7 8// This is only here for PCIARG defines, remove me! 9#include <pci/pci.h> 10// End 11 12const int PCI_CHANNEL_SIZE = 2048; 13 14/* 15 * Helper for constructing the pci_driver_client_frameinfo from a frame cap 16 * \param frame an existing frame cap (>=4k) 17 * \param bind create for bind or accept? 18 * \param fi output 19 */ 20static errval_t frame_to_frameinfo(struct capref frame, bool bind, struct pci_driver_client_frameinfo *fi){ 21 struct frame_identity fid; 22 errval_t err; 23 err = invoke_frame_identify(frame, &fid); 24 if(err_is_fail(err)){ 25 DEBUG_ERR(err, "invoke_frame_identify"); 26 return err; 27 } 28 PDC_DEBUG("pci ep frame base=0x%lx, size=0x%lx\n", fid.base, fid.bytes); 29 30 uint8_t *msg_buf; 31 err = vspace_map_one_frame((void*)&msg_buf, fid.bytes, frame, NULL, NULL); 32 if (err_is_fail(err)) { 33 DEBUG_ERR(err, "vspace_map_one_frame"); 34 return err; 35 } 36 37 fi->outbufsize = PCI_CHANNEL_SIZE; 38 fi->inbufsize = PCI_CHANNEL_SIZE; 39 if(bind){ 40 fi->sendbase = (lpaddr_t)msg_buf; 41 fi->inbuf = msg_buf + PCI_CHANNEL_SIZE; 42 fi->outbuf = msg_buf; 43 } else { 44 fi->sendbase = (lpaddr_t)msg_buf + PCI_CHANNEL_SIZE; 45 fi->inbuf = msg_buf; 46 fi->outbuf = msg_buf + PCI_CHANNEL_SIZE; 47 } 48 49 return SYS_ERR_OK; 50} 51 52static void pci_bind_cont(void *st, errval_t err, struct pci_driver_client_binding *_binding) { 53 //struct pcid * pcd = (struct pcid *) st; 54} 55 56static errval_t bind_to_pci(struct capref ep, struct pcid * pdc){ 57 errval_t err; 58 struct pci_driver_client_frameinfo fi; 59 err = frame_to_frameinfo(ep, true, &fi); 60 if (err_is_fail(err)) { 61 DEBUG_ERR(err, "frame_to_frameinfo"); 62 return err; 63 } 64 65 err = pci_driver_client_connect(&fi, pci_bind_cont, pdc, get_default_waitset(), 66 IDC_BIND_FLAGS_DEFAULT); 67 if (err_is_fail(err)) { 68 DEBUG_ERR(err, "pci_driver_client_connect"); 69 return err; 70 } 71 return SYS_ERR_OK; 72} 73 74static inline bool strbegins(char *str, char *start){ 75 return strncmp(str, start, strlen(start)) == 0; 76} 77 78errval_t pcid_init( 79 struct pcid * pdc, 80 struct capref* caps, 81 size_t caps_len, 82 char** args, 83 size_t args_len, 84 struct waitset * ws) 85{ 86 errval_t err; 87 pdc->ws = ws; 88 89 // all caps that are not Interrupt or PCI_EP 90 pdc->num_bars = caps_len - 2; 91 92 { 93 struct capref cnodecap; 94 err = slot_alloc_root(&cnodecap); 95 if(err_is_fail(err)){ 96 DEBUG_ERR(err, "slot_alloc_root"); 97 return err; 98 } 99 if(caps_len == 1) { 100 debug_printf("Not enough caps received\n"); 101 return PCI_ERR_NO_CAP; 102 } 103 err = cap_copy(cnodecap, caps[0]); 104 pdc->arg_cnode = build_cnoderef(cnodecap, CNODE_TYPE_OTHER); 105 } 106 107 108 // Parse pci and int_model arguments 109 bool arg_pci_found = false; 110 bool arg_int_found = false; 111 for(int i=0; i<args_len; i++) { 112 if(strbegins(args[i], "pci=")){ 113 pci_deserialize_octet(args[i] + strlen("pci="), &pdc->addr, 114 &pdc->id, &pdc->cls); 115 arg_pci_found = true; 116 } 117 if(strbegins(args[i], "int_model=") ){ 118 err = int_startup_argument_parse(args[i], &pdc->int_arg); 119 if(err_is_fail(err)){ 120 DEBUG_ERR(err, "int_startup_argument_parse"); 121 return err; 122 } 123 arg_int_found = true; 124 } 125 } 126 127 if(!arg_pci_found || !arg_int_found){ 128 debug_printf("PCI or INT arg not found"); 129 return PCI_ERR_ARG_PARSE; 130 } 131 132 // Connect to PCI endpoint 133 { 134 struct capref ep = { 135 .cnode = pdc->arg_cnode, 136 .slot = PCIARG_SLOT_PCI_EP 137 }; 138 PDC_DEBUG("binding to pci ...\n"); 139 err = bind_to_pci(ep, pdc); 140 assert(err_is_ok(err)); 141 } 142 143 // Connect to interrupt service 144 err = int_route_client_connect(); 145 if(err_is_fail(err)){ 146 DEBUG_ERR(err, "int_route_client_connect"); 147 return err; 148 149 } 150 151 return SYS_ERR_OK; 152} 153 154errval_t pcid_get_interrupt_cap(struct pcid* pdc, struct capref *ret) { 155 156 157 struct capref interrupt = { 158 .cnode = pdc->arg_cnode, 159 .slot = PCIARG_SLOT_INT, 160 }; 161 162 *ret = interrupt; 163 164 return SYS_ERR_OK; 165} 166 167errval_t pcid_get_bar_cap(struct pcid* pdc, int bar_index, struct capref *ret) { 168 169 assert(bar_index <= pdc->num_bars); 170 struct capref bar = { 171 .cnode = pdc->arg_cnode, 172 .slot = PCIARG_SLOT_BAR0 + bar_index, 173 }; 174 175 *ret = bar; 176 177 return SYS_ERR_OK; 178} 179 180size_t pcid_get_bar_num(struct pcid* pdc) 181{ 182 return pdc->num_bars; 183} 184 185errval_t pcid_connect_int_with_cap(struct capref int_src, int int_index, 186 interrupt_handler_fn handler, void *st) 187{ 188 errval_t err; 189 190 err = int_route_client_route_and_connect(int_src, int_index, 191 get_default_waitset(), handler, st); 192 193 if(err_is_fail(err)) { 194 DEBUG_ERR(err, "set-up int routing"); 195 } 196 197 return err; 198} 199 200errval_t pcid_connect_int(struct pcid* pdc, int int_index, 201 interrupt_handler_fn handler, void *st) 202{ 203 errval_t err; 204 struct capref irq_cap; 205 err = pcid_get_interrupt_cap(pdc, &irq_cap); 206 if(err_is_fail(err)){ 207 return err; 208 } 209 210 return pcid_connect_int_with_cap(irq_cap, int_index, handler, st); 211} 212 213errval_t pcid_enable_msix(int *num_vectors) { 214 //TODO RPC 215 return SYS_ERR_OK; 216} 217