diff options
Diffstat (limited to 'drivers/firewire/ohci.c')
-rw-r--r-- | drivers/firewire/ohci.c | 135 |
1 files changed, 98 insertions, 37 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 9dcb17d51aee..e3c8b60bd86b 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[]. */ |
@@ -577,17 +594,11 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr, | |||
577 | return ret; | 594 | return ret; |
578 | } | 595 | } |
579 | 596 | ||
580 | static int ar_context_add_page(struct ar_context *ctx) | 597 | static void ar_context_link_page(struct ar_context *ctx, |
598 | struct ar_buffer *ab, dma_addr_t ab_bus) | ||
581 | { | 599 | { |
582 | struct device *dev = ctx->ohci->card.device; | ||
583 | struct ar_buffer *ab; | ||
584 | dma_addr_t uninitialized_var(ab_bus); | ||
585 | size_t offset; | 600 | size_t offset; |
586 | 601 | ||
587 | ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC); | ||
588 | if (ab == NULL) | ||
589 | return -ENOMEM; | ||
590 | |||
591 | ab->next = NULL; | 602 | ab->next = NULL; |
592 | memset(&ab->descriptor, 0, sizeof(ab->descriptor)); | 603 | memset(&ab->descriptor, 0, sizeof(ab->descriptor)); |
593 | ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | | 604 | ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | |
@@ -606,6 +617,19 @@ static int ar_context_add_page(struct ar_context *ctx) | |||
606 | 617 | ||
607 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); | 618 | reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); |
608 | flush_writes(ctx->ohci); | 619 | flush_writes(ctx->ohci); |
620 | } | ||
621 | |||
622 | static int ar_context_add_page(struct ar_context *ctx) | ||
623 | { | ||
624 | struct device *dev = ctx->ohci->card.device; | ||
625 | struct ar_buffer *ab; | ||
626 | dma_addr_t uninitialized_var(ab_bus); | ||
627 | |||
628 | ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC); | ||
629 | if (ab == NULL) | ||
630 | return -ENOMEM; | ||
631 | |||
632 | ar_context_link_page(ctx, ab, ab_bus); | ||
609 | 633 | ||
610 | return 0; | 634 | return 0; |
611 | } | 635 | } |
@@ -730,16 +754,17 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) | |||
730 | static void ar_context_tasklet(unsigned long data) | 754 | static void ar_context_tasklet(unsigned long data) |
731 | { | 755 | { |
732 | struct ar_context *ctx = (struct ar_context *)data; | 756 | struct ar_context *ctx = (struct ar_context *)data; |
733 | struct fw_ohci *ohci = ctx->ohci; | ||
734 | struct ar_buffer *ab; | 757 | struct ar_buffer *ab; |
735 | struct descriptor *d; | 758 | struct descriptor *d; |
736 | void *buffer, *end; | 759 | void *buffer, *end; |
760 | __le16 res_count; | ||
737 | 761 | ||
738 | ab = ctx->current_buffer; | 762 | ab = ctx->current_buffer; |
739 | d = &ab->descriptor; | 763 | d = &ab->descriptor; |
740 | 764 | ||
741 | if (d->res_count == 0) { | 765 | res_count = ACCESS_ONCE(d->res_count); |
742 | size_t size, rest, offset; | 766 | if (res_count == 0) { |
767 | size_t size, size2, rest, pktsize, size3, offset; | ||
743 | dma_addr_t start_bus; | 768 | dma_addr_t start_bus; |
744 | void *start; | 769 | void *start; |
745 | 770 | ||
@@ -750,29 +775,63 @@ static void ar_context_tasklet(unsigned long data) | |||
750 | */ | 775 | */ |
751 | 776 | ||
752 | offset = offsetof(struct ar_buffer, data); | 777 | offset = offsetof(struct ar_buffer, data); |
753 | start = buffer = ab; | 778 | start = ab; |
754 | start_bus = le32_to_cpu(ab->descriptor.data_address) - offset; | 779 | start_bus = le32_to_cpu(ab->descriptor.data_address) - offset; |
780 | buffer = ab->data; | ||
755 | 781 | ||
756 | ab = ab->next; | 782 | ab = ab->next; |
757 | d = &ab->descriptor; | 783 | d = &ab->descriptor; |
758 | size = buffer + PAGE_SIZE - ctx->pointer; | 784 | size = start + PAGE_SIZE - ctx->pointer; |
785 | /* valid buffer data in the next page */ | ||
759 | rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); | 786 | rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); |
787 | /* what actually fits in this page */ | ||
788 | size2 = min(rest, (size_t)PAGE_SIZE - offset - size); | ||
760 | memmove(buffer, ctx->pointer, size); | 789 | memmove(buffer, ctx->pointer, size); |
761 | memcpy(buffer + size, ab->data, rest); | 790 | memcpy(buffer + size, ab->data, size2); |
762 | ctx->current_buffer = ab; | 791 | |
763 | ctx->pointer = (void *) ab->data + rest; | 792 | while (size > 0) { |
764 | end = buffer + size + rest; | 793 | void *next = handle_ar_packet(ctx, buffer); |
794 | pktsize = next - buffer; | ||
795 | if (pktsize >= size) { | ||
796 | /* | ||
797 | * We have handled all the data that was | ||
798 | * originally in this page, so we can now | ||
799 | * continue in the next page. | ||
800 | */ | ||
801 | buffer = next; | ||
802 | break; | ||
803 | } | ||
804 | /* move the next packet to the start of the buffer */ | ||
805 | memmove(buffer, next, size + size2 - pktsize); | ||
806 | size -= pktsize; | ||
807 | /* fill up this page again */ | ||
808 | size3 = min(rest - size2, | ||
809 | (size_t)PAGE_SIZE - offset - size - size2); | ||
810 | memcpy(buffer + size + size2, | ||
811 | (void *) ab->data + size2, size3); | ||
812 | size2 += size3; | ||
813 | } | ||
765 | 814 | ||
766 | while (buffer < end) | 815 | if (rest > 0) { |
767 | buffer = handle_ar_packet(ctx, buffer); | 816 | /* handle the packets that are fully in the next page */ |
817 | buffer = (void *) ab->data + | ||
818 | (buffer - (start + offset + size)); | ||
819 | end = (void *) ab->data + rest; | ||
768 | 820 | ||
769 | dma_free_coherent(ohci->card.device, PAGE_SIZE, | 821 | while (buffer < end) |
770 | start, start_bus); | 822 | buffer = handle_ar_packet(ctx, buffer); |
771 | ar_context_add_page(ctx); | 823 | |
824 | ctx->current_buffer = ab; | ||
825 | ctx->pointer = end; | ||
826 | |||
827 | ar_context_link_page(ctx, start, start_bus); | ||
828 | } else { | ||
829 | ctx->pointer = start + PAGE_SIZE; | ||
830 | } | ||
772 | } else { | 831 | } else { |
773 | buffer = ctx->pointer; | 832 | buffer = ctx->pointer; |
774 | ctx->pointer = end = | 833 | ctx->pointer = end = |
775 | (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count); | 834 | (void *) ab + PAGE_SIZE - le16_to_cpu(res_count); |
776 | 835 | ||
777 | while (buffer < end) | 836 | while (buffer < end) |
778 | buffer = handle_ar_packet(ctx, buffer); | 837 | buffer = handle_ar_packet(ctx, buffer); |
@@ -2885,9 +2944,11 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
2885 | } | 2944 | } |
2886 | 2945 | ||
2887 | for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++) | 2946 | for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++) |
2888 | if (ohci_quirks[i].vendor == dev->vendor && | 2947 | if ((ohci_quirks[i].vendor == dev->vendor) && |
2889 | (ohci_quirks[i].device == dev->device || | 2948 | (ohci_quirks[i].device == (unsigned short)PCI_ANY_ID || |
2890 | ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) { | 2949 | ohci_quirks[i].device == dev->device) && |
2950 | (ohci_quirks[i].revision == (unsigned short)PCI_ANY_ID || | ||
2951 | ohci_quirks[i].revision >= dev->revision)) { | ||
2891 | ohci->quirks = ohci_quirks[i].flags; | 2952 | ohci->quirks = ohci_quirks[i].flags; |
2892 | break; | 2953 | break; |
2893 | } | 2954 | } |