diff options
author | Jay Fenlason <fenlason@redhat.com> | 2009-12-11 14:23:58 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-12-11 15:43:45 -0500 |
commit | 8c0c0cc2d9f4c523fde04bdfe41e4380dec8ee54 (patch) | |
tree | eeb3a432eab9e357b332366fe7719fa932e29b88 /drivers/firewire/ohci.c | |
parent | af0940dac37545b1e7900b19c464fb6367d3f82f (diff) |
firewire: ohci: handle receive packets with a data length of zero
Queueing to receive an ISO packet with a payload length of zero
silently does nothing in dualbuffer mode, and crashes the kernel in
packet-per-buffer mode. Return an error in dualbuffer mode, because
the DMA controller won't let us do what we want, and work correctly in
packet-per-buffer mode.
Signed-off-by: Jay Fenlason <fenlason@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: stable@kernel.org
Diffstat (limited to 'drivers/firewire/ohci.c')
-rw-r--r-- | drivers/firewire/ohci.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index a71477541dc7..553c74e1e4e3 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -2189,6 +2189,13 @@ static int ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, | |||
2189 | page = payload >> PAGE_SHIFT; | 2189 | page = payload >> PAGE_SHIFT; |
2190 | offset = payload & ~PAGE_MASK; | 2190 | offset = payload & ~PAGE_MASK; |
2191 | rest = p->payload_length; | 2191 | rest = p->payload_length; |
2192 | /* | ||
2193 | * The controllers I've tested have not worked correctly when | ||
2194 | * second_req_count is zero. Rather than do something we know won't | ||
2195 | * work, return an error | ||
2196 | */ | ||
2197 | if (rest == 0) | ||
2198 | return -EINVAL; | ||
2192 | 2199 | ||
2193 | /* FIXME: make packet-per-buffer/dual-buffer a context option */ | 2200 | /* FIXME: make packet-per-buffer/dual-buffer a context option */ |
2194 | while (rest > 0) { | 2201 | while (rest > 0) { |
@@ -2242,7 +2249,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, | |||
2242 | unsigned long payload) | 2249 | unsigned long payload) |
2243 | { | 2250 | { |
2244 | struct iso_context *ctx = container_of(base, struct iso_context, base); | 2251 | struct iso_context *ctx = container_of(base, struct iso_context, base); |
2245 | struct descriptor *d = NULL, *pd = NULL; | 2252 | struct descriptor *d, *pd; |
2246 | struct fw_iso_packet *p = packet; | 2253 | struct fw_iso_packet *p = packet; |
2247 | dma_addr_t d_bus, page_bus; | 2254 | dma_addr_t d_bus, page_bus; |
2248 | u32 z, header_z, rest; | 2255 | u32 z, header_z, rest; |
@@ -2280,8 +2287,9 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, | |||
2280 | d->data_address = cpu_to_le32(d_bus + (z * sizeof(*d))); | 2287 | d->data_address = cpu_to_le32(d_bus + (z * sizeof(*d))); |
2281 | 2288 | ||
2282 | rest = payload_per_buffer; | 2289 | rest = payload_per_buffer; |
2290 | pd = d; | ||
2283 | for (j = 1; j < z; j++) { | 2291 | for (j = 1; j < z; j++) { |
2284 | pd = d + j; | 2292 | pd++; |
2285 | pd->control = cpu_to_le16(DESCRIPTOR_STATUS | | 2293 | pd->control = cpu_to_le16(DESCRIPTOR_STATUS | |
2286 | DESCRIPTOR_INPUT_MORE); | 2294 | DESCRIPTOR_INPUT_MORE); |
2287 | 2295 | ||