mirror of https://github.com/torvalds/linux.git
firewire updates for v6.19
This release includes two changes for core functions, which affects all
use cases of this subsystem.
- Handle per-device interoperability quirks
It is well known that some devices have quirks affecting
interoperability. To identify such quirks at an early stages of
device detection, the step for reading the configuration ROM contents
has been changed. As a side effect, the entire detection process is
now performed at the basic transaction speed (S100), without no trial
to probe higher supported speeds.
With this change, the following devices should now work with fewer
issues:
- TASCAM FW-1884, FW-1804, and FW-1082
- MOTU Audio Express
- Safer removals of host card
There was a race condition between host card removal and handling of
bus reset events in the workqueue. This appears to be a long standing
issue (for a dozen years or so[1]), and recent changes to use more
workqueues escalate it. To solve it, a new callback has been added to
the 1394 OHCI PCI driver to unregister the interrupt sources and wait
for workqueue completions when removing a card instance.
[1] https://sourceforge.net/p/linux1394/mailman/linux1394-devel/thread/20250629024836.GA16759%40workstation.local/#msg59200628
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQQE66IEYNDXNBPeGKSsLtaWM8LwEwUCaS4gGwAKCRCsLtaWM8Lw
E1EhAP48BItL1FUcn1oHGU019iHCE57vTOxPE89LXlinAe7GAAD/WUq77tQ84RUJ
gCuml3cWgRJuDqT6rksDQNNPOFbPbgI=
=B7Xh
-----END PGP SIGNATURE-----
Merge tag 'firewire-updates-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394
Pull firewire updates from Takashi Sakamoto:
"This includes two changes for core functions, which affects all use
cases of this subsystem:
- Handle per-device interoperability quirks
Some devices have quirks affecting interoperability. To identify
such quirks at an early stages of device detection, the step for
reading the configuration ROM contents has been changed. As a side
effect, the entire detection process is now performed at the basic
transaction speed (S100), without a trial to probe higher
supported speeds.
With this change, the following devices should now work with fewer
issues:
- TASCAM FW-1884, FW-1804, and FW-1082
- MOTU Audio Express
- Safer removals of host card
There was a race condition between host card removal and handling
of bus reset events in the workqueue. This appears to be a long
standing issue, and recent changes to use more workqueues escalate
it.
To solve it, a new callback has been added to the 1394 OHCI PCI
driver to unregister the interrupt sources and wait for workqueue
completions when removing a card instance"
* tag 'firewire-updates-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
firewire: core: abort pending transactions at card removal
firewire: core: add WQ_UNBOUND to alloc_workqueue users
firewire: core: clear sources of hardware interrupt at card removal
firewire: core: code refactoring to find and pop transaction entry
firewire: core: code refactoring to remove transaction entry
firewire: core: use cleanup function to release cached configuration ROM
ALSA: firewire-tascam: reserve resources for transferred isochronous packets at S400
firewire: core: handle device quirk of TASCAM FW-1884/FW-1804/FW-1082
firewire: core: determine transaction speed after detecting quirks
firewire: core: code refactoring to compute transaction speed
firewire: core: handle device quirk of MOTU Audio Express
firewire: core: detect device quirk when reading configuration ROM
This commit is contained in:
commit
205f1a0d18
|
|
@ -86,8 +86,6 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
|
|||
*/
|
||||
#define DEFAULT_SPLIT_TIMEOUT (2 * 8000)
|
||||
|
||||
#define CANON_OUI 0x000085
|
||||
|
||||
static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
|
||||
{
|
||||
struct fw_descriptor *desc;
|
||||
|
|
@ -308,11 +306,9 @@ __must_hold(&card->lock)
|
|||
cpu_to_be32(local_id),
|
||||
};
|
||||
bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125));
|
||||
bool irm_is_1394_1995_only = false;
|
||||
bool keep_this_irm = false;
|
||||
struct fw_node *irm_node;
|
||||
struct fw_device *irm_device;
|
||||
int irm_node_id;
|
||||
int irm_node_id, irm_device_quirks = 0;
|
||||
int rcode;
|
||||
|
||||
lockdep_assert_held(&card->lock);
|
||||
|
|
@ -328,15 +324,12 @@ __must_hold(&card->lock)
|
|||
return BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF;
|
||||
}
|
||||
|
||||
// NOTE: It is likely that the quirk detection for IRM device has not done yet.
|
||||
irm_device = fw_node_get_device(irm_node);
|
||||
if (irm_device && irm_device->config_rom) {
|
||||
irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0;
|
||||
|
||||
// Canon MV5i works unreliably if it is not root node.
|
||||
keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI;
|
||||
}
|
||||
|
||||
if (irm_is_1394_1995_only && !keep_this_irm) {
|
||||
if (irm_device)
|
||||
irm_device_quirks = READ_ONCE(irm_device->quirks);
|
||||
if ((irm_device_quirks & FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY) &&
|
||||
!(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) {
|
||||
fw_notice(card, "IRM is not 1394a compliant, making local node (%02x) root\n",
|
||||
local_id);
|
||||
return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY;
|
||||
|
|
@ -373,7 +366,7 @@ __must_hold(&card->lock)
|
|||
return BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM;
|
||||
}
|
||||
default:
|
||||
if (!keep_this_irm) {
|
||||
if (!(irm_device_quirks & FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER)) {
|
||||
fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n",
|
||||
fw_rcode_string(rcode), local_id);
|
||||
return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY;
|
||||
|
|
@ -793,9 +786,13 @@ void fw_core_remove_card(struct fw_card *card)
|
|||
/* Switch off most of the card driver interface. */
|
||||
dummy_driver.free_iso_context = card->driver->free_iso_context;
|
||||
dummy_driver.stop_iso = card->driver->stop_iso;
|
||||
dummy_driver.disable = card->driver->disable;
|
||||
card->driver = &dummy_driver;
|
||||
|
||||
drain_workqueue(card->isoc_wq);
|
||||
drain_workqueue(card->async_wq);
|
||||
card->driver->disable(card);
|
||||
fw_cancel_pending_transactions(card);
|
||||
|
||||
scoped_guard(spinlock_irqsave, &card->lock)
|
||||
fw_destroy_nodes(card);
|
||||
|
|
|
|||
|
|
@ -542,8 +542,83 @@ static struct device_attribute fw_device_attributes[] = {
|
|||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static int read_rom(struct fw_device *device,
|
||||
int generation, int index, u32 *data)
|
||||
#define CANON_OUI 0x000085
|
||||
|
||||
static int detect_quirks_by_bus_information_block(const u32 *bus_information_block)
|
||||
{
|
||||
int quirks = 0;
|
||||
|
||||
if ((bus_information_block[2] & 0x000000f0) == 0)
|
||||
quirks |= FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY;
|
||||
|
||||
if ((bus_information_block[3] >> 8) == CANON_OUI)
|
||||
quirks |= FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER;
|
||||
|
||||
return quirks;
|
||||
}
|
||||
|
||||
struct entry_match {
|
||||
unsigned int index;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
static const struct entry_match motu_audio_express_matches[] = {
|
||||
{ 1, 0x030001f2 },
|
||||
{ 3, 0xd1000002 },
|
||||
{ 4, 0x8d000005 },
|
||||
{ 6, 0x120001f2 },
|
||||
{ 7, 0x13000033 },
|
||||
{ 8, 0x17104800 },
|
||||
};
|
||||
|
||||
static const struct entry_match tascam_fw_series_matches[] = {
|
||||
{ 1, 0x0300022e },
|
||||
{ 3, 0x8d000006 },
|
||||
{ 4, 0xd1000001 },
|
||||
{ 6, 0x1200022e },
|
||||
{ 8, 0xd4000004 },
|
||||
};
|
||||
|
||||
static int detect_quirks_by_root_directory(const u32 *root_directory, unsigned int length)
|
||||
{
|
||||
static const struct {
|
||||
enum fw_device_quirk quirk;
|
||||
const struct entry_match *matches;
|
||||
unsigned int match_count;
|
||||
} *entry, entries[] = {
|
||||
{
|
||||
.quirk = FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE,
|
||||
.matches = motu_audio_express_matches,
|
||||
.match_count = ARRAY_SIZE(motu_audio_express_matches),
|
||||
},
|
||||
{
|
||||
.quirk = FW_DEVICE_QUIRK_UNSTABLE_AT_S400,
|
||||
.matches = tascam_fw_series_matches,
|
||||
.match_count = ARRAY_SIZE(tascam_fw_series_matches),
|
||||
},
|
||||
};
|
||||
int quirks = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(entries); ++i) {
|
||||
int j;
|
||||
|
||||
entry = entries + i;
|
||||
for (j = 0; j < entry->match_count; ++j) {
|
||||
unsigned int index = entry->matches[j].index;
|
||||
unsigned int value = entry->matches[j].value;
|
||||
|
||||
if ((length < index) || (root_directory[index] != value))
|
||||
break;
|
||||
}
|
||||
if (j == entry->match_count)
|
||||
quirks |= entry->quirk;
|
||||
}
|
||||
|
||||
return quirks;
|
||||
}
|
||||
|
||||
static int read_rom(struct fw_device *device, int generation, int speed, int index, u32 *data)
|
||||
{
|
||||
u64 offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4;
|
||||
int i, rcode;
|
||||
|
|
@ -554,7 +629,7 @@ static int read_rom(struct fw_device *device,
|
|||
for (i = 10; i < 100; i += 10) {
|
||||
rcode = fw_run_transaction(device->card,
|
||||
TCODE_READ_QUADLET_REQUEST, device->node_id,
|
||||
generation, device->max_speed, offset, data, 4);
|
||||
generation, speed, offset, data, 4);
|
||||
if (rcode != RCODE_BUSY)
|
||||
break;
|
||||
msleep(i);
|
||||
|
|
@ -578,10 +653,11 @@ static int read_rom(struct fw_device *device,
|
|||
static int read_config_rom(struct fw_device *device, int generation)
|
||||
{
|
||||
struct fw_card *card = device->card;
|
||||
const u32 *old_rom, *new_rom;
|
||||
u32 *rom, *stack;
|
||||
const u32 *new_rom, *old_rom __free(kfree) = NULL;
|
||||
u32 *stack, *rom __free(kfree) = NULL;
|
||||
u32 sp, key;
|
||||
int i, end, length, ret;
|
||||
int i, end, length, ret, speed;
|
||||
int quirks;
|
||||
|
||||
rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
|
||||
sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
|
||||
|
|
@ -591,13 +667,13 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|||
stack = &rom[MAX_CONFIG_ROM_SIZE];
|
||||
memset(rom, 0, sizeof(*rom) * MAX_CONFIG_ROM_SIZE);
|
||||
|
||||
device->max_speed = SCODE_100;
|
||||
speed = SCODE_100;
|
||||
|
||||
/* First read the bus info block. */
|
||||
for (i = 0; i < 5; i++) {
|
||||
ret = read_rom(device, generation, i, &rom[i]);
|
||||
ret = read_rom(device, generation, speed, i, &rom[i]);
|
||||
if (ret != RCODE_COMPLETE)
|
||||
goto out;
|
||||
return ret;
|
||||
/*
|
||||
* As per IEEE1212 7.2, during initialization, devices can
|
||||
* reply with a 0 for the first quadlet of the config
|
||||
|
|
@ -606,39 +682,14 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|||
* harddisk). In that case we just fail, and the
|
||||
* retry mechanism will try again later.
|
||||
*/
|
||||
if (i == 0 && rom[i] == 0) {
|
||||
ret = RCODE_BUSY;
|
||||
goto out;
|
||||
}
|
||||
if (i == 0 && rom[i] == 0)
|
||||
return RCODE_BUSY;
|
||||
}
|
||||
|
||||
device->max_speed = device->node->max_speed;
|
||||
quirks = detect_quirks_by_bus_information_block(rom);
|
||||
|
||||
/*
|
||||
* Determine the speed of
|
||||
* - devices with link speed less than PHY speed,
|
||||
* - devices with 1394b PHY (unless only connected to 1394a PHYs),
|
||||
* - all devices if there are 1394b repeaters.
|
||||
* Note, we cannot use the bus info block's link_spd as starting point
|
||||
* because some buggy firmwares set it lower than necessary and because
|
||||
* 1394-1995 nodes do not have the field.
|
||||
*/
|
||||
if ((rom[2] & 0x7) < device->max_speed ||
|
||||
device->max_speed == SCODE_BETA ||
|
||||
card->beta_repeaters_present) {
|
||||
u32 dummy;
|
||||
|
||||
/* for S1600 and S3200 */
|
||||
if (device->max_speed == SCODE_BETA)
|
||||
device->max_speed = card->link_speed;
|
||||
|
||||
while (device->max_speed > SCODE_100) {
|
||||
if (read_rom(device, generation, 0, &dummy) ==
|
||||
RCODE_COMPLETE)
|
||||
break;
|
||||
device->max_speed--;
|
||||
}
|
||||
}
|
||||
// Just prevent from torn writing/reading.
|
||||
WRITE_ONCE(device->quirks, quirks);
|
||||
|
||||
/*
|
||||
* Now parse the config rom. The config rom is a recursive
|
||||
|
|
@ -659,15 +710,13 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|||
*/
|
||||
key = stack[--sp];
|
||||
i = key & 0xffffff;
|
||||
if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE)) {
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE))
|
||||
return -ENXIO;
|
||||
|
||||
/* Read header quadlet for the block to get the length. */
|
||||
ret = read_rom(device, generation, i, &rom[i]);
|
||||
ret = read_rom(device, generation, speed, i, &rom[i]);
|
||||
if (ret != RCODE_COMPLETE)
|
||||
goto out;
|
||||
return ret;
|
||||
end = i + (rom[i] >> 16) + 1;
|
||||
if (end > MAX_CONFIG_ROM_SIZE) {
|
||||
/*
|
||||
|
|
@ -689,9 +738,9 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|||
* it references another block, and push it in that case.
|
||||
*/
|
||||
for (; i < end; i++) {
|
||||
ret = read_rom(device, generation, i, &rom[i]);
|
||||
ret = read_rom(device, generation, speed, i, &rom[i]);
|
||||
if (ret != RCODE_COMPLETE)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
if ((key >> 30) != 3 || (rom[i] >> 30) < 2)
|
||||
continue;
|
||||
|
|
@ -716,27 +765,54 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|||
length = i;
|
||||
}
|
||||
|
||||
quirks |= detect_quirks_by_root_directory(rom + ROOT_DIR_OFFSET, length - ROOT_DIR_OFFSET);
|
||||
|
||||
// Just prevent from torn writing/reading.
|
||||
WRITE_ONCE(device->quirks, quirks);
|
||||
|
||||
if (unlikely(quirks & FW_DEVICE_QUIRK_UNSTABLE_AT_S400))
|
||||
speed = SCODE_200;
|
||||
else
|
||||
speed = device->node->max_speed;
|
||||
|
||||
// Determine the speed of
|
||||
// - devices with link speed less than PHY speed,
|
||||
// - devices with 1394b PHY (unless only connected to 1394a PHYs),
|
||||
// - all devices if there are 1394b repeaters.
|
||||
// Note, we cannot use the bus info block's link_spd as starting point because some buggy
|
||||
// firmwares set it lower than necessary and because 1394-1995 nodes do not have the field.
|
||||
if ((rom[2] & 0x7) < speed || speed == SCODE_BETA || card->beta_repeaters_present) {
|
||||
u32 dummy;
|
||||
|
||||
// for S1600 and S3200.
|
||||
if (speed == SCODE_BETA)
|
||||
speed = card->link_speed;
|
||||
|
||||
while (speed > SCODE_100) {
|
||||
if (read_rom(device, generation, speed, 0, &dummy) ==
|
||||
RCODE_COMPLETE)
|
||||
break;
|
||||
--speed;
|
||||
}
|
||||
}
|
||||
|
||||
device->max_speed = speed;
|
||||
|
||||
old_rom = device->config_rom;
|
||||
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
|
||||
if (new_rom == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (new_rom == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
scoped_guard(rwsem_write, &fw_device_rwsem) {
|
||||
device->config_rom = new_rom;
|
||||
device->config_rom_length = length;
|
||||
}
|
||||
|
||||
kfree(old_rom);
|
||||
ret = RCODE_COMPLETE;
|
||||
device->max_rec = rom[2] >> 12 & 0xf;
|
||||
device->cmc = rom[2] >> 30 & 1;
|
||||
device->irmc = rom[2] >> 31 & 1;
|
||||
out:
|
||||
kfree(rom);
|
||||
|
||||
return ret;
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
static void fw_unit_release(struct device *dev)
|
||||
|
|
@ -1122,10 +1198,10 @@ static void fw_device_init(struct work_struct *work)
|
|||
device->workfn = fw_device_shutdown;
|
||||
fw_schedule_device_work(device, SHUTDOWN_DELAY);
|
||||
} else {
|
||||
fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
|
||||
fw_notice(card, "created device %s: GUID %08x%08x, S%d00, quirks %08x\n",
|
||||
dev_name(&device->device),
|
||||
device->config_rom[3], device->config_rom[4],
|
||||
1 << device->max_speed);
|
||||
1 << device->max_speed, device->quirks);
|
||||
device->config_rom_retries = 0;
|
||||
|
||||
set_broadcast_channel(device, device->generation);
|
||||
|
|
@ -1160,7 +1236,7 @@ static int reread_config_rom(struct fw_device *device, int generation,
|
|||
int i, rcode;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
rcode = read_rom(device, generation, i, &q);
|
||||
rcode = read_rom(device, generation, device->max_speed, i, &q);
|
||||
if (rcode != RCODE_COMPLETE)
|
||||
return rcode;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,28 +44,68 @@ static int try_cancel_split_timeout(struct fw_transaction *t)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int close_transaction(struct fw_transaction *transaction, struct fw_card *card, int rcode,
|
||||
u32 response_tstamp)
|
||||
// card->transactions.lock must be acquired in advance.
|
||||
static void remove_transaction_entry(struct fw_card *card, struct fw_transaction *entry)
|
||||
{
|
||||
struct fw_transaction *t = NULL, *iter;
|
||||
list_del_init(&entry->link);
|
||||
card->transactions.tlabel_mask &= ~(1ULL << entry->tlabel);
|
||||
}
|
||||
|
||||
// Must be called without holding card->transactions.lock.
|
||||
void fw_cancel_pending_transactions(struct fw_card *card)
|
||||
{
|
||||
struct fw_transaction *t, *tmp;
|
||||
LIST_HEAD(pending_list);
|
||||
|
||||
// NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for
|
||||
// local destination never runs in any type of IRQ context.
|
||||
scoped_guard(spinlock_irqsave, &card->transactions.lock) {
|
||||
list_for_each_entry(iter, &card->transactions.list, link) {
|
||||
if (iter == transaction) {
|
||||
if (try_cancel_split_timeout(iter)) {
|
||||
list_del_init(&iter->link);
|
||||
card->transactions.tlabel_mask &= ~(1ULL << iter->tlabel);
|
||||
t = iter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
list_for_each_entry_safe(t, tmp, &card->transactions.list, link) {
|
||||
if (try_cancel_split_timeout(t))
|
||||
list_move(&t->link, &pending_list);
|
||||
}
|
||||
}
|
||||
|
||||
if (!t)
|
||||
return -ENOENT;
|
||||
list_for_each_entry_safe(t, tmp, &pending_list, link) {
|
||||
list_del(&t->link);
|
||||
|
||||
if (!t->with_tstamp) {
|
||||
t->callback.without_tstamp(card, RCODE_CANCELLED, NULL, 0,
|
||||
t->callback_data);
|
||||
} else {
|
||||
t->callback.with_tstamp(card, RCODE_CANCELLED, t->packet.timestamp, 0,
|
||||
NULL, 0, t->callback_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// card->transactions.lock must be acquired in advance.
|
||||
#define find_and_pop_transaction_entry(card, condition) \
|
||||
({ \
|
||||
struct fw_transaction *iter, *t = NULL; \
|
||||
list_for_each_entry(iter, &card->transactions.list, link) { \
|
||||
if (condition) { \
|
||||
t = iter; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (t && try_cancel_split_timeout(t)) \
|
||||
remove_transaction_entry(card, t); \
|
||||
t; \
|
||||
})
|
||||
|
||||
static int close_transaction(struct fw_transaction *transaction, struct fw_card *card, int rcode,
|
||||
u32 response_tstamp)
|
||||
{
|
||||
struct fw_transaction *t;
|
||||
|
||||
// NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for
|
||||
// local destination never runs in any type of IRQ context.
|
||||
scoped_guard(spinlock_irqsave, &card->transactions.lock) {
|
||||
t = find_and_pop_transaction_entry(card, iter == transaction);
|
||||
if (!t)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!t->with_tstamp) {
|
||||
t->callback.without_tstamp(card, rcode, NULL, 0, t->callback_data);
|
||||
|
|
@ -122,8 +162,7 @@ static void split_transaction_timeout_callback(struct timer_list *timer)
|
|||
scoped_guard(spinlock_irqsave, &card->transactions.lock) {
|
||||
if (list_empty(&t->link))
|
||||
return;
|
||||
list_del(&t->link);
|
||||
card->transactions.tlabel_mask &= ~(1ULL << t->tlabel);
|
||||
remove_transaction_entry(card, t);
|
||||
}
|
||||
|
||||
if (!t->with_tstamp) {
|
||||
|
|
@ -1097,7 +1136,7 @@ EXPORT_SYMBOL(fw_core_handle_request);
|
|||
|
||||
void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
|
||||
{
|
||||
struct fw_transaction *t = NULL, *iter;
|
||||
struct fw_transaction *t = NULL;
|
||||
u32 *data;
|
||||
size_t data_length;
|
||||
int tcode, tlabel, source, rcode;
|
||||
|
|
@ -1139,16 +1178,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
|
|||
// NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for
|
||||
// local destination never runs in any type of IRQ context.
|
||||
scoped_guard(spinlock_irqsave, &card->transactions.lock) {
|
||||
list_for_each_entry(iter, &card->transactions.list, link) {
|
||||
if (iter->node_id == source && iter->tlabel == tlabel) {
|
||||
if (try_cancel_split_timeout(iter)) {
|
||||
list_del_init(&iter->link);
|
||||
card->transactions.tlabel_mask &= ~(1ULL << iter->tlabel);
|
||||
t = iter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
t = find_and_pop_transaction_entry(card,
|
||||
iter->node_id == source && iter->tlabel == tlabel);
|
||||
}
|
||||
|
||||
trace_async_response_inbound((uintptr_t)t, card->index, p->generation, p->speed, p->ack,
|
||||
|
|
@ -1437,7 +1468,8 @@ static int __init fw_core_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM, 0);
|
||||
fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM | WQ_UNBOUND,
|
||||
0);
|
||||
if (!fw_workqueue)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ struct fw_card_driver {
|
|||
int (*enable)(struct fw_card *card,
|
||||
const __be32 *config_rom, size_t length);
|
||||
|
||||
// After returning the call, any function is no longer triggered to handle hardware event.
|
||||
void (*disable)(struct fw_card *card);
|
||||
|
||||
int (*read_phy_reg)(struct fw_card *card, int address);
|
||||
int (*update_phy_reg)(struct fw_card *card, int address,
|
||||
int clear_bits, int set_bits);
|
||||
|
|
@ -284,6 +287,8 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
|
|||
void fw_request_get(struct fw_request *request);
|
||||
void fw_request_put(struct fw_request *request);
|
||||
|
||||
void fw_cancel_pending_transactions(struct fw_card *card);
|
||||
|
||||
// Convert the value of IEEE 1394 CYCLE_TIME register to the format of timeStamp field in
|
||||
// descriptors of 1394 OHCI.
|
||||
static inline u32 cycle_time_to_ohci_tstamp(u32 tstamp)
|
||||
|
|
|
|||
|
|
@ -1319,6 +1319,14 @@ static void at_context_flush(struct at_context *ctx)
|
|||
enable_work(&ctx->work);
|
||||
}
|
||||
|
||||
static int find_fw_device(struct device *dev, const void *data)
|
||||
{
|
||||
struct fw_device *device = fw_device(dev);
|
||||
const u32 *params = data;
|
||||
|
||||
return (device->generation == params[0]) && (device->node_id == params[1]);
|
||||
}
|
||||
|
||||
static int handle_at_packet(struct context *context,
|
||||
struct descriptor *d,
|
||||
struct descriptor *last)
|
||||
|
|
@ -1390,6 +1398,27 @@ static int handle_at_packet(struct context *context,
|
|||
fallthrough;
|
||||
|
||||
default:
|
||||
if (unlikely(evt == 0x10)) {
|
||||
u32 params[2] = {
|
||||
packet->generation,
|
||||
async_header_get_destination(packet->header),
|
||||
};
|
||||
struct device *dev;
|
||||
|
||||
fw_card_get(&ohci->card);
|
||||
dev = device_find_child(ohci->card.device, (const void *)params, find_fw_device);
|
||||
fw_card_put(&ohci->card);
|
||||
if (dev) {
|
||||
struct fw_device *device = fw_device(dev);
|
||||
int quirks = READ_ONCE(device->quirks);
|
||||
|
||||
put_device(dev);
|
||||
if (quirks & FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE) {
|
||||
packet->ack = ACK_PENDING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
packet->ack = RCODE_SEND_ERROR;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2379,6 +2408,41 @@ static int ohci_enable(struct fw_card *card,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ohci_disable(struct fw_card *card)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(card->device);
|
||||
struct fw_ohci *ohci = pci_get_drvdata(pdev);
|
||||
int i, irq = pci_irq_vector(pdev, 0);
|
||||
|
||||
// If the removal is happening from the suspend state, LPS won't be enabled and host
|
||||
// registers (eg., IntMaskClear) won't be accessible.
|
||||
if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS))
|
||||
return;
|
||||
|
||||
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
|
||||
flush_writes(ohci);
|
||||
|
||||
if (irq >= 0)
|
||||
synchronize_irq(irq);
|
||||
|
||||
flush_work(&ohci->ar_request_ctx.work);
|
||||
flush_work(&ohci->ar_response_ctx.work);
|
||||
flush_work(&ohci->at_request_ctx.work);
|
||||
flush_work(&ohci->at_response_ctx.work);
|
||||
|
||||
for (i = 0; i < ohci->n_ir; ++i) {
|
||||
if (!(ohci->ir_context_mask & BIT(i)))
|
||||
flush_work(&ohci->ir_context_list[i].base.work);
|
||||
}
|
||||
for (i = 0; i < ohci->n_it; ++i) {
|
||||
if (!(ohci->it_context_mask & BIT(i)))
|
||||
flush_work(&ohci->it_context_list[i].base.work);
|
||||
}
|
||||
|
||||
at_context_flush(&ohci->at_request_ctx);
|
||||
at_context_flush(&ohci->at_response_ctx);
|
||||
}
|
||||
|
||||
static int ohci_set_config_rom(struct fw_card *card,
|
||||
const __be32 *config_rom, size_t length)
|
||||
{
|
||||
|
|
@ -3413,6 +3477,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base)
|
|||
|
||||
static const struct fw_card_driver ohci_driver = {
|
||||
.enable = ohci_enable,
|
||||
.disable = ohci_disable,
|
||||
.read_phy_reg = ohci_read_phy_reg,
|
||||
.update_phy_reg = ohci_update_phy_reg,
|
||||
.set_config_rom = ohci_set_config_rom,
|
||||
|
|
@ -3652,21 +3717,8 @@ static void pci_remove(struct pci_dev *dev)
|
|||
struct fw_ohci *ohci = pci_get_drvdata(dev);
|
||||
int irq;
|
||||
|
||||
/*
|
||||
* If the removal is happening from the suspend state, LPS won't be
|
||||
* enabled and host registers (eg., IntMaskClear) won't be accessible.
|
||||
*/
|
||||
if (reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS) {
|
||||
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
|
||||
flush_writes(ohci);
|
||||
}
|
||||
fw_core_remove_card(&ohci->card);
|
||||
|
||||
/*
|
||||
* FIXME: Fail all pending packets here, now that the upper
|
||||
* layers can't queue any more.
|
||||
*/
|
||||
|
||||
software_reset(ohci);
|
||||
|
||||
irq = pci_irq_vector(dev, 0);
|
||||
|
|
|
|||
|
|
@ -170,6 +170,20 @@ struct fw_attribute_group {
|
|||
struct attribute *attrs[13];
|
||||
};
|
||||
|
||||
enum fw_device_quirk {
|
||||
// See afa1282a35d3 ("firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder").
|
||||
FW_DEVICE_QUIRK_IRM_IS_1394_1995_ONLY = BIT(0),
|
||||
|
||||
// See a509e43ff338 ("firewire: core: fix unstable I/O with Canon camcorder").
|
||||
FW_DEVICE_QUIRK_IRM_IGNORES_BUS_MANAGER = BIT(1),
|
||||
|
||||
// MOTU Audio Express transfers acknowledge packet with 0x10 for pending state.
|
||||
FW_DEVICE_QUIRK_ACK_PACKET_WITH_INVALID_PENDING_CODE = BIT(2),
|
||||
|
||||
// TASCAM FW-1082/FW-1804/FW-1884 often freezes when receiving S400 packets.
|
||||
FW_DEVICE_QUIRK_UNSTABLE_AT_S400 = BIT(3),
|
||||
};
|
||||
|
||||
enum fw_device_state {
|
||||
FW_DEVICE_INITIALIZING,
|
||||
FW_DEVICE_RUNNING,
|
||||
|
|
@ -203,6 +217,9 @@ struct fw_device {
|
|||
struct fw_card *card;
|
||||
struct device device;
|
||||
|
||||
// A set of enum fw_device_quirk.
|
||||
int quirks;
|
||||
|
||||
struct mutex client_list_mutex;
|
||||
struct list_head client_list;
|
||||
|
||||
|
|
|
|||
|
|
@ -282,20 +282,22 @@ static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
|
|||
struct amdtp_stream *stream)
|
||||
{
|
||||
struct fw_iso_resources *resources;
|
||||
int speed;
|
||||
int err;
|
||||
|
||||
if (stream == &tscm->tx_stream)
|
||||
if (stream == &tscm->tx_stream) {
|
||||
resources = &tscm->tx_resources;
|
||||
else
|
||||
speed = fw_parent_device(tscm->unit)->max_speed;
|
||||
} else {
|
||||
resources = &tscm->rx_resources;
|
||||
speed = SCODE_400;
|
||||
}
|
||||
|
||||
err = amdtp_tscm_set_parameters(stream, rate);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return fw_iso_resources_allocate(resources,
|
||||
amdtp_stream_get_max_payload(stream),
|
||||
fw_parent_device(tscm->unit)->max_speed);
|
||||
return fw_iso_resources_allocate(resources, amdtp_stream_get_max_payload(stream), speed);
|
||||
}
|
||||
|
||||
static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s)
|
||||
|
|
@ -455,7 +457,6 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
|
|||
}
|
||||
|
||||
if (!amdtp_stream_running(&tscm->rx_stream)) {
|
||||
int spd = fw_parent_device(tscm->unit)->max_speed;
|
||||
unsigned int tx_init_skip_cycles;
|
||||
|
||||
err = set_stream_formats(tscm, rate);
|
||||
|
|
@ -466,13 +467,13 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
|
|||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream,
|
||||
tscm->rx_resources.channel, spd);
|
||||
err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream, tscm->rx_resources.channel,
|
||||
fw_parent_device(tscm->unit)->max_speed);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream,
|
||||
tscm->tx_resources.channel, spd);
|
||||
err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream, tscm->tx_resources.channel,
|
||||
SCODE_400);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue