Commit c3ca48f0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
  firewire: core: ignore link-active bit of new nodes, fix device recognition
  firewire: sbp2: revert obsolete 'fix stall with "Unsolicited response"'
  firewire: core: increase default SPLIT_TIMEOUT value
  firewire: ohci: Misleading kfree in ohci.c::pci_probe/remove
  firewire: ohci: omit IntEvent.busReset check rom AT queueing
  firewire: ohci: prevent starting of iso contexts with empty queue
  firewire: ohci: prevent iso completion callbacks after context stop
  firewire: core: rename some variables
  firewire: nosy: should work on Power Mac G4 PCI too
  firewire: core: fix card->reset_jiffies overflow
  firewire: cdev: remove unneeded reference
  firewire: cdev: always wait for outbound transactions to complete
  firewire: cdev: remove unneeded idr_find() from complete_transaction()
  firewire: ohci: log dead DMA contexts
parents 4e76ae44 115881d3
...@@ -75,7 +75,8 @@ config FIREWIRE_NOSY ...@@ -75,7 +75,8 @@ config FIREWIRE_NOSY
The following cards are known to be based on PCILynx or PCILynx-2: The following cards are known to be based on PCILynx or PCILynx-2:
IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2 IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2
(PCI card), Newer Technology FireWire 2 Go (CardBus card), (PCI card), Newer Technology FireWire 2 Go (CardBus card),
Apple Power Mac G3 blue & white (onboard controller). Apple Power Mac G3 blue & white and G4 with PCI graphics
(onboard controller).
To compile this driver as a module, say M here: The module will be To compile this driver as a module, say M here: The module will be
called nosy. Source code of a userspace interface to nosy, called called nosy. Source code of a userspace interface to nosy, called
......
...@@ -75,6 +75,13 @@ static size_t config_rom_length = 1 + 4 + 1 + 1; ...@@ -75,6 +75,13 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
#define BIB_IRMC ((1) << 31) #define BIB_IRMC ((1) << 31)
#define NODE_CAPABILITIES 0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */ #define NODE_CAPABILITIES 0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */
/*
* IEEE-1394 specifies a default SPLIT_TIMEOUT value of 800 cycles (100 ms),
* but we have to make it longer because there are many devices whose firmware
* is just too slow for that.
*/
#define DEFAULT_SPLIT_TIMEOUT (2 * 8000)
#define CANON_OUI 0x000085 #define CANON_OUI 0x000085
static void generate_config_rom(struct fw_card *card, __be32 *config_rom) static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
...@@ -233,7 +240,7 @@ static void br_work(struct work_struct *work) ...@@ -233,7 +240,7 @@ static void br_work(struct work_struct *work)
/* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
if (card->reset_jiffies != 0 && if (card->reset_jiffies != 0 &&
time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) { time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) {
if (!schedule_delayed_work(&card->br_work, 2 * HZ)) if (!schedule_delayed_work(&card->br_work, 2 * HZ))
fw_card_put(card); fw_card_put(card);
return; return;
...@@ -316,7 +323,8 @@ static void bm_work(struct work_struct *work) ...@@ -316,7 +323,8 @@ static void bm_work(struct work_struct *work)
irm_id = card->irm_node->node_id; irm_id = card->irm_node->node_id;
local_id = card->local_node->node_id; local_id = card->local_node->node_id;
grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 8)); grace = time_after64(get_jiffies_64(),
card->reset_jiffies + DIV_ROUND_UP(HZ, 8));
if ((is_next_generation(generation, card->bm_generation) && if ((is_next_generation(generation, card->bm_generation) &&
!card->bm_abdicate) || !card->bm_abdicate) ||
...@@ -511,10 +519,11 @@ void fw_card_initialize(struct fw_card *card, ...@@ -511,10 +519,11 @@ void fw_card_initialize(struct fw_card *card,
card->device = device; card->device = device;
card->current_tlabel = 0; card->current_tlabel = 0;
card->tlabel_mask = 0; card->tlabel_mask = 0;
card->split_timeout_hi = 0; card->split_timeout_hi = DEFAULT_SPLIT_TIMEOUT / 8000;
card->split_timeout_lo = 800 << 19; card->split_timeout_lo = (DEFAULT_SPLIT_TIMEOUT % 8000) << 19;
card->split_timeout_cycles = 800; card->split_timeout_cycles = DEFAULT_SPLIT_TIMEOUT;
card->split_timeout_jiffies = DIV_ROUND_UP(HZ, 10); card->split_timeout_jiffies =
DIV_ROUND_UP(DEFAULT_SPLIT_TIMEOUT * HZ, 8000);
card->color = 0; card->color = 0;
card->broadcast_channel = BROADCAST_CHANNEL_INITIAL; card->broadcast_channel = BROADCAST_CHANNEL_INITIAL;
......
...@@ -64,6 +64,7 @@ struct client { ...@@ -64,6 +64,7 @@ struct client {
struct idr resource_idr; struct idr resource_idr;
struct list_head event_list; struct list_head event_list;
wait_queue_head_t wait; wait_queue_head_t wait;
wait_queue_head_t tx_flush_wait;
u64 bus_reset_closure; u64 bus_reset_closure;
struct fw_iso_context *iso_context; struct fw_iso_context *iso_context;
...@@ -251,6 +252,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file) ...@@ -251,6 +252,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
idr_init(&client->resource_idr); idr_init(&client->resource_idr);
INIT_LIST_HEAD(&client->event_list); INIT_LIST_HEAD(&client->event_list);
init_waitqueue_head(&client->wait); init_waitqueue_head(&client->wait);
init_waitqueue_head(&client->tx_flush_wait);
INIT_LIST_HEAD(&client->phy_receiver_link); INIT_LIST_HEAD(&client->phy_receiver_link);
kref_init(&client->kref); kref_init(&client->kref);
...@@ -520,10 +522,6 @@ static int release_client_resource(struct client *client, u32 handle, ...@@ -520,10 +522,6 @@ static int release_client_resource(struct client *client, u32 handle,
static void release_transaction(struct client *client, static void release_transaction(struct client *client,
struct client_resource *resource) struct client_resource *resource)
{ {
struct outbound_transaction_resource *r = container_of(resource,
struct outbound_transaction_resource, resource);
fw_cancel_transaction(client->device->card, &r->transaction);
} }
static void complete_transaction(struct fw_card *card, int rcode, static void complete_transaction(struct fw_card *card, int rcode,
...@@ -540,22 +538,9 @@ static void complete_transaction(struct fw_card *card, int rcode, ...@@ -540,22 +538,9 @@ static void complete_transaction(struct fw_card *card, int rcode,
memcpy(rsp->data, payload, rsp->length); memcpy(rsp->data, payload, rsp->length);
spin_lock_irqsave(&client->lock, flags); spin_lock_irqsave(&client->lock, flags);
/* idr_remove(&client->resource_idr, e->r.resource.handle);
* 1. If called while in shutdown, the idr tree must be left untouched. if (client->in_shutdown)
* The idr handle will be removed and the client reference will be wake_up(&client->tx_flush_wait);
* dropped later.
* 2. If the call chain was release_client_resource ->
* release_transaction -> complete_transaction (instead of a normal
* conclusion of the transaction), i.e. if this resource was already
* unregistered from the idr, the client reference will be dropped
* by release_client_resource and we must not drop it here.
*/
if (!client->in_shutdown &&
idr_find(&client->resource_idr, e->r.resource.handle)) {
idr_remove(&client->resource_idr, e->r.resource.handle);
/* Drop the idr's reference */
client_put(client);
}
spin_unlock_irqrestore(&client->lock, flags); spin_unlock_irqrestore(&client->lock, flags);
rsp->type = FW_CDEV_EVENT_RESPONSE; rsp->type = FW_CDEV_EVENT_RESPONSE;
...@@ -575,7 +560,7 @@ static void complete_transaction(struct fw_card *card, int rcode, ...@@ -575,7 +560,7 @@ static void complete_transaction(struct fw_card *card, int rcode,
queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
NULL, 0); NULL, 0);
/* Drop the transaction callback's reference */ /* Drop the idr's reference */
client_put(client); client_put(client);
} }
...@@ -614,9 +599,6 @@ static int init_request(struct client *client, ...@@ -614,9 +599,6 @@ static int init_request(struct client *client,
if (ret < 0) if (ret < 0)
goto failed; goto failed;
/* Get a reference for the transaction callback */
client_get(client);
fw_send_request(client->device->card, &e->r.transaction, fw_send_request(client->device->card, &e->r.transaction,
request->tcode, destination_id, request->generation, request->tcode, destination_id, request->generation,
speed, request->offset, e->response.data, speed, request->offset, e->response.data,
...@@ -1223,7 +1205,8 @@ static void iso_resource_work(struct work_struct *work) ...@@ -1223,7 +1205,8 @@ static void iso_resource_work(struct work_struct *work)
todo = r->todo; todo = r->todo;
/* Allow 1000ms grace period for other reallocations. */ /* Allow 1000ms grace period for other reallocations. */
if (todo == ISO_RES_ALLOC && if (todo == ISO_RES_ALLOC &&
time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) { time_before64(get_jiffies_64(),
client->device->card->reset_jiffies + HZ)) {
schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3)); schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
skip = true; skip = true;
} else { } else {
...@@ -1678,6 +1661,25 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1678,6 +1661,25 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
return ret; return ret;
} }
static int is_outbound_transaction_resource(int id, void *p, void *data)
{
struct client_resource *resource = p;
return resource->release == release_transaction;
}
static int has_outbound_transactions(struct client *client)
{
int ret;
spin_lock_irq(&client->lock);
ret = idr_for_each(&client->resource_idr,
is_outbound_transaction_resource, NULL);
spin_unlock_irq(&client->lock);
return ret;
}
static int shutdown_resource(int id, void *p, void *data) static int shutdown_resource(int id, void *p, void *data)
{ {
struct client_resource *resource = p; struct client_resource *resource = p;
...@@ -1713,6 +1715,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file) ...@@ -1713,6 +1715,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
client->in_shutdown = true; client->in_shutdown = true;
spin_unlock_irq(&client->lock); spin_unlock_irq(&client->lock);
wait_event(client->tx_flush_wait, !has_outbound_transactions(client));
idr_for_each(&client->resource_idr, shutdown_resource, client); idr_for_each(&client->resource_idr, shutdown_resource, client);
idr_remove_all(&client->resource_idr); idr_remove_all(&client->resource_idr);
idr_destroy(&client->resource_idr); idr_destroy(&client->resource_idr);
......
...@@ -747,7 +747,8 @@ static void fw_device_shutdown(struct work_struct *work) ...@@ -747,7 +747,8 @@ static void fw_device_shutdown(struct work_struct *work)
container_of(work, struct fw_device, work.work); container_of(work, struct fw_device, work.work);
int minor = MINOR(device->device.devt); int minor = MINOR(device->device.devt);
if (time_is_after_jiffies(device->card->reset_jiffies + SHUTDOWN_DELAY) if (time_before64(get_jiffies_64(),
device->card->reset_jiffies + SHUTDOWN_DELAY)
&& !list_empty(&device->card->link)) { && !list_empty(&device->card->link)) {
schedule_delayed_work(&device->work, SHUTDOWN_DELAY); schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
return; return;
...@@ -954,8 +955,9 @@ static void fw_device_init(struct work_struct *work) ...@@ -954,8 +955,9 @@ static void fw_device_init(struct work_struct *work)
device->config_rom_retries++; device->config_rom_retries++;
schedule_delayed_work(&device->work, RETRY_DELAY); schedule_delayed_work(&device->work, RETRY_DELAY);
} else { } else {
fw_notify("giving up on config rom for node id %x\n", if (device->node->link_on)
device->node_id); fw_notify("giving up on config rom for node id %x\n",
device->node_id);
if (device->node == device->card->root_node) if (device->node == device->card->root_node)
fw_schedule_bm_work(device->card, 0); fw_schedule_bm_work(device->card, 0);
fw_device_release(&device->device); fw_device_release(&device->device);
...@@ -1168,9 +1170,12 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) ...@@ -1168,9 +1170,12 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
switch (event) { switch (event) {
case FW_NODE_CREATED: case FW_NODE_CREATED:
case FW_NODE_LINK_ON: /*
if (!node->link_on) * Attempt to scan the node, regardless whether its self ID has
break; * the L (link active) flag set or not. Some broken devices
* send L=0 but have an up-and-running link; others send L=1
* without actually having a link.
*/
create: create:
device = kzalloc(sizeof(*device), GFP_ATOMIC); device = kzalloc(sizeof(*device), GFP_ATOMIC);
if (device == NULL) if (device == NULL)
...@@ -1213,6 +1218,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) ...@@ -1213,6 +1218,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
break; break;
case FW_NODE_INITIATED_RESET: case FW_NODE_INITIATED_RESET:
case FW_NODE_LINK_ON:
device = node->data; device = node->data;
if (device == NULL) if (device == NULL)
goto create; goto create;
...@@ -1230,10 +1236,10 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) ...@@ -1230,10 +1236,10 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
break; break;
case FW_NODE_UPDATED: case FW_NODE_UPDATED:
if (!node->link_on || node->data == NULL) device = node->data;
if (device == NULL)
break; break;
device = node->data;
device->node_id = node->node_id; device->node_id = node->node_id;
smp_wmb(); /* update node_id before generation */ smp_wmb(); /* update node_id before generation */
device->generation = card->generation; device->generation = card->generation;
......
...@@ -235,45 +235,45 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, ...@@ -235,45 +235,45 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
static int manage_channel(struct fw_card *card, int irm_id, int generation, static int manage_channel(struct fw_card *card, int irm_id, int generation,
u32 channels_mask, u64 offset, bool allocate, __be32 data[2]) u32 channels_mask, u64 offset, bool allocate, __be32 data[2])
{ {
__be32 c, all, old; __be32 bit, all, old;
int i, ret = -EIO, retry = 5; int channel, ret = -EIO, retry = 5;
old = all = allocate ? cpu_to_be32(~0) : 0; old = all = allocate ? cpu_to_be32(~0) : 0;
for (i = 0; i < 32; i++) { for (channel = 0; channel < 32; channel++) {
if (!(channels_mask & 1 << i)) if (!(channels_mask & 1 << channel))
continue; continue;
ret = -EBUSY; ret = -EBUSY;
c = cpu_to_be32(1 << (31 - i)); bit = cpu_to_be32(1 << (31 - channel));
if ((old & c) != (all & c)) if ((old & bit) != (all & bit))
continue; continue;
data[0] = old; data[0] = old;
data[1] = old ^ c; data[1] = old ^ bit;
switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
irm_id, generation, SCODE_100, irm_id, generation, SCODE_100,
offset, data, 8)) { offset, data, 8)) {
case RCODE_GENERATION: case RCODE_GENERATION:
/* A generation change frees all channels. */ /* A generation change frees all channels. */
return allocate ? -EAGAIN : i; return allocate ? -EAGAIN : channel;
case RCODE_COMPLETE: case RCODE_COMPLETE:
if (data[0] == old) if (data[0] == old)
return i; return channel;
old = data[0]; old = data[0];
/* Is the IRM 1394a-2000 compliant? */ /* Is the IRM 1394a-2000 compliant? */
if ((data[0] & c) == (data[1] & c)) if ((data[0] & bit) == (data[1] & bit))
continue; continue;
/* 1394-1995 IRM, fall through to retry. */ /* 1394-1995 IRM, fall through to retry. */
default: default:
if (retry) { if (retry) {
retry--; retry--;
i--; channel--;
} else { } else {
ret = -EIO; ret = -EIO;
} }
......
...@@ -545,7 +545,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, ...@@ -545,7 +545,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
*/ */
smp_wmb(); smp_wmb();
card->generation = generation; card->generation = generation;
card->reset_jiffies = jiffies; card->reset_jiffies = get_jiffies_64();
card->bm_node_id = 0xffff; card->bm_node_id = 0xffff;
card->bm_abdicate = bm_abdicate; card->bm_abdicate = bm_abdicate;
fw_schedule_bm_work(card, 0); fw_schedule_bm_work(card, 0);
......
...@@ -208,9 +208,11 @@ struct fw_ohci { ...@@ -208,9 +208,11 @@ struct fw_ohci {
struct context at_request_ctx; struct context at_request_ctx;
struct context at_response_ctx; struct context at_response_ctx;
u32 it_context_support;
u32 it_context_mask; /* unoccupied IT contexts */ u32 it_context_mask; /* unoccupied IT contexts */
struct iso_context *it_context_list; struct iso_context *it_context_list;
u64 ir_context_channels; /* unoccupied channels */ u64 ir_context_channels; /* unoccupied channels */
u32 ir_context_support;
u32 ir_context_mask; /* unoccupied IR contexts */ u32 ir_context_mask; /* unoccupied IR contexts */
struct iso_context *ir_context_list; struct iso_context *ir_context_list;
u64 mc_channels; /* channels in use by the multichannel IR context */ u64 mc_channels; /* channels in use by the multichannel IR context */
...@@ -338,7 +340,7 @@ static void log_irqs(u32 evt) ...@@ -338,7 +340,7 @@ static void log_irqs(u32 evt)
!(evt & OHCI1394_busReset)) !(evt & OHCI1394_busReset))
return; return;
fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
evt & OHCI1394_selfIDComplete ? " selfID" : "", evt & OHCI1394_selfIDComplete ? " selfID" : "",
evt & OHCI1394_RQPkt ? " AR_req" : "", evt & OHCI1394_RQPkt ? " AR_req" : "",
evt & OHCI1394_RSPkt ? " AR_resp" : "", evt & OHCI1394_RSPkt ? " AR_resp" : "",
...@@ -351,6 +353,7 @@ static void log_irqs(u32 evt) ...@@ -351,6 +353,7 @@ static void log_irqs(u32 evt)
evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "", evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "",
evt & OHCI1394_regAccessFail ? " regAccessFail" : "", evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
evt & OHCI1394_unrecoverableError ? " unrecoverableError" : "",
evt & OHCI1394_busReset ? " busReset" : "", evt & OHCI1394_busReset ? " busReset" : "",
evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
OHCI1394_RSPkt | OHCI1394_reqTxComplete | OHCI1394_RSPkt | OHCI1394_reqTxComplete |
...@@ -1326,21 +1329,8 @@ static int at_context_queue_packet(struct context *ctx, ...@@ -1326,21 +1329,8 @@ static int at_context_queue_packet(struct context *ctx,
DESCRIPTOR_IRQ_ALWAYS | DESCRIPTOR_IRQ_ALWAYS |
DESCRIPTOR_BRANCH_ALWAYS); DESCRIPTOR_BRANCH_ALWAYS);
/* /* FIXME: Document how the locking works. */
* If the controller and packet generations don't match, we need to if (ohci->generation != packet->generation) {
* bail out and try again. If IntEvent.busReset is set, the AT context
* is halted, so appending to the context and trying to run it is
* futile. Most controllers do the right thing and just flush the AT
* queue (per section 7.2.3.2 of the OHCI 1.1 specification), but
* some controllers (like a JMicron JMB381 PCI-e) misbehave and wind
* up stalling out. So we just bail out in software and try again
* later, and everyone is happy.
* FIXME: Test of IntEvent.busReset may no longer be necessary since we
* flush AT queues in bus_reset_tasklet.
* FIXME: Document how the locking works.
*/
if (ohci->generation != packet->generation ||
reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
if (packet->payload_mapped) if (packet->payload_mapped)
dma_unmap_single(ohci->card.device, payload_bus, dma_unmap_single(ohci->card.device, payload_bus,
packet->payload_length, DMA_TO_DEVICE); packet->payload_length, DMA_TO_DEVICE);
...@@ -1590,6 +1580,47 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) ...@@ -1590,6 +1580,47 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet)
} }
static void detect_dead_context(struct fw_ohci *ohci,
const char *name, unsigned int regs)
{
u32 ctl;
ctl = reg_read(ohci, CONTROL_SET(regs));
if (ctl & CONTEXT_DEAD) {
#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
fw_error("DMA context %s has stopped, error code: %s\n",
name, evts[ctl & 0x1f]);
#else
fw_error("DMA context %s has stopped, error code: %#x\n",
name, ctl & 0x1f);
#endif
}
}
static void handle_dead_contexts(struct fw_ohci *ohci)
{
unsigned int i;
char name[8];
detect_dead_context(ohci, "ATReq", OHCI1394_AsReqTrContextBase);
detect_dead_context(ohci, "ATRsp", OHCI1394_AsRspTrContextBase);
detect_dead_context(ohci, "ARReq", OHCI1394_AsReqRcvContextBase);
detect_dead_context(ohci, "ARRsp", OHCI1394_AsRspRcvContextBase);
for (i = 0; i < 32; ++i) {
if (!(ohci->it_context_support & (1 << i)))
continue;
sprintf(name, "IT%u", i);
detect_dead_context(ohci, name, OHCI1394_IsoXmitContextBase(i));
}
for (i = 0; i < 32; ++i) {
if (!(ohci->ir_context_support & (1 << i)))
continue;
sprintf(name, "IR%u", i);
detect_dead_context(ohci, name, OHCI1394_IsoRcvContextBase(i));
}
/* TODO: maybe try to flush and restart the dead contexts */
}
static u32 cycle_timer_ticks(u32 cycle_timer) static u32 cycle_timer_ticks(u32 cycle_timer)
{ {
u32 ticks; u32 ticks;
...@@ -1904,6 +1935,9 @@ static irqreturn_t irq_handler(int irq, void *data) ...@@ -1904,6 +1935,9 @@ static irqreturn_t irq_handler(int irq, void *data)
fw_notify("isochronous cycle inconsistent\n"); fw_notify("isochronous cycle inconsistent\n");
} }
if (unlikely(event & OHCI1394_unrecoverableError))
handle_dead_contexts(ohci);
if (event & OHCI1394_cycle64Seconds) { if (event & OHCI1394_cycle64Seconds) {
spin_lock(&ohci->lock); spin_lock(&ohci->lock);
update_bus_time(ohci); update_bus_time(ohci);
...@@ -2141,7 +2175,9 @@ static int ohci_enable(struct fw_card *card, ...@@ -2141,7 +2175,9 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_selfIDComplete | OHCI1394_selfIDComplete |
OHCI1394_regAccessFail | OHCI1394_regAccessFail |
OHCI1394_cycle64Seconds | OHCI1394_cycle64Seconds |
OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong | OHCI1394_cycleInconsistent |
OHCI1394_unrecoverableError |
OHCI1394_cycleTooLong |
OHCI1394_masterIntEnable; OHCI1394_masterIntEnable;
if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
irqs |= OHCI1394_busReset; irqs |= OHCI1394_busReset;
...@@ -2657,6 +2693,10 @@ static int ohci_start_iso(struct fw_iso_context *base, ...@@ -2657,6 +2693,10 @@ static int ohci_start_iso(struct fw_iso_context *base,
u32 control = IR_CONTEXT_ISOCH_HEADER, match; u32 control = IR_CONTEXT_ISOCH_HEADER, match;
int index; int index;
/* the controller cannot start without any queued packets */
if (ctx->context.last->branch_address == 0)
return -ENODATA;
switch (ctx->base.type) { switch (ctx->base.type) {
case FW_ISO_CONTEXT_TRANSMIT: case FW_ISO_CONTEXT_TRANSMIT:
index = ctx - ohci->it_context_list; index = ctx - ohci->it_context_list;
...@@ -2715,6 +2755,7 @@ static int ohci_stop_iso(struct fw_iso_context *base) ...@@ -2715,6 +2755,7 @@ static int ohci_stop_iso(struct fw_iso_context *base)
} }
flush_writes(ohci); flush_writes(ohci);
context_stop(&ctx->context); context_stop(&ctx->context);
tasklet_kill(&ctx->context.tasklet);
return 0; return 0;
} }
...@@ -3207,15 +3248,17 @@ static int __devinit pci_probe(struct pci_dev *dev, ...@@ -3207,15 +3248,17 @@ static int __devinit pci_probe(struct pci_dev *dev,
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
ohci->ir_context_channels = ~0ULL; ohci->ir_context_channels = ~0ULL;
ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); ohci->ir_context_support = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
ohci->ir_context_mask = ohci->ir_context_support;
ohci->n_ir = hweight32(ohci->ir_context_mask); ohci->n_ir = hweight32(ohci->ir_context_mask);
size = sizeof(struct iso_context) * ohci->n_ir; size = sizeof(struct iso_context) * ohci->n_ir;
ohci->ir_context_list = kzalloc(size, GFP_KERNEL); ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
ohci->it_context_mask = ohci->it_context_support;
ohci->n_it = hweight32(ohci->it_context_mask); ohci->n_it = hweight32(ohci->it_context_mask);
size = sizeof(struct iso_context) * ohci->n_it; size = sizeof(struct iso_context) * ohci->n_it;
ohci->it_context_list = kzalloc(size, GFP_KERNEL); ohci->it_context_list = kzalloc(size, GFP_KERNEL);
...@@ -3266,7 +3309,7 @@ static int __devinit pci_probe(struct pci_dev *dev, ...@@ -3266,7 +3309,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
fail_disable: fail_disable:
pci_disable_device(dev); pci_disable_device(dev);
fail_free: fail_free:
kfree(&ohci->card); kfree(ohci);
pmac_ohci_off(dev); pmac_ohci_off(dev);
fail: fail:
if (err == -ENOMEM) if (err == -ENOMEM)
...@@ -3310,7 +3353,7 @@ static void pci_remove(struct pci_dev *dev) ...@@ -3310,7 +3353,7 @@ static void pci_remove(struct pci_dev *dev)
pci_iounmap(dev, ohci->registers); pci_iounmap(dev, ohci->registers);
pci_release_region(dev, 0); pci_release_region(dev, 0);
pci_disable_device(dev); pci_disable_device(dev);
kfree(&ohci->card); kfree(ohci);
pmac_ohci_off(dev); pmac_ohci_off(dev);
fw_notify("Removed fw-ohci device.\n"); fw_notify("Removed fw-ohci device.\n");
......
...@@ -472,18 +472,12 @@ static void complete_transaction(struct fw_card *card, int rcode, ...@@ -472,18 +472,12 @@ static void complete_transaction(struct fw_card *card, int rcode,
* So this callback only sets the rcode if it hasn't already * So this callback only sets the rcode if it hasn't already
* been set and only does the cleanup if the transaction * been set and only does the cleanup if the transaction
* failed and we didn't already get a status write. * failed and we didn't already get a status write.
*
* Here we treat RCODE_CANCELLED like RCODE_COMPLETE because some
* OXUF936QSE firmwares occasionally respond after Split_Timeout and
* complete the ORB just fine. Note, we also get RCODE_CANCELLED
* from sbp2_cancel_orbs() if fw_cancel_transaction() == 0.
*/ */
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
if (orb->rcode == -1) if (orb->rcode == -1)
orb->rcode = rcode; orb->rcode = rcode;
if (orb->rcode != RCODE_COMPLETE) {
if (orb->rcode != RCODE_COMPLETE && orb->rcode != RCODE_CANCELLED) {
list_del(&orb->link); list_del(&orb->link);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
...@@ -532,7 +526,8 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) ...@@ -532,7 +526,8 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
list_for_each_entry_safe(orb, next, &list, link) { list_for_each_entry_safe(orb, next, &list, link) {
retval = 0; retval = 0;
fw_cancel_transaction(device->card, &orb->t); if (fw_cancel_transaction(device->card, &orb->t) == 0)
continue;
orb->rcode = RCODE_CANCELLED; orb->rcode = RCODE_CANCELLED;
orb->callback(orb, NULL); orb->callback(orb, NULL);
......
...@@ -93,7 +93,7 @@ struct fw_card { ...@@ -93,7 +93,7 @@ struct fw_card {
int current_tlabel; int current_tlabel;
u64 tlabel_mask; u64 tlabel_mask;
struct list_head transaction_list; struct list_head transaction_list;
unsigned long reset_jiffies; u64 reset_jiffies;
u32 split_timeout_hi; u32 split_timeout_hi;
u32 split_timeout_lo; u32 split_timeout_lo;
......
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