Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 206810
b: refs/heads/master
c: a48777e
h: refs/heads/master
v: v3
  • Loading branch information
Clemens Ladisch committed Jun 10, 2010
1 parent 231607d commit 8059d75
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 63 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9ab5071cd4a16001e4ba790172a7da5e4172462b
refs/heads/master: a48777e03ad53777ed119a5f86dd22a6c5a378ad
14 changes: 11 additions & 3 deletions trunk/drivers/firewire/core-transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,17 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
rcode = RCODE_TYPE_ERROR;
break;

case CSR_BUS_TIME:
if (tcode == TCODE_READ_QUADLET_REQUEST)
*data = cpu_to_be32(card->driver->
read_csr_reg(card, CSR_BUS_TIME));
else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
card->driver->write_csr_reg(card, CSR_BUS_TIME,
be32_to_cpu(*data));
else
rcode = RCODE_TYPE_ERROR;
break;

case CSR_BROADCAST_CHANNEL:
if (tcode == TCODE_READ_QUADLET_REQUEST)
*data = cpu_to_be32(card->broadcast_channel);
Expand Down Expand Up @@ -1132,9 +1143,6 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
case CSR_BUSY_TIMEOUT:
/* FIXME: Implement this. */

case CSR_BUS_TIME:
/* Useless without initialization by the bus manager. */

default:
rcode = RCODE_ADDRESS_ERROR;
break;
Expand Down
168 changes: 109 additions & 59 deletions trunk/drivers/firewire/ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ struct fw_ohci {
int generation;
int request_generation; /* for timestamping incoming requests */
unsigned quirks;
u32 bus_time;

/*
* Spinlock for accessing fw_ohci data. Never call out of
Expand Down Expand Up @@ -292,7 +293,7 @@ static void log_irqs(u32 evt)
!(evt & OHCI1394_busReset))
return;

fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
evt & OHCI1394_selfIDComplete ? " selfID" : "",
evt & OHCI1394_RQPkt ? " AR_req" : "",
evt & OHCI1394_RSPkt ? " AR_resp" : "",
Expand All @@ -302,14 +303,16 @@ static void log_irqs(u32 evt)
evt & OHCI1394_isochTx ? " IT" : "",
evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "",
evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
evt & OHCI1394_busReset ? " busReset" : "",
evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
OHCI1394_RSPkt | OHCI1394_reqTxComplete |
OHCI1394_respTxComplete | OHCI1394_isochRx |
OHCI1394_isochTx | OHCI1394_postedWriteErr |
OHCI1394_cycleTooLong | OHCI1394_cycleInconsistent |
OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
OHCI1394_cycleInconsistent |
OHCI1394_regAccessFail | OHCI1394_busReset)
? " ?" : "");
}
Expand Down Expand Up @@ -1316,6 +1319,78 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet)

}

static u32 cycle_timer_ticks(u32 cycle_timer)
{
u32 ticks;

ticks = cycle_timer & 0xfff;
ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
ticks += (3072 * 8000) * (cycle_timer >> 25);

return ticks;
}

/*
* Some controllers exhibit one or more of the following bugs when updating the
* iso cycle timer register:
* - When the lowest six bits are wrapping around to zero, a read that happens
* at the same time will return garbage in the lowest ten bits.
* - When the cycleOffset field wraps around to zero, the cycleCount field is
* not incremented for about 60 ns.
* - Occasionally, the entire register reads zero.
*
* To catch these, we read the register three times and ensure that the
* difference between each two consecutive reads is approximately the same, i.e.
* less than twice the other. Furthermore, any negative difference indicates an
* error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
* execute, so we have enough precision to compute the ratio of the differences.)
*/
static u32 get_cycle_time(struct fw_ohci *ohci)
{
u32 c0, c1, c2;
u32 t0, t1, t2;
s32 diff01, diff12;
int i;

c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);

if (ohci->quirks & QUIRK_CYCLE_TIMER) {
i = 0;
c1 = c2;
c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
do {
c0 = c1;
c1 = c2;
c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
t0 = cycle_timer_ticks(c0);
t1 = cycle_timer_ticks(c1);
t2 = cycle_timer_ticks(c2);
diff01 = t1 - t0;
diff12 = t2 - t1;
} while ((diff01 <= 0 || diff12 <= 0 ||
diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
&& i++ < 20);
}

return c2;
}

/*
* This function has to be called at least every 64 seconds. The bus_time
* field stores not only the upper 25 bits of the BUS_TIME register but also
* the most significant bit of the cycle timer in bit 6 so that we can detect
* changes in this bit.
*/
static u32 update_bus_time(struct fw_ohci *ohci)
{
u32 cycle_time_seconds = get_cycle_time(ohci) >> 25;

if ((ohci->bus_time & 0x40) != (cycle_time_seconds & 0x40))
ohci->bus_time += 0x40;

return ohci->bus_time | cycle_time_seconds;
}

static void bus_reset_tasklet(unsigned long data)
{
struct fw_ohci *ohci = (struct fw_ohci *)data;
Expand Down Expand Up @@ -1520,6 +1595,12 @@ static irqreturn_t irq_handler(int irq, void *data)
fw_notify("isochronous cycle inconsistent\n");
}

if (event & OHCI1394_cycle64Seconds) {
spin_lock(&ohci->lock);
update_bus_time(ohci);
spin_unlock(&ohci->lock);
}

return IRQ_HANDLED;
}

