|
@@ -42,6 +42,7 @@
|
|
#include <linux/string.h>
|
|
#include <linux/string.h>
|
|
#include <linux/time.h>
|
|
#include <linux/time.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
+#include <linux/workqueue.h>
|
|
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <asm/byteorder.h>
|
|
#include <asm/page.h>
|
|
#include <asm/page.h>
|
|
@@ -125,6 +126,7 @@ struct context {
|
|
struct fw_ohci *ohci;
|
|
struct fw_ohci *ohci;
|
|
u32 regs;
|
|
u32 regs;
|
|
int total_allocation;
|
|
int total_allocation;
|
|
|
|
+ u32 current_bus;
|
|
bool running;
|
|
bool running;
|
|
bool flushing;
|
|
bool flushing;
|
|
|
|
|
|
@@ -226,7 +228,7 @@ struct fw_ohci {
|
|
|
|
|
|
__le32 *self_id_cpu;
|
|
__le32 *self_id_cpu;
|
|
dma_addr_t self_id_bus;
|
|
dma_addr_t self_id_bus;
|
|
- struct tasklet_struct bus_reset_tasklet;
|
|
|
|
|
|
+ struct work_struct bus_reset_work;
|
|
|
|
|
|
u32 self_id_buffer[512];
|
|
u32 self_id_buffer[512];
|
|
};
|
|
};
|
|
@@ -263,6 +265,8 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
|
|
#define PCI_DEVICE_ID_AGERE_FW643 0x5901
|
|
#define PCI_DEVICE_ID_AGERE_FW643 0x5901
|
|
#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
|
|
#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
|
|
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
|
|
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
|
|
|
|
+#define PCI_DEVICE_ID_TI_TSB12LV26 0x8020
|
|
|
|
+#define PCI_DEVICE_ID_TI_TSB82AA2 0x8025
|
|
#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd
|
|
#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd
|
|
|
|
|
|
#define QUIRK_CYCLE_TIMER 1
|
|
#define QUIRK_CYCLE_TIMER 1
|
|
@@ -270,6 +274,7 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
|
|
#define QUIRK_BE_HEADERS 4
|
|
#define QUIRK_BE_HEADERS 4
|
|
#define QUIRK_NO_1394A 8
|
|
#define QUIRK_NO_1394A 8
|
|
#define QUIRK_NO_MSI 16
|
|
#define QUIRK_NO_MSI 16
|
|
|
|
+#define QUIRK_TI_SLLZ059 32
|
|
|
|
|
|
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
|
|
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
|
|
static const struct {
|
|
static const struct {
|
|
@@ -299,6 +304,12 @@ static const struct {
|
|
{PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID,
|
|
{PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID,
|
|
QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A},
|
|
QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A},
|
|
|
|
|
|
|
|
+ {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV26, PCI_ANY_ID,
|
|
|
|
+ QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059},
|
|
|
|
+
|
|
|
|
+ {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB82AA2, PCI_ANY_ID,
|
|
|
|
+ QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059},
|
|
|
|
+
|
|
{PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID,
|
|
{PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID,
|
|
QUIRK_RESET_PACKET},
|
|
QUIRK_RESET_PACKET},
|
|
|
|
|
|
@@ -315,6 +326,7 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
|
|
", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
|
|
", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
|
|
", no 1394a enhancements = " __stringify(QUIRK_NO_1394A)
|
|
", no 1394a enhancements = " __stringify(QUIRK_NO_1394A)
|
|
", disable MSI = " __stringify(QUIRK_NO_MSI)
|
|
", disable MSI = " __stringify(QUIRK_NO_MSI)
|
|
|
|
+ ", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059)
|
|
")");
|
|
")");
|
|
|
|
|
|
#define OHCI_PARAM_DEBUG_AT_AR 1
|
|
#define OHCI_PARAM_DEBUG_AT_AR 1
|
|
@@ -859,7 +871,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
|
|
*
|
|
*
|
|
* Alas some chips sometimes emit bus reset packets with a
|
|
* Alas some chips sometimes emit bus reset packets with a
|
|
* wrong generation. We set the correct generation for these
|
|
* wrong generation. We set the correct generation for these
|
|
- * at a slightly incorrect time (in bus_reset_tasklet).
|
|
|
|
|
|
+ * at a slightly incorrect time (in bus_reset_work).
|
|
*/
|
|
*/
|
|
if (evt == OHCI1394_evt_bus_reset) {
|
|
if (evt == OHCI1394_evt_bus_reset) {
|
|
if (!(ohci->quirks & QUIRK_RESET_PACKET))
|
|
if (!(ohci->quirks & QUIRK_RESET_PACKET))
|
|
@@ -1046,6 +1058,7 @@ static void context_tasklet(unsigned long data)
|
|
address = le32_to_cpu(last->branch_address);
|
|
address = le32_to_cpu(last->branch_address);
|
|
z = address & 0xf;
|
|
z = address & 0xf;
|
|
address &= ~0xf;
|
|
address &= ~0xf;
|
|
|
|
+ ctx->current_bus = address;
|
|
|
|
|
|
/* If the branch address points to a buffer outside of the
|
|
/* If the branch address points to a buffer outside of the
|
|
* current buffer, advance to the next buffer. */
|
|
* current buffer, advance to the next buffer. */
|
|
@@ -1713,9 +1726,94 @@ static u32 update_bus_time(struct fw_ohci *ohci)
|
|
return ohci->bus_time | cycle_time_seconds;
|
|
return ohci->bus_time | cycle_time_seconds;
|
|
}
|
|
}
|
|
|
|
|
|
-static void bus_reset_tasklet(unsigned long data)
|
|
|
|
|
|
+static int get_status_for_port(struct fw_ohci *ohci, int port_index)
|
|
|
|
+{
|
|
|
|
+ int reg;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&ohci->phy_reg_mutex);
|
|
|
|
+ reg = write_phy_reg(ohci, 7, port_index);
|
|
|
|
+ if (reg >= 0)
|
|
|
|
+ reg = read_phy_reg(ohci, 8);
|
|
|
|
+ mutex_unlock(&ohci->phy_reg_mutex);
|
|
|
|
+ if (reg < 0)
|
|
|
|
+ return reg;
|
|
|
|
+
|
|
|
|
+ switch (reg & 0x0f) {
|
|
|
|
+ case 0x06:
|
|
|
|
+ return 2; /* is child node (connected to parent node) */
|
|
|
|
+ case 0x0e:
|
|
|
|
+ return 3; /* is parent node (connected to child node) */
|
|
|
|
+ }
|
|
|
|
+ return 1; /* not connected */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int get_self_id_pos(struct fw_ohci *ohci, u32 self_id,
|
|
|
|
+ int self_id_count)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+ u32 entry;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < self_id_count; i++) {
|
|
|
|
+ entry = ohci->self_id_buffer[i];
|
|
|
|
+ if ((self_id & 0xff000000) == (entry & 0xff000000))
|
|
|
|
+ return -1;
|
|
|
|
+ if ((self_id & 0xff000000) < (entry & 0xff000000))
|
|
|
|
+ return i;
|
|
|
|
+ }
|
|
|
|
+ return i;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * TI TSB82AA2B and TSB12LV26 do not receive the selfID of a locally
|
|
|
|
+ * attached TSB41BA3D phy; see http://www.ti.com/litv/pdf/sllz059.
|
|
|
|
+ * Construct the selfID from phy register contents.
|
|
|
|
+ * FIXME: How to determine the selfID.i flag?
|
|
|
|
+ */
|
|
|
|
+static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count)
|
|
|
|
+{
|
|
|
|
+ int reg, i, pos, status;
|
|
|
|
+ /* link active 1, speed 3, bridge 0, contender 1, more packets 0 */
|
|
|
|
+ u32 self_id = 0x8040c800;
|
|
|
|
+
|
|
|
|
+ reg = reg_read(ohci, OHCI1394_NodeID);
|
|
|
|
+ if (!(reg & OHCI1394_NodeID_idValid)) {
|
|
|
|
+ fw_notify("node ID not valid, new bus reset in progress\n");
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ }
|
|
|
|
+ self_id |= ((reg & 0x3f) << 24); /* phy ID */
|
|
|
|
+
|
|
|
|
+ reg = ohci_read_phy_reg(&ohci->card, 4);
|
|
|
|
+ if (reg < 0)
|
|
|
|
+ return reg;
|
|
|
|
+ self_id |= ((reg & 0x07) << 8); /* power class */
|
|
|
|
+
|
|
|
|
+ reg = ohci_read_phy_reg(&ohci->card, 1);
|
|
|
|
+ if (reg < 0)
|
|
|
|
+ return reg;
|
|
|
|
+ self_id |= ((reg & 0x3f) << 16); /* gap count */
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < 3; i++) {
|
|
|
|
+ status = get_status_for_port(ohci, i);
|
|
|
|
+ if (status < 0)
|
|
|
|
+ return status;
|
|
|
|
+ self_id |= ((status & 0x3) << (6 - (i * 2)));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos = get_self_id_pos(ohci, self_id, self_id_count);
|
|
|
|
+ if (pos >= 0) {
|
|
|
|
+ memmove(&(ohci->self_id_buffer[pos+1]),
|
|
|
|
+ &(ohci->self_id_buffer[pos]),
|
|
|
|
+ (self_id_count - pos) * sizeof(*ohci->self_id_buffer));
|
|
|
|
+ ohci->self_id_buffer[pos] = self_id;
|
|
|
|
+ self_id_count++;
|
|
|
|
+ }
|
|
|
|
+ return self_id_count;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void bus_reset_work(struct work_struct *work)
|
|
{
|
|
{
|
|
- struct fw_ohci *ohci = (struct fw_ohci *)data;
|
|
|
|
|
|
+ struct fw_ohci *ohci =
|
|
|
|
+ container_of(work, struct fw_ohci, bus_reset_work);
|
|
int self_id_count, i, j, reg;
|
|
int self_id_count, i, j, reg;
|
|
int generation, new_generation;
|
|
int generation, new_generation;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -1753,21 +1851,50 @@ static void bus_reset_tasklet(unsigned long data)
|
|
* bit extra to get the actual number of self IDs.
|
|
* bit extra to get the actual number of self IDs.
|
|
*/
|
|
*/
|
|
self_id_count = (reg >> 3) & 0xff;
|
|
self_id_count = (reg >> 3) & 0xff;
|
|
- if (self_id_count == 0 || self_id_count > 252) {
|
|
|
|
|
|
+
|
|
|
|
+ if (self_id_count > 252) {
|
|
fw_notify("inconsistent self IDs\n");
|
|
fw_notify("inconsistent self IDs\n");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+
|
|
generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
|
|
generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
|
|
rmb();
|
|
rmb();
|
|
|
|
|
|
for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
|
|
for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
|
|
if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) {
|
|
if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) {
|
|
- fw_notify("inconsistent self IDs\n");
|
|
|
|
- return;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If the invalid data looks like a cycle start packet,
|
|
|
|
+ * it's likely to be the result of the cycle master
|
|
|
|
+ * having a wrong gap count. In this case, the self IDs
|
|
|
|
+ * so far are valid and should be processed so that the
|
|
|
|
+ * bus manager can then correct the gap count.
|
|
|
|
+ */
|
|
|
|
+ if (cond_le32_to_cpu(ohci->self_id_cpu[i])
|
|
|
|
+ == 0xffff008f) {
|
|
|
|
+ fw_notify("ignoring spurious self IDs\n");
|
|
|
|
+ self_id_count = j;
|
|
|
|
+ break;
|
|
|
|
+ } else {
|
|
|
|
+ fw_notify("inconsistent self IDs\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
ohci->self_id_buffer[j] =
|
|
ohci->self_id_buffer[j] =
|
|
cond_le32_to_cpu(ohci->self_id_cpu[i]);
|
|
cond_le32_to_cpu(ohci->self_id_cpu[i]);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (ohci->quirks & QUIRK_TI_SLLZ059) {
|
|
|
|
+ self_id_count = find_and_insert_self_id(ohci, self_id_count);
|
|
|
|
+ if (self_id_count < 0) {
|
|
|
|
+ fw_notify("could not construct local self ID\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (self_id_count == 0) {
|
|
|
|
+ fw_notify("inconsistent self IDs\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
rmb();
|
|
rmb();
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1887,7 +2014,7 @@ static irqreturn_t irq_handler(int irq, void *data)
|
|
log_irqs(event);
|
|
log_irqs(event);
|
|
|
|
|
|
if (event & OHCI1394_selfIDComplete)
|
|
if (event & OHCI1394_selfIDComplete)
|
|
- tasklet_schedule(&ohci->bus_reset_tasklet);
|
|
|
|
|
|
+ queue_work(fw_workqueue, &ohci->bus_reset_work);
|
|
|
|
|
|
if (event & OHCI1394_RQPkt)
|
|
if (event & OHCI1394_RQPkt)
|
|
tasklet_schedule(&ohci->ar_request_ctx.tasklet);
|
|
tasklet_schedule(&ohci->ar_request_ctx.tasklet);
|
|
@@ -1934,7 +2061,8 @@ static irqreturn_t irq_handler(int irq, void *data)
|
|
reg_read(ohci, OHCI1394_PostedWriteAddressLo);
|
|
reg_read(ohci, OHCI1394_PostedWriteAddressLo);
|
|
reg_write(ohci, OHCI1394_IntEventClear,
|
|
reg_write(ohci, OHCI1394_IntEventClear,
|
|
OHCI1394_postedWriteErr);
|
|
OHCI1394_postedWriteErr);
|
|
- fw_error("PCI posted write error\n");
|
|
|
|
|
|
+ if (printk_ratelimit())
|
|
|
|
+ fw_error("PCI posted write error\n");
|
|
}
|
|
}
|
|
|
|
|
|
if (unlikely(event & OHCI1394_cycleTooLong)) {
|
|
if (unlikely(event & OHCI1394_cycleTooLong)) {
|
|
@@ -2048,6 +2176,28 @@ static int configure_1394a_enhancements(struct fw_ohci *ohci)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int probe_tsb41ba3d(struct fw_ohci *ohci)
|
|
|
|
+{
|
|
|
|
+ /* TI vendor ID = 0x080028, TSB41BA3D product ID = 0x833005 (sic) */
|
|
|
|
+ static const u8 id[] = { 0x08, 0x00, 0x28, 0x83, 0x30, 0x05, };
|
|
|
|
+ int reg, i;
|
|
|
|
+
|
|
|
|
+ reg = read_phy_reg(ohci, 2);
|
|
|
|
+ if (reg < 0)
|
|
|
|
+ return reg;
|
|
|
|
+ if ((reg & PHY_EXTENDED_REGISTERS) != PHY_EXTENDED_REGISTERS)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ for (i = ARRAY_SIZE(id) - 1; i >= 0; i--) {
|
|
|
|
+ reg = read_paged_phy_reg(ohci, 1, i + 10);
|
|
|
|
+ if (reg < 0)
|
|
|
|
+ return reg;
|
|
|
|
+ if (reg != id[i])
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
static int ohci_enable(struct fw_card *card,
|
|
static int ohci_enable(struct fw_card *card,
|
|
const __be32 *config_rom, size_t length)
|
|
const __be32 *config_rom, size_t length)
|
|
{
|
|
{
|
|
@@ -2085,6 +2235,16 @@ static int ohci_enable(struct fw_card *card,
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (ohci->quirks & QUIRK_TI_SLLZ059) {
|
|
|
|
+ ret = probe_tsb41ba3d(ohci);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+ if (ret)
|
|
|
|
+ fw_notify("local TSB41BA3D phy\n");
|
|
|
|
+ else
|
|
|
|
+ ohci->quirks &= ~QUIRK_TI_SLLZ059;
|
|
|
|
+ }
|
|
|
|
+
|
|
reg_write(ohci, OHCI1394_HCControlClear,
|
|
reg_write(ohci, OHCI1394_HCControlClear,
|
|
OHCI1394_HCControl_noByteSwapData);
|
|
OHCI1394_HCControl_noByteSwapData);
|
|
|
|
|
|
@@ -2260,7 +2420,7 @@ static int ohci_set_config_rom(struct fw_card *card,
|
|
* then set up the real values for the two registers.
|
|
* then set up the real values for the two registers.
|
|
*
|
|
*
|
|
* We use ohci->lock to avoid racing with the code that sets
|
|
* We use ohci->lock to avoid racing with the code that sets
|
|
- * ohci->next_config_rom to NULL (see bus_reset_tasklet).
|
|
|
|
|
|
+ * ohci->next_config_rom to NULL (see bus_reset_work).
|
|
*/
|
|
*/
|
|
|
|
|
|
next_config_rom =
|
|
next_config_rom =
|
|
@@ -2539,6 +2699,7 @@ static int handle_ir_packet_per_buffer(struct context *context,
|
|
struct iso_context *ctx =
|
|
struct iso_context *ctx =
|
|
container_of(context, struct iso_context, context);
|
|
container_of(context, struct iso_context, context);
|
|
struct descriptor *pd;
|
|
struct descriptor *pd;
|
|
|
|
+ u32 buffer_dma;
|
|
__le32 *ir_header;
|
|
__le32 *ir_header;
|
|
void *p;
|
|
void *p;
|
|
|
|
|
|
@@ -2549,6 +2710,16 @@ static int handle_ir_packet_per_buffer(struct context *context,
|
|
/* Descriptor(s) not done yet, stop iteration */
|
|
/* Descriptor(s) not done yet, stop iteration */
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ while (!(d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))) {
|
|
|
|
+ d++;
|
|
|
|
+ buffer_dma = le32_to_cpu(d->data_address);
|
|
|
|
+ dma_sync_single_range_for_cpu(context->ohci->card.device,
|
|
|
|
+ buffer_dma & PAGE_MASK,
|
|
|
|
+ buffer_dma & ~PAGE_MASK,
|
|
|
|
+ le16_to_cpu(d->req_count),
|
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
|
+ }
|
|
|
|
+
|
|
p = last + 1;
|
|
p = last + 1;
|
|
copy_iso_headers(ctx, p);
|
|
copy_iso_headers(ctx, p);
|
|
|
|
|
|
@@ -2571,11 +2742,19 @@ static int handle_ir_buffer_fill(struct context *context,
|
|
{
|
|
{
|
|
struct iso_context *ctx =
|
|
struct iso_context *ctx =
|
|
container_of(context, struct iso_context, context);
|
|
container_of(context, struct iso_context, context);
|
|
|
|
+ u32 buffer_dma;
|
|
|
|
|
|
if (!last->transfer_status)
|
|
if (!last->transfer_status)
|
|
/* Descriptor(s) not done yet, stop iteration */
|
|
/* Descriptor(s) not done yet, stop iteration */
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ buffer_dma = le32_to_cpu(last->data_address);
|
|
|
|
+ dma_sync_single_range_for_cpu(context->ohci->card.device,
|
|
|
|
+ buffer_dma & PAGE_MASK,
|
|
|
|
+ buffer_dma & ~PAGE_MASK,
|
|
|
|
+ le16_to_cpu(last->req_count),
|
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
|
+
|
|
if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
|
|
if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
|
|
ctx->base.callback.mc(&ctx->base,
|
|
ctx->base.callback.mc(&ctx->base,
|
|
le32_to_cpu(last->data_address) +
|
|
le32_to_cpu(last->data_address) +
|
|
@@ -2586,6 +2765,43 @@ static int handle_ir_buffer_fill(struct context *context,
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline void sync_it_packet_for_cpu(struct context *context,
|
|
|
|
+ struct descriptor *pd)
|
|
|
|
+{
|
|
|
|
+ __le16 control;
|
|
|
|
+ u32 buffer_dma;
|
|
|
|
+
|
|
|
|
+ /* only packets beginning with OUTPUT_MORE* have data buffers */
|
|
|
|
+ if (pd->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /* skip over the OUTPUT_MORE_IMMEDIATE descriptor */
|
|
|
|
+ pd += 2;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the packet has a header, the first OUTPUT_MORE/LAST descriptor's
|
|
|
|
+ * data buffer is in the context program's coherent page and must not
|
|
|
|
+ * be synced.
|
|
|
|
+ */
|
|
|
|
+ if ((le32_to_cpu(pd->data_address) & PAGE_MASK) ==
|
|
|
|
+ (context->current_bus & PAGE_MASK)) {
|
|
|
|
+ if (pd->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))
|
|
|
|
+ return;
|
|
|
|
+ pd++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ do {
|
|
|
|
+ buffer_dma = le32_to_cpu(pd->data_address);
|
|
|
|
+ dma_sync_single_range_for_cpu(context->ohci->card.device,
|
|
|
|
+ buffer_dma & PAGE_MASK,
|
|
|
|
+ buffer_dma & ~PAGE_MASK,
|
|
|
|
+ le16_to_cpu(pd->req_count),
|
|
|
|
+ DMA_TO_DEVICE);
|
|
|
|
+ control = pd->control;
|
|
|
|
+ pd++;
|
|
|
|
+ } while (!(control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)));
|
|
|
|
+}
|
|
|
|
+
|
|
static int handle_it_packet(struct context *context,
|
|
static int handle_it_packet(struct context *context,
|
|
struct descriptor *d,
|
|
struct descriptor *d,
|
|
struct descriptor *last)
|
|
struct descriptor *last)
|
|
@@ -2602,6 +2818,8 @@ static int handle_it_packet(struct context *context,
|
|
/* Descriptor(s) not done yet, stop iteration */
|
|
/* Descriptor(s) not done yet, stop iteration */
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ sync_it_packet_for_cpu(context, d);
|
|
|
|
+
|
|
i = ctx->header_length;
|
|
i = ctx->header_length;
|
|
if (i + 4 < PAGE_SIZE) {
|
|
if (i + 4 < PAGE_SIZE) {
|
|
/* Present this value as big-endian to match the receive code */
|
|
/* Present this value as big-endian to match the receive code */
|
|
@@ -2971,6 +3189,10 @@ static int queue_iso_transmit(struct iso_context *ctx,
|
|
page_bus = page_private(buffer->pages[page]);
|
|
page_bus = page_private(buffer->pages[page]);
|
|
pd[i].data_address = cpu_to_le32(page_bus + offset);
|
|
pd[i].data_address = cpu_to_le32(page_bus + offset);
|
|
|
|
|
|
|
|
+ dma_sync_single_range_for_device(ctx->context.ohci->card.device,
|
|
|
|
+ page_bus, offset, length,
|
|
|
|
+ DMA_TO_DEVICE);
|
|
|
|
+
|
|
payload_index += length;
|
|
payload_index += length;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2995,6 +3217,7 @@ static int queue_iso_packet_per_buffer(struct iso_context *ctx,
|
|
struct fw_iso_buffer *buffer,
|
|
struct fw_iso_buffer *buffer,
|
|
unsigned long payload)
|
|
unsigned long payload)
|
|
{
|
|
{
|
|
|
|
+ struct device *device = ctx->context.ohci->card.device;
|
|
struct descriptor *d, *pd;
|
|
struct descriptor *d, *pd;
|
|
dma_addr_t d_bus, page_bus;
|
|
dma_addr_t d_bus, page_bus;
|
|
u32 z, header_z, rest;
|
|
u32 z, header_z, rest;
|
|
@@ -3049,6 +3272,10 @@ static int queue_iso_packet_per_buffer(struct iso_context *ctx,
|
|
page_bus = page_private(buffer->pages[page]);
|
|
page_bus = page_private(buffer->pages[page]);
|
|
pd->data_address = cpu_to_le32(page_bus + offset);
|
|
pd->data_address = cpu_to_le32(page_bus + offset);
|
|
|
|
|
|
|
|
+ dma_sync_single_range_for_device(device, page_bus,
|
|
|
|
+ offset, length,
|
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
|
+
|
|
offset = (offset + length) & ~PAGE_MASK;
|
|
offset = (offset + length) & ~PAGE_MASK;
|
|
rest -= length;
|
|
rest -= length;
|
|
if (offset == 0)
|
|
if (offset == 0)
|
|
@@ -3108,6 +3335,10 @@ static int queue_iso_buffer_fill(struct iso_context *ctx,
|
|
page_bus = page_private(buffer->pages[page]);
|
|
page_bus = page_private(buffer->pages[page]);
|
|
d->data_address = cpu_to_le32(page_bus + offset);
|
|
d->data_address = cpu_to_le32(page_bus + offset);
|
|
|
|
|
|
|
|
+ dma_sync_single_range_for_device(ctx->context.ohci->card.device,
|
|
|
|
+ page_bus, offset, length,
|
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
|
+
|
|
rest -= length;
|
|
rest -= length;
|
|
offset = 0;
|
|
offset = 0;
|
|
page++;
|
|
page++;
|
|
@@ -3239,8 +3470,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
|
|
spin_lock_init(&ohci->lock);
|
|
spin_lock_init(&ohci->lock);
|
|
mutex_init(&ohci->phy_reg_mutex);
|
|
mutex_init(&ohci->phy_reg_mutex);
|
|
|
|
|
|
- tasklet_init(&ohci->bus_reset_tasklet,
|
|
|
|
- bus_reset_tasklet, (unsigned long)ohci);
|
|
|
|
|
|
+ INIT_WORK(&ohci->bus_reset_work, bus_reset_work);
|
|
|
|
|
|
err = pci_request_region(dev, 0, ohci_driver_name);
|
|
err = pci_request_region(dev, 0, ohci_driver_name);
|
|
if (err) {
|
|
if (err) {
|
|
@@ -3382,6 +3612,7 @@ static void pci_remove(struct pci_dev *dev)
|
|
ohci = pci_get_drvdata(dev);
|
|
ohci = pci_get_drvdata(dev);
|
|
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
|
|
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
|
|
flush_writes(ohci);
|
|
flush_writes(ohci);
|
|
|
|
+ cancel_work_sync(&ohci->bus_reset_work);
|
|
fw_core_remove_card(&ohci->card);
|
|
fw_core_remove_card(&ohci->card);
|
|
|
|
|
|
/*
|
|
/*
|