Commit 95984f62 authored by Stefan Richter's avatar Stefan Richter

firewire: fw-ohci: TSB43AB22/A dualbuffer workaround

Isochronous reception in dualbuffer mode is reportedly broken with
TI TSB43AB22A on x86-64.  Descriptor addresses above 2G have been
determined as the trigger:
https://bugzilla.redhat.com/show_bug.cgi?id=435550

Two fixes are possible:
  - pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK);
    at least when IR descriptors are allocated, or
  - simply don't use dualbuffer.
This fix implements the latter workaround.

But we keep using dualbuffer on x86-32 which won't give us highmen (and
thus physical addresses outside the 31bit range) in coherent DMA memory
allocations.  Right now we could for example also whitelist PPC32, but
DMA mapping implementation details are expected to change there.
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: default avatarJarod Wilson <jwilson@redhat.com>
parent f9543d0a
...@@ -171,7 +171,6 @@ struct iso_context { ...@@ -171,7 +171,6 @@ struct iso_context {
struct fw_ohci { struct fw_ohci {
struct fw_card card; struct fw_card card;
u32 version;
__iomem char *registers; __iomem char *registers;
dma_addr_t self_id_bus; dma_addr_t self_id_bus;
__le32 *self_id_cpu; __le32 *self_id_cpu;
...@@ -180,6 +179,8 @@ struct fw_ohci { ...@@ -180,6 +179,8 @@ struct fw_ohci {
int generation; int generation;
int request_generation; /* for timestamping incoming requests */ int request_generation; /* for timestamping incoming requests */
u32 bus_seconds; u32 bus_seconds;
bool use_dualbuffer;
bool old_uninorth; bool old_uninorth;
bool bus_reset_packet_quirk; bool bus_reset_packet_quirk;
...@@ -1885,7 +1886,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size) ...@@ -1885,7 +1886,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
} else { } else {
mask = &ohci->ir_context_mask; mask = &ohci->ir_context_mask;
list = ohci->ir_context_list; list = ohci->ir_context_list;
if (ohci->version >= OHCI_VERSION_1_1) if (ohci->use_dualbuffer)
callback = handle_ir_dualbuffer_packet; callback = handle_ir_dualbuffer_packet;
else else
callback = handle_ir_packet_per_buffer; callback = handle_ir_packet_per_buffer;
...@@ -1949,7 +1950,7 @@ static int ohci_start_iso(struct fw_iso_context *base, ...@@ -1949,7 +1950,7 @@ static int ohci_start_iso(struct fw_iso_context *base,
} else { } else {
index = ctx - ohci->ir_context_list; index = ctx - ohci->ir_context_list;
control = IR_CONTEXT_ISOCH_HEADER; control = IR_CONTEXT_ISOCH_HEADER;
if (ohci->version >= OHCI_VERSION_1_1) if (ohci->use_dualbuffer)
control |= IR_CONTEXT_DUAL_BUFFER_MODE; control |= IR_CONTEXT_DUAL_BUFFER_MODE;
match = (tags << 28) | (sync << 8) | ctx->base.channel; match = (tags << 28) | (sync << 8) | ctx->base.channel;
if (cycle >= 0) { if (cycle >= 0) {
...@@ -2279,7 +2280,7 @@ ohci_queue_iso(struct fw_iso_context *base, ...@@ -2279,7 +2280,7 @@ ohci_queue_iso(struct fw_iso_context *base,
spin_lock_irqsave(&ctx->context.ohci->lock, flags); spin_lock_irqsave(&ctx->context.ohci->lock, flags);
if (base->type == FW_ISO_CONTEXT_TRANSMIT) if (base->type == FW_ISO_CONTEXT_TRANSMIT)
retval = ohci_queue_iso_transmit(base, packet, buffer, payload); retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
else if (ctx->context.ohci->version >= OHCI_VERSION_1_1) else if (ctx->context.ohci->use_dualbuffer)
retval = ohci_queue_iso_receive_dualbuffer(base, packet, retval = ohci_queue_iso_receive_dualbuffer(base, packet,
buffer, payload); buffer, payload);
else else
...@@ -2341,7 +2342,7 @@ static int __devinit ...@@ -2341,7 +2342,7 @@ static int __devinit
pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{ {
struct fw_ohci *ohci; struct fw_ohci *ohci;
u32 bus_options, max_receive, link_speed; u32 bus_options, max_receive, link_speed, version;
u64 guid; u64 guid;
int err; int err;
size_t size; size_t size;
...@@ -2366,12 +2367,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ...@@ -2366,12 +2367,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
pci_set_drvdata(dev, ohci); pci_set_drvdata(dev, ohci);
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
#endif
ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
spin_lock_init(&ohci->lock); spin_lock_init(&ohci->lock);
tasklet_init(&ohci->bus_reset_tasklet, tasklet_init(&ohci->bus_reset_tasklet,
...@@ -2390,6 +2385,23 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ...@@ -2390,6 +2385,23 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
goto fail_iomem; goto fail_iomem;
} }
version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
ohci->use_dualbuffer = version >= OHCI_VERSION_1_1;
/* x86-32 currently doesn't use highmem for dma_alloc_coherent */
#if !defined(CONFIG_X86_32)
/* dual-buffer mode is broken with descriptor addresses above 2G */
if (dev->vendor == PCI_VENDOR_ID_TI &&
dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
ohci->use_dualbuffer = false;
#endif
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
#endif
ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
ar_context_init(&ohci->ar_request_ctx, ohci, ar_context_init(&ohci->ar_request_ctx, ohci,
OHCI1394_AsReqRcvContextControlSet); OHCI1394_AsReqRcvContextControlSet);
...@@ -2441,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ...@@ -2441,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
if (err < 0) if (err < 0)
goto fail_self_id; goto fail_self_id;
ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n", fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff); dev->dev.bus_id, version >> 16, version & 0xff);
return 0; return 0;
fail_self_id: fail_self_id:
......
...@@ -748,6 +748,7 @@ ...@@ -748,6 +748,7 @@
#define PCI_VENDOR_ID_TI 0x104c #define PCI_VENDOR_ID_TI 0x104c
#define PCI_DEVICE_ID_TI_TVP4020 0x3d07 #define PCI_DEVICE_ID_TI_TVP4020 0x3d07
#define PCI_DEVICE_ID_TI_4450 0x8011 #define PCI_DEVICE_ID_TI_4450 0x8011
#define PCI_DEVICE_ID_TI_TSB43AB22 0x8023
#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 #define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033 #define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033
#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034 #define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment