X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FInterfaces%2FUDI%2Ftrans%2Fbus_pci.c;h=daf07f27fdbc7c8f160021090a7e5a7281916303;hb=e2ff5722101ae7dbb10f51f1477eac625fa30c1e;hp=b586947725d30d5ec95fca40ae0d20f68d2ec59c;hpb=35f7d0523c463a6b6cc4d859c2e05234bdb0c6b8;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c b/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c index b5869477..daf07f27 100644 --- a/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c +++ b/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c @@ -5,10 +5,14 @@ * trans/bus_pci.c * - PCI Bus Driver */ +#define DEBUG 1 #include #include +#include #include #include // acess +#include +#include // === MACROS === /* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */ @@ -36,6 +40,10 @@ (attr)->attr_length = (len); \ udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len)) +#define PCI_OPS_BRIDGE 1 +#define PCI_OPS_IRQ 2 + +#define PCI_MAX_EVENT_CBS 8 // === TYPES === typedef struct @@ -45,6 +53,25 @@ typedef struct tPCIDev cur_iter; } pci_rdata_t; +typedef struct +{ + udi_child_chan_context_t child_chan_context; + + udi_channel_t interrupt_channel; + struct { + tPAddr paddr; + void *vaddr; + size_t length; + } bars[6]; + + int interrupt_handle; + + udi_pio_handle_t intr_preprocessing; + udi_intr_event_cb_t *event_cbs[PCI_MAX_EVENT_CBS]; + int event_cb_wr_ofs; + int event_cb_rd_ofs; +} pci_child_chan_context_t; + // === PROTOTYPES === void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level); void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level); @@ -55,13 +82,41 @@ void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb); void pci_unbind_req(udi_bus_bind_cb_t *cb); void pci_bind_req_op(udi_bus_bind_cb_t *cb); void pci_intr_attach_req(udi_intr_attach_cb_t *cb); +void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel); void pci_intr_detach_req(udi_intr_detach_cb_t *cb); +void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb); +void pci_intr_event_rdy(udi_intr_event_cb_t *cb); +void pci_intr_handler(int irq, void *void_context); +void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result); + +// - Hook to physio (UDI doesn't define these) + int pci_pio_get_regset(udi_cb_t *gcb, udi_ubit32_t regset_idx, void **baseptr, size_t *lenptr); // === CODE === void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level) { - UNIMPLEMENTED(); + pci_rdata_t *rdata = UDI_GCB(cb)->context; + + switch(cb->meta_idx) + { + case 1: // mgmt + break; + } + + switch(resource_level) + { + case UDI_RESOURCES_CRITICAL: + case UDI_RESOURCES_LOW: + case UDI_RESOURCES_NORMAL: + case UDI_RESOURCES_PLENTIFUL: + break; + } + + // TODO: Initialise rdata + rdata->cur_iter = -1; + + udi_usage_res(cb); } void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level) { @@ -83,7 +138,16 @@ void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level) Uint16 ven, dev; Uint32 class; PCI_GetDeviceInfo(rdata->cur_iter, &ven, &dev, &class); + Uint8 revision; + PCI_GetDeviceVersion(rdata->cur_iter, &revision); + Uint16 sven, sdev; + PCI_GetDeviceSubsys(rdata->cur_iter, &sven, &sdev); + udi_strcpy(attr_list->attr_name, "identifier"); + attr_list->attr_length = sprintf((char*)attr_list->attr_value, + "%04x%04x%02x%04x%04x", + ven, dev, revision, sven, sdev); + attr_list ++; DPT_SET_ATTR_STRING(attr_list, "bus_type", "pci", 3); attr_list ++; DPT_SET_ATTR32(attr_list, "pci_vendor_id", ven); @@ -92,7 +156,8 @@ void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level) attr_list ++; cb->attr_valid_length = attr_list - cb->attr_list; - udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 0); + cb->child_ID = rdata->cur_iter; + udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 1); } break; } @@ -110,23 +175,159 @@ void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb) { UNIMPLEMENTED(); } -void pci_unbind_req(udi_bus_bind_cb_t *cb) +void pci_bind_req(udi_bus_bind_cb_t *cb) { - UNIMPLEMENTED(); + // TODO: "Lock" PCI device + + // TODO: DMA constraints + udi_bus_bind_ack(cb, 0, UDI_DMA_LITTLE_ENDIAN, UDI_OK); } -void pci_bind_req_op(udi_bus_bind_cb_t *cb) +void pci_unbind_req(udi_bus_bind_cb_t *cb) { UNIMPLEMENTED(); } void pci_intr_attach_req(udi_intr_attach_cb_t *cb) { - UNIMPLEMENTED(); + pci_child_chan_context_t *context = UDI_GCB(cb)->context; + + ASSERT(cb->interrupt_idx == 0); + + context->intr_preprocessing = cb->preprocessing_handle; + // Check if interrupt is already bound + if( !UDI_HANDLE_IS_NULL(context->interrupt_channel, udi_channel_t) ) + { + udi_intr_attach_ack(cb, UDI_OK); + return ; + } + // Create a channel + udi_channel_spawn(pci_intr_attach_req__channel_spawned, UDI_GCB(cb), + cb->gcb.channel, cb->interrupt_idx, PCI_OPS_IRQ, context); +} +void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel) +{ + udi_intr_attach_cb_t *cb = UDI_MCB(gcb, udi_intr_attach_cb_t); + pci_child_chan_context_t *context = UDI_GCB(cb)->context; + + if( UDI_HANDLE_IS_NULL(new_channel, udi_channel_t) ) + { + // oops + return ; + } + + context->interrupt_channel = new_channel; + + context->interrupt_handle = IRQ_AddHandler( + PCI_GetIRQ(context->child_chan_context.child_ID), + pci_intr_handler, new_channel); + + udi_intr_attach_ack(cb, UDI_OK); } void pci_intr_detach_req(udi_intr_detach_cb_t *cb) { UNIMPLEMENTED(); } +void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb) +{ + UNIMPLEMENTED(); +} +void pci_intr_event_rdy(udi_intr_event_cb_t *cb) +{ + pci_child_chan_context_t *context = UDI_GCB(cb)->context; + if( context->event_cbs[context->event_cb_wr_ofs] ) + { + // oops, overrun. + return ; + } + context->event_cbs[context->event_cb_wr_ofs++] = cb; + if( context->event_cb_wr_ofs == PCI_MAX_EVENT_CBS ) + context->event_cb_wr_ofs = 0; +} + +void pci_intr_handler(int irq, void *void_context) +{ + pci_child_chan_context_t *context = void_context; + + if( context->event_cb_rd_ofs == context->event_cb_wr_ofs ) { + // Dropped + return ; + } + + udi_intr_event_cb_t *cb = context->event_cbs[context->event_cb_rd_ofs]; + context->event_cbs[context->event_cb_rd_ofs] = NULL; + context->event_cb_rd_ofs ++; + if( context->event_cb_rd_ofs == PCI_MAX_EVENT_CBS ) + context->event_cb_rd_ofs = 0; + + if( UDI_HANDLE_IS_NULL(context->intr_preprocessing, udi_pio_handle_t) ) + { + udi_intr_event_ind(cb, 0); + } + else + { + // Processing + // - no event info, so mem_ptr=NULL + udi_pio_trans(pci_intr_handle__trans_done, UDI_GCB(cb), + context->intr_preprocessing, 1, cb->event_buf, NULL); + } +} + +void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result) +{ + udi_intr_event_cb_t *cb = UDI_MCB(gcb, udi_intr_event_cb_t); + + cb->intr_result = result; + + udi_intr_event_ind(cb, UDI_INTR_PREPROCESSED); +} + +// - physio hooks +udi_status_t pci_pio_do_io(uint32_t child_ID, udi_ubit32_t regset_idx, udi_ubit32_t ofs, udi_ubit8_t len, + void *data, bool isOutput) +{ +// LOG("child_ID=%i, regset_idx=%i,ofs=0x%x,len=%i,data=%p,isOutput=%b", +// child_ID, regset_idx, ofs, len, data, isOutput); + tPCIDev pciid = child_ID; + // TODO: Cache child mappings + + switch(regset_idx) + { + case UDI_PCI_CONFIG_SPACE: + // TODO: + return UDI_STAT_NOT_SUPPORTED; + case UDI_PCI_BAR_0 ... UDI_PCI_BAR_5: { + Uint64 bar = PCI_GetBAR(pciid, regset_idx); + if(bar & 1) + { + // IO BAR + bar &= ~3; + #define _IO(fc, type) do {\ + if( isOutput ) out##fc(bar+ofs, *(type*)data); \ + else *(type*)data = in##fc(bar+ofs); \ + } while(0) + switch(len) + { + case UDI_PIO_1BYTE: _IO(b, udi_ubit8_t); return UDI_OK; + case UDI_PIO_2BYTE: _IO(w, udi_ubit16_t); return UDI_OK; + case UDI_PIO_4BYTE: _IO(d, udi_ubit32_t); return UDI_OK; + //case UDI_PIO_8BYTE: _IO(q, uint64_t); return UDI_OK; + default: + return UDI_STAT_NOT_SUPPORTED; + } + #undef _IO + } + else + { + // Memory BAR + bar = PCI_GetValidBAR(pciid, regset_idx, PCI_BARTYPE_MEM); + return UDI_STAT_NOT_SUPPORTED; + } + break; } + default: + return UDI_STAT_NOT_UNDERSTOOD; + } +} + // === UDI Functions === udi_mgmt_ops_t pci_mgmt_ops = { pci_usage_ind, @@ -137,12 +338,17 @@ udi_mgmt_ops_t pci_mgmt_ops = { udi_ubit8_t pci_mgmt_op_flags[4] = {0,0,0,0}; udi_bus_bridge_ops_t pci_bridge_ops = { pci_bridge_ch_event_ind, + pci_bind_req, pci_unbind_req, - pci_bind_req_op, pci_intr_attach_req, pci_intr_detach_req }; udi_ubit8_t pci_bridge_op_flags[5] = {0,0,0,0,0}; +udi_intr_dispatcher_ops_t pci_irq_ops = { + pci_intr_ch_event_ind, + pci_intr_event_rdy +}; +udi_ubit8_t pci_irq_ops_flags[2] = {0,0}; udi_primary_init_t pci_pri_init = { .mgmt_ops = &pci_mgmt_ops, .mgmt_op_flags = pci_mgmt_op_flags, @@ -154,11 +360,17 @@ udi_primary_init_t pci_pri_init = { }; udi_ops_init_t pci_ops_list[] = { { - 1, 1, UDI_BUS_BRIDGE_OPS_NUM, - 0, + PCI_OPS_BRIDGE, 1, UDI_BUS_BRIDGE_OPS_NUM, + sizeof(pci_child_chan_context_t), (udi_ops_vector_t*)&pci_bridge_ops, pci_bridge_op_flags }, + { + PCI_OPS_IRQ, 1, UDI_BUS_INTR_DISPATCH_OPS_NUM, + 0, + (udi_ops_vector_t*)&pci_irq_ops, + pci_irq_ops_flags + }, {0} }; udi_init_t pci_init = { @@ -178,6 +390,7 @@ const char pci_udiprops[] = "requires udi 0x101\0" "provides udi_bridge 0x101\0" "meta 1 udi_bridge\0" + "enumerates 4 0 100 1 bus_name string pci\0" "region 0\0" "child_bind_ops 1 0 1\0" "";