From: =?utf-8?q?Kristian_H=C3=B8gsberg?= Subject: [PATCH 21/21] firewire: Implement CSR cycle time and bus time registers. Date: Wed, 7 Mar 2007 12:12:56 -0500 Signed-off-by: Kristian Høgsberg Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 26 ++++++++++++++- drivers/firewire/fw-transaction.c | 61 ++++++++++++++++++++++++++++++++++++- drivers/firewire/fw-transaction.h | 2 + 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 1e3ca5c..c80e43c 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -139,6 +139,7 @@ struct fw_ohci { int node_id; int generation; int request_generation; + u32 bus_seconds; /* Spinlock for accessing fw_ohci data. Never call out of * this driver with this lock held. */ @@ -959,7 +960,7 @@ static void bus_reset_tasklet(unsigned long data) static irqreturn_t irq_handler(int irq, void *data) { struct fw_ohci *ohci = data; - u32 event, iso_event; + u32 event, iso_event, cycle_time; int i; event = reg_read(ohci, OHCI1394_IntEventClear); @@ -1002,6 +1003,12 @@ static irqreturn_t irq_handler(int irq, void *data) iso_event &= ~(1 << i); } + if (event & OHCI1394_cycle64Seconds) { + cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + if ((cycle_time & 0x80000000) == 0) + ohci->bus_seconds++; + } + return IRQ_HANDLED; } @@ -1213,6 +1220,19 @@ ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) return retval; } +static u64 +ohci_get_bus_time(struct fw_card *card) +{ + struct fw_ohci *ohci = fw_ohci(card); + u32 cycle_time; + u64 bus_time; + + cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + bus_time = ((u64) ohci->bus_seconds << 32) | cycle_time; + + return bus_time; +} + static int handle_ir_bufferfill_packet(struct context *context, struct descriptor *d, struct descriptor *last) @@ -1686,6 +1706,7 @@ static const struct fw_card_driver ohci_driver = { .send_response = ohci_send_response, .cancel_packet = ohci_cancel_packet, .enable_phys_dma = ohci_enable_phys_dma, + .get_bus_time = ohci_get_bus_time, .allocate_iso_context = ohci_allocate_iso_context, .free_iso_context = ohci_free_iso_context, @@ -1862,7 +1883,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_reqTxComplete | OHCI1394_respTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | - OHCI1394_masterIntEnable); + OHCI1394_masterIntEnable | + OHCI1394_cycle64Seconds); bus_options = reg_read(ohci, OHCI1394_BusOptions); max_receive = (bus_options >> 12) & 0xf; diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 38b286e..d36dd51 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -752,10 +752,65 @@ handle_topology_map(struct fw_card *card, struct fw_request *request, } static struct fw_address_handler topology_map = { - .length = 0x400, + .length = 0x200, .address_callback = handle_topology_map, }; +const struct fw_address_region registers_region = + { .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, }; + +static void +handle_registers(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, + int generation, int speed, + unsigned long long offset, + void *payload, size_t length, void *callback_data) +{ + int reg = offset - CSR_REGISTER_BASE; + unsigned long long bus_time; + __be32 *data = payload; + + switch (reg) { + case CSR_CYCLE_TIME: + case CSR_BUS_TIME: + if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + break; + } + + bus_time = card->driver->get_bus_time(card); + if (reg == CSR_CYCLE_TIME) + *data = cpu_to_be32(bus_time); + else + *data = cpu_to_be32(bus_time >> 25); + fw_send_response(card, request, RCODE_COMPLETE); + break; + + case CSR_BUS_MANAGER_ID: + case CSR_BANDWIDTH_AVAILABLE: + case CSR_CHANNELS_AVAILABLE_HI: + case CSR_CHANNELS_AVAILABLE_LO: + /* FIXME: these are handled by the OHCI hardware and + * the stack never sees these request. If we add + * support for a new type of controller that doesn't + * handle this in hardware we need to deal with these + * transactions. */ + BUG(); + break; + + case CSR_BUSY_TIMEOUT: + /* FIXME: Implement this. */ + default: + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + break; + } +} + +static struct fw_address_handler registers = { + .length = 0x400, + .address_callback = handle_registers, +}; + MODULE_AUTHOR("Kristian Hoegsberg "); MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); MODULE_LICENSE("GPL"); @@ -811,6 +866,10 @@ static int __init fw_core_init(void) &topology_map_region); BUG_ON(retval < 0); + retval = fw_core_add_address_handler(®isters, + ®isters_region); + BUG_ON(retval < 0); + /* Add the vendor textual descriptor. */ retval = fw_core_add_descriptor(&vendor_id_descriptor); BUG_ON(retval < 0); diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index a661afb..855beb2 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -433,6 +433,8 @@ struct fw_card_driver { int (*enable_phys_dma) (struct fw_card *card, int node_id, int generation); + u64 (*get_bus_time) (struct fw_card *card); + struct fw_iso_context * (*allocate_iso_context)(struct fw_card *card, int sync, int tags, int type, size_t header_size);