diff options
author | Maxim Levitsky <maximlevitsky@gmail.com> | 2010-11-28 21:09:50 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-12-13 14:39:15 -0500 |
commit | dd23736e092035b71df1117482b71fdfb5634239 (patch) | |
tree | 82e5ca95a4065f57e6c0e6504b3458d592a7c7f0 /drivers | |
parent | 8662b6b029636c35e5876e184d90daf6b0072667 (diff) |
firewire: ohci: restart iso DMA contexts on resume from low power mode
Restore iso channels DMA so that iso channels could continue to work
after resume from RAM/disk.
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/ohci.c | 54 |
1 files changed, 46 insertions, 8 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 3a908038ff62..5e5d5d3d43d1 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/bitops.h> | ||
21 | #include <linux/bug.h> | 22 | #include <linux/bug.h> |
22 | #include <linux/compiler.h> | 23 | #include <linux/compiler.h> |
23 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
@@ -153,6 +154,7 @@ struct context { | |||
153 | descriptor_callback_t callback; | 154 | descriptor_callback_t callback; |
154 | 155 | ||
155 | struct tasklet_struct tasklet; | 156 | struct tasklet_struct tasklet; |
157 | bool active; | ||
156 | }; | 158 | }; |
157 | 159 | ||
158 | #define IT_HEADER_SY(v) ((v) << 0) | 160 | #define IT_HEADER_SY(v) ((v) << 0) |
@@ -168,6 +170,9 @@ struct iso_context { | |||
168 | int excess_bytes; | 170 | int excess_bytes; |
169 | void *header; | 171 | void *header; |
170 | size_t header_length; | 172 | size_t header_length; |
173 | |||
174 | u8 sync; | ||
175 | u8 tags; | ||
171 | }; | 176 | }; |
172 | 177 | ||
173 | #define CONFIG_ROM_SIZE 1024 | 178 | #define CONFIG_ROM_SIZE 1024 |
@@ -184,7 +189,8 @@ struct fw_ohci { | |||
184 | u32 bus_time; | 189 | u32 bus_time; |
185 | bool is_root; | 190 | bool is_root; |
186 | bool csr_state_setclear_abdicate; | 191 | bool csr_state_setclear_abdicate; |
187 | 192 | int n_ir; | |
193 | int n_it; | ||
188 | /* | 194 | /* |
189 | * Spinlock for accessing fw_ohci data. Never call out of | 195 | * Spinlock for accessing fw_ohci data. Never call out of |
190 | * this driver with this lock held. | 196 | * this driver with this lock held. |
@@ -1161,6 +1167,7 @@ static struct descriptor *context_get_descriptors(struct context *ctx, | |||
1161 | static void context_run(struct context *ctx, u32 extra) | 1167 | static void context_run(struct context *ctx, u32 extra) |
1162 | { | 1168 | { |
1163 | struct fw_ohci *ohci = ctx->ohci; | 1169 | struct fw_ohci *ohci = ctx->ohci; |
1170 | ctx->active = true; | ||
1164 | 1171 | ||
1165 | reg_write(ohci, COMMAND_PTR(ctx->regs), | 1172 | reg_write(ohci, COMMAND_PTR(ctx->regs), |
1166 | le32_to_cpu(ctx->last->branch_address)); | 1173 | le32_to_cpu(ctx->last->branch_address)); |
@@ -1192,6 +1199,7 @@ static void context_stop(struct context *ctx) | |||
1192 | u32 reg; | 1199 | u32 reg; |
1193 | int i; | 1200 | int i; |
1194 | 1201 | ||
1202 | ctx->active = false; | ||
1195 | reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); | 1203 | reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); |
1196 | flush_writes(ctx->ohci); | 1204 | flush_writes(ctx->ohci); |
1197 | 1205 | ||
@@ -2641,6 +2649,10 @@ static int ohci_start_iso(struct fw_iso_context *base, | |||
2641 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); | 2649 | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); |
2642 | reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match); | 2650 | reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match); |
2643 | context_run(&ctx->context, control); | 2651 | context_run(&ctx->context, control); |
2652 | |||
2653 | ctx->sync = sync; | ||
2654 | ctx->tags = tags; | ||
2655 | |||
2644 | break; | 2656 | break; |
2645 | } | 2657 | } |
2646 | 2658 | ||
@@ -2738,6 +2750,26 @@ static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels) | |||
2738 | return ret; | 2750 | return ret; |
2739 | } | 2751 | } |
2740 | 2752 | ||
2753 | #ifdef CONFIG_PM | ||
2754 | static void ohci_resume_iso_dma(struct fw_ohci *ohci) | ||
2755 | { | ||
2756 | int i; | ||
2757 | struct iso_context *ctx; | ||
2758 | |||
2759 | for (i = 0 ; i < ohci->n_ir ; i++) { | ||
2760 | ctx = &ohci->ir_context_list[i]; | ||
2761 | if (ctx->context.active) | ||
2762 | ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); | ||
2763 | } | ||
2764 | |||
2765 | for (i = 0 ; i < ohci->n_it ; i++) { | ||
2766 | ctx = &ohci->it_context_list[i]; | ||
2767 | if (ctx->context.active) | ||
2768 | ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); | ||
2769 | } | ||
2770 | } | ||
2771 | #endif | ||
2772 | |||
2741 | static int queue_iso_transmit(struct iso_context *ctx, | 2773 | static int queue_iso_transmit(struct iso_context *ctx, |
2742 | struct fw_iso_packet *packet, | 2774 | struct fw_iso_packet *packet, |
2743 | struct fw_iso_buffer *buffer, | 2775 | struct fw_iso_buffer *buffer, |
@@ -3047,7 +3079,7 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
3047 | struct fw_ohci *ohci; | 3079 | struct fw_ohci *ohci; |
3048 | u32 bus_options, max_receive, link_speed, version; | 3080 | u32 bus_options, max_receive, link_speed, version; |
3049 | u64 guid; | 3081 | u64 guid; |
3050 | int i, err, n_ir, n_it; | 3082 | int i, err; |
3051 | size_t size; | 3083 | size_t size; |
3052 | 3084 | ||
3053 | ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); | 3085 | ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); |
@@ -3141,15 +3173,15 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
3141 | ohci->ir_context_channels = ~0ULL; | 3173 | ohci->ir_context_channels = ~0ULL; |
3142 | ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); | 3174 | ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); |
3143 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); | 3175 | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); |
3144 | n_ir = hweight32(ohci->ir_context_mask); | 3176 | ohci->n_ir = hweight32(ohci->ir_context_mask); |
3145 | size = sizeof(struct iso_context) * n_ir; | 3177 | size = sizeof(struct iso_context) * ohci->n_ir; |
3146 | ohci->ir_context_list = kzalloc(size, GFP_KERNEL); | 3178 | ohci->ir_context_list = kzalloc(size, GFP_KERNEL); |
3147 | 3179 | ||
3148 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); | 3180 | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); |
3149 | ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); | 3181 | ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); |
3150 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); | 3182 | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); |
3151 | n_it = hweight32(ohci->it_context_mask); | 3183 | ohci->n_it = hweight32(ohci->it_context_mask); |
3152 | size = sizeof(struct iso_context) * n_it; | 3184 | size = sizeof(struct iso_context) * ohci->n_it; |
3153 | ohci->it_context_list = kzalloc(size, GFP_KERNEL); | 3185 | ohci->it_context_list = kzalloc(size, GFP_KERNEL); |
3154 | 3186 | ||
3155 | if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) { | 3187 | if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) { |
@@ -3174,7 +3206,7 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
3174 | fw_notify("Added fw-ohci device %s, OHCI v%x.%x, " | 3206 | fw_notify("Added fw-ohci device %s, OHCI v%x.%x, " |
3175 | "%d IR + %d IT contexts, quirks 0x%x\n", | 3207 | "%d IR + %d IT contexts, quirks 0x%x\n", |
3176 | dev_name(&dev->dev), version >> 16, version & 0xff, | 3208 | dev_name(&dev->dev), version >> 16, version & 0xff, |
3177 | n_ir, n_it, ohci->quirks); | 3209 | ohci->n_ir, ohci->n_it, ohci->quirks); |
3178 | 3210 | ||
3179 | return 0; | 3211 | return 0; |
3180 | 3212 | ||
@@ -3291,7 +3323,13 @@ static int pci_resume(struct pci_dev *dev) | |||
3291 | reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32)); | 3323 | reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32)); |
3292 | } | 3324 | } |
3293 | 3325 | ||
3294 | return ohci_enable(&ohci->card, NULL, 0); | 3326 | err = ohci_enable(&ohci->card, NULL, 0); |
3327 | |||
3328 | if (err) | ||
3329 | return err; | ||
3330 | |||
3331 | ohci_resume_iso_dma(ohci); | ||
3332 | return 0; | ||
3295 | } | 3333 | } |
3296 | #endif | 3334 | #endif |
3297 | 3335 | ||