Expand Down Expand Up @@ -1604,7 +1685,7 @@ static int ohci_enable(struct fw_card *card,
{
struct fw_ohci *ohci = fw_ohci(card);
struct pci_dev *dev = to_pci_dev(card->device);
u32 lps, irqs;
u32 lps, seconds, irqs;
int i, ret;

if (software_reset(ohci)) {
Expand Down Expand Up @@ -1652,6 +1733,10 @@ static int ohci_enable(struct fw_card *card,
(OHCI1394_MAX_AT_RESP_RETRIES << 4) |
(OHCI1394_MAX_PHYS_RESP_RETRIES << 8));

seconds = lower_32_bits(get_seconds());
reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
ohci->bus_time = seconds & ~0x3f;

ar_context_run(&ohci->ar_request_ctx);
ar_context_run(&ohci->ar_response_ctx);

Expand Down Expand Up @@ -1732,6 +1817,7 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_postedWriteErr |
OHCI1394_selfIDComplete |
OHCI1394_regAccessFail |
OHCI1394_cycle64Seconds |
OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong |
OHCI1394_masterIntEnable;
if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
Expand Down Expand Up @@ -1913,65 +1999,11 @@ static int ohci_enable_phys_dma(struct fw_card *card,
#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
}

static u32 cycle_timer_ticks(u32 cycle_timer)
{
u32 ticks;

ticks = cycle_timer & 0xfff;
ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
ticks += (3072 * 8000) * (cycle_timer >> 25);

return ticks;
}

/*
* Some controllers exhibit one or more of the following bugs when updating the
* iso cycle timer register:
* - When the lowest six bits are wrapping around to zero, a read that happens
* at the same time will return garbage in the lowest ten bits.
* - When the cycleOffset field wraps around to zero, the cycleCount field is
* not incremented for about 60 ns.
* - Occasionally, the entire register reads zero.
*
* To catch these, we read the register three times and ensure that the
* difference between each two consecutive reads is approximately the same, i.e.
* less than twice the other. Furthermore, any negative difference indicates an
* error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
* execute, so we have enough precision to compute the ratio of the differences.)
*/
static u32 get_cycle_time(struct fw_ohci *ohci)
{
u32 c0, c1, c2;
u32 t0, t1, t2;
s32 diff01, diff12;
int i;

c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);

if (ohci->quirks & QUIRK_CYCLE_TIMER) {
i = 0;
c1 = c2;
c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
do {
c0 = c1;
c1 = c2;
c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
t0 = cycle_timer_ticks(c0);
t1 = cycle_timer_ticks(c1);
t2 = cycle_timer_ticks(c2);
diff01 = t1 - t0;
diff12 = t2 - t1;
} while ((diff01 <= 0 || diff12 <= 0 ||
diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
&& i++ < 20);
}

return c2;
}

static u32 ohci_read_csr_reg(struct fw_card *card, int csr_offset)
{
struct fw_ohci *ohci = fw_ohci(card);
unsigned long flags;
u32 value;

switch (csr_offset) {
case CSR_NODE_IDS:
Expand All @@ -1980,6 +2012,17 @@ static u32 ohci_read_csr_reg(struct fw_card *card, int csr_offset)
case CSR_CYCLE_TIME:
return get_cycle_time(ohci);

case CSR_BUS_TIME:
/*
* We might be called just after the cycle timer has wrapped
* around but just before the cycle64Seconds handler, so we
* better check here, too, if the bus time needs to be updated.
*/
spin_lock_irqsave(&ohci->lock, flags);
value = update_bus_time(ohci);
spin_unlock_irqrestore(&ohci->lock, flags);
return value;

default:
WARN_ON(1);
return 0;
Expand All @@ -1989,6 +2032,7 @@ static u32 ohci_read_csr_reg(struct fw_card *card, int csr_offset)
static void ohci_write_csr_reg(struct fw_card *card, int csr_offset, u32 value)
{
struct fw_ohci *ohci = fw_ohci(card);
unsigned long flags;

switch (csr_offset) {
case CSR_NODE_IDS:
Expand All @@ -2003,6 +2047,12 @@ static void ohci_write_csr_reg(struct fw_card *card, int csr_offset, u32 value)
flush_writes(ohci);
break;

case CSR_BUS_TIME:
spin_lock_irqsave(&ohci->lock, flags);
ohci->bus_time = (ohci->bus_time & 0x7f) | (value & ~0x7f);
spin_unlock_irqrestore(&ohci->lock, flags);
break;

default:
WARN_ON(1);
break;
Expand Down

0 comments on commit 8059d75

Please sign in to comment.