X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FInterfaces%2FUDI%2Ftrans%2Fbus_pci.c;h=990965554acac3ceec30b5f6ebaea3270fa05f1d;hb=845b6f9d90bb87b5e760e4d49aa93b0e003ab750;hp=1c3a7c13e97b8db3dc509de2f4d3d658bf204ce9;hpb=8d3b2c5f55f648f964afe7540a9fca97ab0b17d6;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 1c3a7c13..99096555 100644 --- a/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c +++ b/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c @@ -5,12 +5,17 @@ * trans/bus_pci.c * - PCI Bus Driver */ +#define DEBUG 0 +#define UDI_VERSION 0x101 +#define UDI_PHYSIO_VERSION 0x101 +#define UDI_PCI_VERSION 0x101 #include #include #include #include #include // acess -#include "../udi_internal.h" +#include +#include // === MACROS === /* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */ @@ -38,6 +43,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 @@ -47,6 +56,26 @@ 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]; + udi_index_t event_cb_wr_ofs; + udi_index_t event_cb_rd_ofs; + int bIntrEnabled; +} 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); @@ -57,8 +86,15 @@ 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_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result); +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); @@ -123,6 +159,15 @@ void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level) attr_list ++; DPT_SET_ATTR32(attr_list, "pci_device_id", dev); attr_list ++; + + DPT_SET_ATTR32(attr_list, "pci_baseclass", class >> 16); + attr_list ++; + DPT_SET_ATTR32(attr_list, "pci_base_class", class >> 16); // E20010702.1 + attr_list ++; + DPT_SET_ATTR32(attr_list, "pci_sub_class", (class >> 8) & 0xFF); + attr_list ++; + DPT_SET_ATTR32(attr_list, "pci_prog_if", (class >> 0) & 0xFF); + attr_list ++; cb->attr_valid_length = attr_list - cb->attr_list; cb->child_ID = rdata->cur_iter; @@ -157,19 +202,155 @@ void pci_unbind_req(udi_bus_bind_cb_t *cb) } void pci_intr_attach_req(udi_intr_attach_cb_t *cb) { + 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(, UCI_GCB(cb), cb->gcb.channel, 0, PCI_OPS_IRQ, NULL); - UNIMPLEMENTED(); + 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, context); + + 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; + + ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS); + ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS); + + LOG("Rd %i, Wr %i [WR %p{%p}]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb, cb->event_buf); + 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; + + // TODO: Fire once >= min_event_pend CBs are recieved + if( !context->bIntrEnabled ) + { + context->bIntrEnabled = 1; + udi_pio_trans(pci_intr_event_rdy__irqs_enabled, NULL, context->intr_preprocessing, 0, NULL, NULL); + } +} +void pci_intr_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result) +{ + // Do nothing +} + +void pci_intr_handler(int irq, void *void_context) +{ + pci_child_chan_context_t *context = void_context; + + LOG("irq=%i, context=%p", irq, context); + + if( context->event_cb_rd_ofs == context->event_cb_wr_ofs ) { + // Dropped + return ; + } + + ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS); + ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS); + + udi_intr_event_cb_t *cb = context->event_cbs[context->event_cb_rd_ofs]; + LOG("Rd %i, Wr %i [RD %p]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb); + 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; + ASSERT(cb); + ASSERT(cb->gcb.scratch); + + if( UDI_HANDLE_IS_NULL(context->intr_preprocessing, udi_pio_handle_t) ) + { + // TODO: Ensure region is an interrupt region + udi_intr_event_ind(cb, 0); + } + else + { + // Processing + *(udi_ubit8_t*)(cb->gcb.scratch) = 0; + // - 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); + // V V V + } +} + +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); + LOG("cb(%p)->event_buf=%p, new_buf=%p", + cb, cb->event_buf, new_buf); + + // TODO: Buffers should not change + cb->event_buf = new_buf; + cb->intr_result = result; + + udi_ubit8_t intr_status = *(udi_ubit8_t*)(gcb->scratch); + if( intr_status & UDI_INTR_UNCLAIMED ) + { + // Not claimed, next please. + // NOTE: Same as no event in the acess model + LOG("Unclaimed"); + pci_intr_event_rdy(cb); + } + else if( intr_status & UDI_INTR_NO_EVENT ) + { + // No event should be generated, return cb to pool + // EVIL! + pci_intr_event_rdy(cb); + LOG("No event, return cb to pool"); + } + else + { + LOG("Inform driver"); + 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 @@ -179,14 +360,20 @@ udi_status_t pci_pio_do_io(uint32_t child_ID, udi_ubit32_t regset_idx, udi_ubit3 // TODO: return UDI_STAT_NOT_SUPPORTED; case UDI_PCI_BAR_0 ... UDI_PCI_BAR_5: { - Uint64 bar = PCI_GetBAR(pciid, regset_idx); + Uint32 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); \ + if( isOutput ) { \ + /*LOG("out"#fc"(0x%x, 0x%x)",bar+ofs,*(type*)data);*/\ + out##fc(bar+ofs, *(type*)data); \ + } \ + else { \ + *(type*)data = in##fc(bar+ofs); \ + /*LOG("in"#fc"(0x%x) = 0x%x",bar+ofs,*(type*)data);*/\ + }\ } while(0) switch(len) { @@ -202,7 +389,7 @@ udi_status_t pci_pio_do_io(uint32_t child_ID, udi_ubit32_t regset_idx, udi_ubit3 else { // Memory BAR - bar = PCI_GetValidBAR(pciid, regset_idx, PCI_BARTYPE_MEM); + //Uint64 longbar = PCI_GetValidBAR(pciid, regset_idx, PCI_BARTYPE_MEM); return UDI_STAT_NOT_SUPPORTED; } break; } @@ -227,22 +414,33 @@ udi_bus_bridge_ops_t pci_bridge_ops = { 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, .mgmt_scratch_requirement = 0, - .enumeration_attr_list_length = 4, + .enumeration_attr_list_length = 7, .rdata_size = sizeof(pci_rdata_t), .child_data_size = 0, .per_parent_paths = 0 }; udi_ops_init_t pci_ops_list[] = { { - 1, 1, UDI_BUS_BRIDGE_OPS_NUM, - sizeof(udi_child_chan_context_t), + 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 = {