mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
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: state userland requirements in Kconfig help firewire: avoid memleak after phy config transmit failure firewire: fw-ohci: TSB43AB22/A dualbuffer workaround firewire: queue the right number of data firewire: warn on unfinished transactions during card removal firewire: small fw_fill_request cleanup firewire: fully initialize fw_transaction before marking it pending firewire: fix race of bus reset with request transmission
This commit is contained in:
commit
837b41b5de
7 changed files with 64 additions and 68 deletions
|
@ -16,8 +16,13 @@ config FIREWIRE
|
||||||
enable the new stack.
|
enable the new stack.
|
||||||
|
|
||||||
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 firewire-core. It functionally replaces ieee1394, raw1394,
|
called firewire-core.
|
||||||
and video1394.
|
|
||||||
|
This module functionally replaces ieee1394, raw1394, and video1394.
|
||||||
|
To access it from application programs, you generally need at least
|
||||||
|
libraw1394 version 2. IIDC/DCAM applications also need libdc1394
|
||||||
|
version 2. No libraries are required to access storage devices
|
||||||
|
through the firewire-sbp2 driver.
|
||||||
|
|
||||||
config FIREWIRE_OHCI
|
config FIREWIRE_OHCI
|
||||||
tristate "OHCI-1394 controllers"
|
tristate "OHCI-1394 controllers"
|
||||||
|
|
|
@ -539,7 +539,7 @@ fw_core_remove_card(struct fw_card *card)
|
||||||
wait_for_completion(&card->done);
|
wait_for_completion(&card->done);
|
||||||
|
|
||||||
cancel_delayed_work_sync(&card->work);
|
cancel_delayed_work_sync(&card->work);
|
||||||
fw_flush_transactions(card);
|
WARN_ON(!list_empty(&card->transaction_list));
|
||||||
del_timer_sync(&card->flush_timer);
|
del_timer_sync(&card->flush_timer);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fw_core_remove_card);
|
EXPORT_SYMBOL(fw_core_remove_card);
|
||||||
|
|
|
@ -382,9 +382,9 @@ complete_transaction(struct fw_card *card, int rcode,
|
||||||
|
|
||||||
response->response.type = FW_CDEV_EVENT_RESPONSE;
|
response->response.type = FW_CDEV_EVENT_RESPONSE;
|
||||||
response->response.rcode = rcode;
|
response->response.rcode = rcode;
|
||||||
queue_event(client, &response->event,
|
queue_event(client, &response->event, &response->response,
|
||||||
&response->response, sizeof(response->response),
|
sizeof(response->response) + response->response.length,
|
||||||
response->response.data, response->response.length);
|
NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioctl_send_request(struct client *client, void *buffer)
|
static int ioctl_send_request(struct client *client, void *buffer)
|
||||||
|
|
|
@ -171,7 +171,6 @@ struct iso_context {
|
||||||
struct fw_ohci {
|
struct fw_ohci {
|
||||||
struct fw_card card;
|
struct fw_card card;
|
||||||
|
|
||||||
u32 version;
|
|
||||||
__iomem char *registers;
|
__iomem char *registers;
|
||||||
dma_addr_t self_id_bus;
|
dma_addr_t self_id_bus;
|
||||||
__le32 *self_id_cpu;
|
__le32 *self_id_cpu;
|
||||||
|
@ -180,6 +179,8 @@ struct fw_ohci {
|
||||||
int generation;
|
int generation;
|
||||||
int request_generation; /* for timestamping incoming requests */
|
int request_generation; /* for timestamping incoming requests */
|
||||||
u32 bus_seconds;
|
u32 bus_seconds;
|
||||||
|
|
||||||
|
bool use_dualbuffer;
|
||||||
bool old_uninorth;
|
bool old_uninorth;
|
||||||
bool bus_reset_packet_quirk;
|
bool bus_reset_packet_quirk;
|
||||||
|
|
||||||
|
@ -1885,7 +1886,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
|
||||||
} else {
|
} else {
|
||||||
mask = &ohci->ir_context_mask;
|
mask = &ohci->ir_context_mask;
|
||||||
list = ohci->ir_context_list;
|
list = ohci->ir_context_list;
|
||||||
if (ohci->version >= OHCI_VERSION_1_1)
|
if (ohci->use_dualbuffer)
|
||||||
callback = handle_ir_dualbuffer_packet;
|
callback = handle_ir_dualbuffer_packet;
|
||||||
else
|
else
|
||||||
callback = handle_ir_packet_per_buffer;
|
callback = handle_ir_packet_per_buffer;
|
||||||
|
@ -1949,7 +1950,7 @@ static int ohci_start_iso(struct fw_iso_context *base,
|
||||||
} else {
|
} else {
|
||||||
index = ctx - ohci->ir_context_list;
|
index = ctx - ohci->ir_context_list;
|
||||||
control = IR_CONTEXT_ISOCH_HEADER;
|
control = IR_CONTEXT_ISOCH_HEADER;
|
||||||
if (ohci->version >= OHCI_VERSION_1_1)
|
if (ohci->use_dualbuffer)
|
||||||
control |= IR_CONTEXT_DUAL_BUFFER_MODE;
|
control |= IR_CONTEXT_DUAL_BUFFER_MODE;
|
||||||
match = (tags << 28) | (sync << 8) | ctx->base.channel;
|
match = (tags << 28) | (sync << 8) | ctx->base.channel;
|
||||||
if (cycle >= 0) {
|
if (cycle >= 0) {
|
||||||
|
@ -2279,7 +2280,7 @@ ohci_queue_iso(struct fw_iso_context *base,
|
||||||
spin_lock_irqsave(&ctx->context.ohci->lock, flags);
|
spin_lock_irqsave(&ctx->context.ohci->lock, flags);
|
||||||
if (base->type == FW_ISO_CONTEXT_TRANSMIT)
|
if (base->type == FW_ISO_CONTEXT_TRANSMIT)
|
||||||
retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
|
retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
|
||||||
else if (ctx->context.ohci->version >= OHCI_VERSION_1_1)
|
else if (ctx->context.ohci->use_dualbuffer)
|
||||||
retval = ohci_queue_iso_receive_dualbuffer(base, packet,
|
retval = ohci_queue_iso_receive_dualbuffer(base, packet,
|
||||||
buffer, payload);
|
buffer, payload);
|
||||||
else
|
else
|
||||||
|
@ -2341,7 +2342,7 @@ static int __devinit
|
||||||
pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
struct fw_ohci *ohci;
|
struct fw_ohci *ohci;
|
||||||
u32 bus_options, max_receive, link_speed;
|
u32 bus_options, max_receive, link_speed, version;
|
||||||
u64 guid;
|
u64 guid;
|
||||||
int err;
|
int err;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -2366,12 +2367,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||||
pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
|
pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
|
||||||
pci_set_drvdata(dev, ohci);
|
pci_set_drvdata(dev, ohci);
|
||||||
|
|
||||||
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
|
|
||||||
ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
|
|
||||||
dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
|
|
||||||
#endif
|
|
||||||
ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
|
|
||||||
|
|
||||||
spin_lock_init(&ohci->lock);
|
spin_lock_init(&ohci->lock);
|
||||||
|
|
||||||
tasklet_init(&ohci->bus_reset_tasklet,
|
tasklet_init(&ohci->bus_reset_tasklet,
|
||||||
|
@ -2390,6 +2385,23 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||||
goto fail_iomem;
|
goto fail_iomem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
|
||||||
|
ohci->use_dualbuffer = version >= OHCI_VERSION_1_1;
|
||||||
|
|
||||||
|
/* x86-32 currently doesn't use highmem for dma_alloc_coherent */
|
||||||
|
#if !defined(CONFIG_X86_32)
|
||||||
|
/* dual-buffer mode is broken with descriptor addresses above 2G */
|
||||||
|
if (dev->vendor == PCI_VENDOR_ID_TI &&
|
||||||
|
dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
|
||||||
|
ohci->use_dualbuffer = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
|
||||||
|
ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
|
||||||
|
dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
|
||||||
|
#endif
|
||||||
|
ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
|
||||||
|
|
||||||
ar_context_init(&ohci->ar_request_ctx, ohci,
|
ar_context_init(&ohci->ar_request_ctx, ohci,
|
||||||
OHCI1394_AsReqRcvContextControlSet);
|
OHCI1394_AsReqRcvContextControlSet);
|
||||||
|
|
||||||
|
@ -2441,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto fail_self_id;
|
goto fail_self_id;
|
||||||
|
|
||||||
ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
|
|
||||||
fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
|
fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
|
||||||
dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
|
dev->dev.bus_id, version >> 16, version & 0xff);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_self_id:
|
fail_self_id:
|
||||||
|
|
|
@ -510,8 +510,6 @@ fw_core_handle_bus_reset(struct fw_card *card,
|
||||||
struct fw_node *local_node;
|
struct fw_node *local_node;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
fw_flush_transactions(card);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&card->lock, flags);
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
@ -151,7 +152,7 @@ transmit_complete_callback(struct fw_packet *packet,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
||||||
int node_id, int source_id, int generation, int speed,
|
int destination_id, int source_id, int generation, int speed,
|
||||||
unsigned long long offset, void *payload, size_t length)
|
unsigned long long offset, void *payload, size_t length)
|
||||||
{
|
{
|
||||||
int ext_tcode;
|
int ext_tcode;
|
||||||
|
@ -166,7 +167,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
||||||
HEADER_RETRY(RETRY_X) |
|
HEADER_RETRY(RETRY_X) |
|
||||||
HEADER_TLABEL(tlabel) |
|
HEADER_TLABEL(tlabel) |
|
||||||
HEADER_TCODE(tcode) |
|
HEADER_TCODE(tcode) |
|
||||||
HEADER_DESTINATION(node_id);
|
HEADER_DESTINATION(destination_id);
|
||||||
packet->header[1] =
|
packet->header[1] =
|
||||||
HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
|
HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
|
||||||
packet->header[2] =
|
packet->header[2] =
|
||||||
|
@ -252,7 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||||
fw_transaction_callback_t callback, void *callback_data)
|
fw_transaction_callback_t callback, void *callback_data)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int tlabel, source;
|
int tlabel;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bump the flush timer up 100ms first of all so we
|
* Bump the flush timer up 100ms first of all so we
|
||||||
|
@ -268,7 +269,6 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||||
|
|
||||||
spin_lock_irqsave(&card->lock, flags);
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
|
|
||||||
source = card->node_id;
|
|
||||||
tlabel = card->current_tlabel;
|
tlabel = card->current_tlabel;
|
||||||
if (card->tlabel_mask & (1 << tlabel)) {
|
if (card->tlabel_mask & (1 << tlabel)) {
|
||||||
spin_unlock_irqrestore(&card->lock, flags);
|
spin_unlock_irqrestore(&card->lock, flags);
|
||||||
|
@ -279,77 +279,58 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||||
card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
|
card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
|
||||||
card->tlabel_mask |= (1 << tlabel);
|
card->tlabel_mask |= (1 << tlabel);
|
||||||
|
|
||||||
list_add_tail(&t->link, &card->transaction_list);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&card->lock, flags);
|
|
||||||
|
|
||||||
/* Initialize rest of transaction, fill out packet and send it. */
|
|
||||||
t->node_id = node_id;
|
t->node_id = node_id;
|
||||||
t->tlabel = tlabel;
|
t->tlabel = tlabel;
|
||||||
t->callback = callback;
|
t->callback = callback;
|
||||||
t->callback_data = callback_data;
|
t->callback_data = callback_data;
|
||||||
|
|
||||||
fw_fill_request(&t->packet, tcode, t->tlabel,
|
fw_fill_request(&t->packet, tcode, t->tlabel, node_id, card->node_id,
|
||||||
node_id, source, generation,
|
generation, speed, offset, payload, length);
|
||||||
speed, offset, payload, length);
|
|
||||||
t->packet.callback = transmit_complete_callback;
|
t->packet.callback = transmit_complete_callback;
|
||||||
|
|
||||||
|
list_add_tail(&t->link, &card->transaction_list);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&card->lock, flags);
|
||||||
|
|
||||||
card->driver->send_request(card, &t->packet);
|
card->driver->send_request(card, &t->packet);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fw_send_request);
|
EXPORT_SYMBOL(fw_send_request);
|
||||||
|
|
||||||
struct fw_phy_packet {
|
static DEFINE_MUTEX(phy_config_mutex);
|
||||||
struct fw_packet packet;
|
static DECLARE_COMPLETION(phy_config_done);
|
||||||
struct completion done;
|
|
||||||
struct kref kref;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void phy_packet_release(struct kref *kref)
|
|
||||||
{
|
|
||||||
struct fw_phy_packet *p =
|
|
||||||
container_of(kref, struct fw_phy_packet, kref);
|
|
||||||
kfree(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void transmit_phy_packet_callback(struct fw_packet *packet,
|
static void transmit_phy_packet_callback(struct fw_packet *packet,
|
||||||
struct fw_card *card, int status)
|
struct fw_card *card, int status)
|
||||||
{
|
{
|
||||||
struct fw_phy_packet *p =
|
complete(&phy_config_done);
|
||||||
container_of(packet, struct fw_phy_packet, packet);
|
|
||||||
|
|
||||||
complete(&p->done);
|
|
||||||
kref_put(&p->kref, phy_packet_release);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct fw_packet phy_config_packet = {
|
||||||
|
.header_length = 8,
|
||||||
|
.payload_length = 0,
|
||||||
|
.speed = SCODE_100,
|
||||||
|
.callback = transmit_phy_packet_callback,
|
||||||
|
};
|
||||||
|
|
||||||
void fw_send_phy_config(struct fw_card *card,
|
void fw_send_phy_config(struct fw_card *card,
|
||||||
int node_id, int generation, int gap_count)
|
int node_id, int generation, int gap_count)
|
||||||
{
|
{
|
||||||
struct fw_phy_packet *p;
|
|
||||||
long timeout = DIV_ROUND_UP(HZ, 10);
|
long timeout = DIV_ROUND_UP(HZ, 10);
|
||||||
u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
|
u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
|
||||||
PHY_CONFIG_ROOT_ID(node_id) |
|
PHY_CONFIG_ROOT_ID(node_id) |
|
||||||
PHY_CONFIG_GAP_COUNT(gap_count);
|
PHY_CONFIG_GAP_COUNT(gap_count);
|
||||||
|
|
||||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
mutex_lock(&phy_config_mutex);
|
||||||
if (p == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p->packet.header[0] = data;
|
phy_config_packet.header[0] = data;
|
||||||
p->packet.header[1] = ~data;
|
phy_config_packet.header[1] = ~data;
|
||||||
p->packet.header_length = 8;
|
phy_config_packet.generation = generation;
|
||||||
p->packet.payload_length = 0;
|
INIT_COMPLETION(phy_config_done);
|
||||||
p->packet.speed = SCODE_100;
|
|
||||||
p->packet.generation = generation;
|
|
||||||
p->packet.callback = transmit_phy_packet_callback;
|
|
||||||
init_completion(&p->done);
|
|
||||||
kref_set(&p->kref, 2);
|
|
||||||
|
|
||||||
card->driver->send_request(card, &p->packet);
|
card->driver->send_request(card, &phy_config_packet);
|
||||||
timeout = wait_for_completion_timeout(&p->done, timeout);
|
wait_for_completion_timeout(&phy_config_done, timeout);
|
||||||
kref_put(&p->kref, phy_packet_release);
|
|
||||||
|
|
||||||
/* will leak p if the callback is never executed */
|
mutex_unlock(&phy_config_mutex);
|
||||||
WARN_ON(timeout == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fw_flush_transactions(struct fw_card *card)
|
void fw_flush_transactions(struct fw_card *card)
|
||||||
|
|
|
@ -748,6 +748,7 @@
|
||||||
#define PCI_VENDOR_ID_TI 0x104c
|
#define PCI_VENDOR_ID_TI 0x104c
|
||||||
#define PCI_DEVICE_ID_TI_TVP4020 0x3d07
|
#define PCI_DEVICE_ID_TI_TVP4020 0x3d07
|
||||||
#define PCI_DEVICE_ID_TI_4450 0x8011
|
#define PCI_DEVICE_ID_TI_4450 0x8011
|
||||||
|
#define PCI_DEVICE_ID_TI_TSB43AB22 0x8023
|
||||||
#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
|
#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
|
||||||
#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033
|
#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033
|
||||||
#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034
|
#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034
|
||||||
|
|
Loading…
Reference in a new issue