diff options
Diffstat (limited to 'drivers/firewire/ohci.c')
-rw-r--r-- | drivers/firewire/ohci.c | 107 |
1 files changed, 81 insertions, 26 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 9dcb17d51aee..a03cb6acaeda 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -242,6 +242,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) | |||
242 | 242 | ||
243 | static char ohci_driver_name[] = KBUILD_MODNAME; | 243 | static char ohci_driver_name[] = KBUILD_MODNAME; |
244 | 244 | ||
245 | #define PCI_DEVICE_ID_AGERE_FW643 0x5901 | ||
245 | #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 | 246 | #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 |
246 | #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 | 247 | #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 |
247 | 248 | ||
@@ -253,18 +254,34 @@ static char ohci_driver_name[] = KBUILD_MODNAME; | |||
253 | 254 | ||
254 | /* In case of multiple matches in ohci_quirks[], only the first one is used. */ | 255 | /* In case of multiple matches in ohci_quirks[], only the first one is used. */ |
255 | static const struct { | 256 | static const struct { |
256 | unsigned short vendor, device, flags; | 257 | unsigned short vendor, device, revision, flags; |
257 | } ohci_quirks[] = { | 258 | } ohci_quirks[] = { |
258 | {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER | | 259 | {PCI_VENDOR_ID_AL, PCI_ANY_ID, PCI_ANY_ID, |
259 | QUIRK_RESET_PACKET | | 260 | QUIRK_CYCLE_TIMER}, |
260 | QUIRK_NO_1394A}, | 261 | |
261 | {PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET}, | 262 | {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, PCI_ANY_ID, |
262 | {PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, | 263 | QUIRK_BE_HEADERS}, |
263 | {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI}, | 264 | |
264 | {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, | 265 | {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, |
265 | {PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, | 266 | QUIRK_NO_MSI}, |
266 | {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, | 267 | |
267 | {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS}, | 268 | {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID, |
269 | QUIRK_NO_MSI}, | ||
270 | |||
271 | {PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID, | ||
272 | QUIRK_CYCLE_TIMER}, | ||
273 | |||
274 | {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID, | ||
275 | QUIRK_CYCLE_TIMER}, | ||
276 | |||
277 | {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, | ||
278 | QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, | ||
279 | |||
280 | {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID, | ||
281 | QUIRK_RESET_PACKET}, | ||
282 | |||
283 | {PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID, | ||
284 | QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, | ||
268 | }; | 285 | }; |
269 | 286 | ||
270 | /* This overrides anything that was found in ohci_quirks[]. */ | 287 | /* This overrides anything that was found in ohci_quirks[]. */ |
@@ -739,7 +756,7 @@ static void ar_context_tasklet(unsigned long data) | |||
739 | d = &ab->descriptor; | 756 | d = &ab->descriptor; |
740 | 757 | ||
741 | if (d->res_count == 0) { | 758 | if (d->res_count == 0) { |
742 | size_t size, rest, offset; | 759 | size_t size, size2, rest, pktsize, size3, offset; |
743 | dma_addr_t start_bus; | 760 | dma_addr_t start_bus; |
744 | void *start; | 761 | void *start; |
745 | 762 | ||
@@ -750,25 +767,61 @@ static void ar_context_tasklet(unsigned long data) | |||
750 | */ | 767 | */ |
751 | 768 | ||
752 | offset = offsetof(struct ar_buffer, data); | 769 | offset = offsetof(struct ar_buffer, data); |
753 | start = buffer = ab; | 770 | start = ab; |
754 | start_bus = le32_to_cpu(ab->descriptor.data_address) - offset; | 771 | start_bus = le32_to_cpu(ab->descriptor.data_address) - offset; |
772 | buffer = ab->data; | ||
755 | 773 | ||
756 | ab = ab->next; | 774 | ab = ab->next; |
757 | d = &ab->descriptor; | 775 | d = &ab->descriptor; |
758 | size = buffer + PAGE_SIZE - ctx->pointer; | 776 | size = start + PAGE_SIZE - ctx->pointer; |
777 | /* valid buffer data in the next page */ | ||
759 | rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); | 778 | rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); |
779 | /* what actually fits in this page */ | ||
780 | size2 = min(rest, (size_t)PAGE_SIZE - offset - size); | ||
760 | memmove(buffer, ctx->pointer, size); | 781 | memmove(buffer, ctx->pointer, size); |
761 | memcpy(buffer + size, ab->data, rest); | 782 | memcpy(buffer + size, ab->data, size2); |
762 | ctx->current_buffer = ab; | 783 | |
763 | ctx->pointer = (void *) ab->data + rest; | 784 | while (size > 0) { |
764 | end = buffer + size + rest; | 785 | void *next = handle_ar_packet(ctx, buffer); |
786 | pktsize = next - buffer; | ||
787 | if (pktsize >= size) { | ||
788 | /* | ||
789 | * We have handled all the data that was | ||
790 | * originally in this page, so we can now | ||
791 | * continue in the next page. | ||
792 | */ | ||
793 | buffer = next; | ||
794 | break; | ||
795 | } | ||
796 | /* move the next packet to the start of the buffer */ | ||
797 | memmove(buffer, next, size + size2 - pktsize); | ||
798 | size -= pktsize; | ||
799 | /* fill up this page again */ | ||
800 | size3 = min(rest - size2, | ||
801 | (size_t)PAGE_SIZE - offset - size - size2); | ||
802 | memcpy(buffer + size + size2, | ||
803 | (void *) ab->data + size2, size3); | ||
804 | size2 += size3; | ||
805 | } | ||
765 | 806 | ||
766 | while (buffer < end) | 807 | if (rest > 0) { |
767 | buffer = handle_ar_packet(ctx, buffer); | 808 | /* handle the packets that are fully in the next page */ |
809 | buffer = (void *) ab->data + | ||
810 | (buffer - (start + offset + size)); | ||
811 | end = (void *) ab->data + rest; | ||
812 | |||
813 | while (buffer < end) | ||
814 | buffer = handle_ar_packet(ctx, buffer); | ||
768 | 815 | ||
769 | dma_free_coherent(ohci->card.device, PAGE_SIZE, | 816 | ctx->current_buffer = ab; |
770 | start, start_bus); | 817 | ctx->pointer = end; |
771 | ar_context_add_page(ctx); | 818 | |
819 | dma_free_coherent(ohci->card.device, PAGE_SIZE, | ||
820 | start, start_bus); | ||
821 | ar_context_add_page(ctx); | ||
822 | } else { | ||
823 | ctx->pointer = start + PAGE_SIZE; | ||
824 | } | ||
772 | } else { | 825 | } else { |
773 | buffer = ctx->pointer; | 826 | buffer = ctx->pointer; |
774 | ctx->pointer = end = | 827 | ctx->pointer = end = |
@@ -2885,9 +2938,11 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
2885 | } | 2938 | } |
2886 | 2939 | ||
2887 | for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++) | 2940 | for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++) |
2888 | if (ohci_quirks[i].vendor == dev->vendor && | 2941 | if ((ohci_quirks[i].vendor == dev->vendor) && |
2889 | (ohci_quirks[i].device == dev->device || | 2942 | (ohci_quirks[i].device == (unsigned short)PCI_ANY_ID || |
2890 | ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) { | 2943 | ohci_quirks[i].device == dev->device) && |
2944 | (ohci_quirks[i].revision == (unsigned short)PCI_ANY_ID || | ||
2945 | ohci_quirks[i].revision >= dev->revision)) { | ||
2891 | ohci->quirks = ohci_quirks[i].flags; | 2946 | ohci->quirks = ohci_quirks[i].flags; |
2892 | break; | 2947 | break; |
2893 | } | 2948 | } |