Merge tag 'firewire-updates-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394

Pull firewire updates from Takashi Sakamoto:
 "This update includes the following changes:

   - Removal of the deprecated debug parameter from firewire-ohci module

   - Replacement of the module-local workqueue in 1394 OHCI PCI driver
     with a companion IRQ thread

   - Refactoring of bus management code

   - Additional minor code cleanup

  The existing tracepoints serve as an alternative to the removed debug
  parameter. The use of IRQ thread is experimental, as it handles 1394
  OHCI SelfIDComplete event only. It may be replaced in the future
  releases with another approach; e.g. by providing workqueue from core
  functionality"

* tag 'firewire-updates-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394: (43 commits)
  firewire: core: fix undefined reference error in ARM EABI
  Revert "firewire: core: disable bus management work temporarily during updating topology"
  Revert "firewire: core: shrink critical section of fw_card spinlock in bm_work"
  firewire: core: suppress overflow warning when computing jiffies from isochronous cycle
  firewire: core: minor code refactoring to delete useless local variable
  firewire: core; eliminate pick_me goto label
  firewire: core: code refactoring to split contention procedure for bus manager
  firewire: core: code refactoring for the case of generation mismatch
  firewire: core: use switch statement to evaluate transaction result to CSR_BUS_MANAGER_ID
  firewire: core: remove useless generation check
  firewire: core: use struct_size and flex_array_size in ioctl_add_descriptor
  firewire: core: shrink critical section of fw_card spinlock in bm_work
  firewire: core: disable bus management work temporarily during updating topology
  firewire: core: schedule bm_work item outside of spin lock
  firewire: core: annotate fw_destroy_nodes with must-hold-lock
  firewire: core: use spin lock specific to timer for split transaction
  firewire: core: use spin lock specific to transaction
  firewire: core: use spin lock specific to topology map
  firewire: core: maintain phy packet receivers locally in cdev layer
  firewire: core: use scoped_guard() to manage critical section to update topology
  ...
This commit is contained in:
Linus Torvalds
2025-10-01 12:52:43 -07:00
8 changed files with 522 additions and 631 deletions
File diff suppressed because it is too large Load Diff
+25 -11
View File
@@ -47,6 +47,9 @@
#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW 5
#define FW_CDEV_VERSION_EVENT_ASYNC_TSTAMP 6
static DEFINE_SPINLOCK(phy_receiver_list_lock);
static LIST_HEAD(phy_receiver_list);
struct client {
u32 version;
struct fw_device *device;
@@ -937,11 +940,12 @@ static int ioctl_add_descriptor(struct client *client, union ioctl_arg *arg)
if (a->length > 256)
return -EINVAL;
r = kmalloc(sizeof(*r) + a->length * 4, GFP_KERNEL);
r = kmalloc(struct_size(r, data, a->length), GFP_KERNEL);
if (r == NULL)
return -ENOMEM;
if (copy_from_user(r->data, u64_to_uptr(a->data), a->length * 4)) {
if (copy_from_user(r->data, u64_to_uptr(a->data),
flex_array_size(r, data, a->length))) {
ret = -EFAULT;
goto failed;
}
@@ -1324,8 +1328,8 @@ static void iso_resource_work(struct work_struct *work)
todo = r->todo;
// Allow 1000ms grace period for other reallocations.
if (todo == ISO_RES_ALLOC &&
time_before64(get_jiffies_64(), client->device->card->reset_jiffies + HZ)) {
schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
time_is_after_jiffies64(client->device->card->reset_jiffies + secs_to_jiffies(1))) {
schedule_iso_resource(r, msecs_to_jiffies(333));
skip = true;
} else {
// We could be called twice within the same generation.
@@ -1669,15 +1673,16 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
static int ioctl_receive_phy_packets(struct client *client, union ioctl_arg *arg)
{
struct fw_cdev_receive_phy_packets *a = &arg->receive_phy_packets;
struct fw_card *card = client->device->card;
/* Access policy: Allow this ioctl only on local nodes' device files. */
if (!client->device->is_local)
return -ENOSYS;
guard(spinlock_irq)(&card->lock);
// NOTE: This can be without irq when we can guarantee that __fw_send_request() for local
// destination never runs in any type of IRQ context.
scoped_guard(spinlock_irq, &phy_receiver_list_lock)
list_move_tail(&client->phy_receiver_link, &phy_receiver_list);
list_move_tail(&client->phy_receiver_link, &card->phy_receiver_list);
client->phy_receiver_closure = a->closure;
return 0;
@@ -1687,10 +1692,17 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p)
{
struct client *client;
guard(spinlock_irqsave)(&card->lock);
// 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.
guard(spinlock_irqsave)(&phy_receiver_list_lock);
list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) {
struct inbound_phy_packet_event *e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
list_for_each_entry(client, &phy_receiver_list, phy_receiver_link) {
struct inbound_phy_packet_event *e;
if (client->device->card != card)
continue;
e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
if (e == NULL)
break;
@@ -1857,7 +1869,9 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
struct client_resource *resource;
unsigned long index;
scoped_guard(spinlock_irq, &client->device->card->lock)
// NOTE: This can be without irq when we can guarantee that __fw_send_request() for local
// destination never runs in any type of IRQ context.
scoped_guard(spinlock_irq, &phy_receiver_list_lock)
list_del(&client->phy_receiver_link);
scoped_guard(mutex, &client->device->client_list_mutex)
+13 -14
View File
@@ -847,16 +847,15 @@ static void fw_schedule_device_work(struct fw_device *device,
*/
#define MAX_RETRIES 10
#define RETRY_DELAY (3 * HZ)
#define INITIAL_DELAY (HZ / 2)
#define SHUTDOWN_DELAY (2 * HZ)
#define RETRY_DELAY secs_to_jiffies(3)
#define INITIAL_DELAY msecs_to_jiffies(500)
#define SHUTDOWN_DELAY secs_to_jiffies(2)
static void fw_device_shutdown(struct work_struct *work)
{
struct fw_device *device = from_work(device, work, work.work);
if (time_before64(get_jiffies_64(),
device->card->reset_jiffies + SHUTDOWN_DELAY)
if (time_is_after_jiffies64(device->card->reset_jiffies + SHUTDOWN_DELAY)
&& !list_empty(&device->card->link)) {
fw_schedule_device_work(device, SHUTDOWN_DELAY);
return;
@@ -887,7 +886,7 @@ static void fw_device_release(struct device *dev)
* bus manager work looks at this node.
*/
scoped_guard(spinlock_irqsave, &card->lock)
device->node->data = NULL;
fw_node_set_device(device->node, NULL);
fw_node_put(device->node);
kfree(device->config_rom);
@@ -1007,7 +1006,7 @@ static void fw_device_init(struct work_struct *work)
int ret;
/*
* All failure paths here set node->data to NULL, so that we
* All failure paths here call fw_node_set_device(node, NULL), so that we
* don't try to do device_for_each_child() on a kfree()'d
* device.
*/
@@ -1051,9 +1050,9 @@ static void fw_device_init(struct work_struct *work)
struct fw_node *obsolete_node = reused->node;
device->node = obsolete_node;
device->node->data = device;
fw_node_set_device(device->node, device);
reused->node = current_node;
reused->node->data = reused;
fw_node_set_device(reused->node, reused);
reused->max_speed = device->max_speed;
reused->node_id = current_node->node_id;
@@ -1292,7 +1291,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
* FW_NODE_UPDATED callbacks can update the node_id
* and generation for the device.
*/
node->data = device;
fw_node_set_device(node, device);
/*
* Many devices are slow to respond after bus resets,
@@ -1307,7 +1306,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
case FW_NODE_INITIATED_RESET:
case FW_NODE_LINK_ON:
device = node->data;
device = fw_node_get_device(node);
if (device == NULL)
goto create;
@@ -1324,7 +1323,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
break;
case FW_NODE_UPDATED:
device = node->data;
device = fw_node_get_device(node);
if (device == NULL)
break;
@@ -1339,7 +1338,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
case FW_NODE_DESTROYED:
case FW_NODE_LINK_OFF:
if (!node->data)
if (!fw_node_get_device(node))
break;
/*
@@ -1354,7 +1353,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
* the device in shutdown state to have that code fail
* to create the device.
*/
device = node->data;
device = fw_node_get_device(node);
if (atomic_xchg(&device->state,
FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
device->workfn = fw_device_shutdown;
+46 -43
View File
@@ -241,7 +241,7 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
// If PHYs report different gap counts, set an invalid count which will force a gap
// count reconfiguration and a reset.
if (phy_packet_self_id_zero_get_gap_count(self_id_sequence[0]) != gap_count)
gap_count = 0;
gap_count = GAP_COUNT_MISMATCHED;
update_hop_count(node);
@@ -325,9 +325,11 @@ static void report_found_node(struct fw_card *card,
card->bm_retries = 0;
}
/* Must be called with card->lock held */
void fw_destroy_nodes(struct fw_card *card)
__must_hold(&card->lock)
{
lockdep_assert_held(&card->lock);
card->color++;
if (card->local_node != NULL)
for_each_fw_node(card, card->local_node, report_lost_node);
@@ -435,20 +437,22 @@ static void update_tree(struct fw_card *card, struct fw_node *root)
}
}
static void update_topology_map(struct fw_card *card,
u32 *self_ids, int self_id_count)
static void update_topology_map(__be32 *buffer, size_t buffer_size, int root_node_id,
const u32 *self_ids, int self_id_count)
{
int node_count = (card->root_node->node_id & 0x3f) + 1;
__be32 *map = card->topology_map;
__be32 *map = buffer;
int node_count = (root_node_id & 0x3f) + 1;
memset(map, 0, buffer_size);
*map++ = cpu_to_be32((self_id_count + 2) << 16);
*map++ = cpu_to_be32(be32_to_cpu(card->topology_map[1]) + 1);
*map++ = cpu_to_be32(be32_to_cpu(buffer[1]) + 1);
*map++ = cpu_to_be32((node_count << 16) | self_id_count);
while (self_id_count--)
*map++ = cpu_to_be32p(self_ids++);
fw_compute_block_crc(card->topology_map);
fw_compute_block_crc(buffer);
}
void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
@@ -458,46 +462,45 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
trace_bus_reset_handle(card->index, generation, node_id, bm_abdicate, self_ids, self_id_count);
guard(spinlock_irqsave)(&card->lock);
scoped_guard(spinlock, &card->lock) {
// If the selfID buffer is not the immediate successor of the
// previously processed one, we cannot reliably compare the
// old and new topologies.
if (!is_next_generation(generation, card->generation) && card->local_node != NULL) {
fw_destroy_nodes(card);
card->bm_retries = 0;
}
card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated;
card->node_id = node_id;
// Update node_id before generation to prevent anybody from using
// a stale node_id together with a current generation.
smp_wmb();
card->generation = generation;
card->reset_jiffies = get_jiffies_64();
card->bm_node_id = 0xffff;
card->bm_abdicate = bm_abdicate;
/*
* If the selfID buffer is not the immediate successor of the
* previously processed one, we cannot reliably compare the
* old and new topologies.
*/
if (!is_next_generation(generation, card->generation) &&
card->local_node != NULL) {
fw_destroy_nodes(card);
card->bm_retries = 0;
local_node = build_tree(card, self_ids, self_id_count, generation);
card->color++;
if (local_node == NULL) {
fw_err(card, "topology build failed\n");
// FIXME: We need to issue a bus reset in this case.
} else if (card->local_node == NULL) {
card->local_node = local_node;
for_each_fw_node(card, local_node, report_found_node);
} else {
update_tree(card, local_node);
}
}
card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated;
card->node_id = node_id;
/*
* Update node_id before generation to prevent anybody from using
* a stale node_id together with a current generation.
*/
smp_wmb();
card->generation = generation;
card->reset_jiffies = get_jiffies_64();
card->bm_node_id = 0xffff;
card->bm_abdicate = bm_abdicate;
fw_schedule_bm_work(card, 0);
local_node = build_tree(card, self_ids, self_id_count, generation);
update_topology_map(card, self_ids, self_id_count);
card->color++;
if (local_node == NULL) {
fw_err(card, "topology build failed\n");
/* FIXME: We need to issue a bus reset in this case. */
} else if (card->local_node == NULL) {
card->local_node = local_node;
for_each_fw_node(card, local_node, report_found_node);
} else {
update_tree(card, local_node);
// Just used by transaction layer.
scoped_guard(spinlock, &card->topology_map.lock) {
update_topology_map(card->topology_map.buffer, sizeof(card->topology_map.buffer),
card->root_node->node_id, self_ids, self_id_count);
}
}
EXPORT_SYMBOL(fw_core_handle_bus_reset);
+84 -46
View File
@@ -49,12 +49,14 @@ static int close_transaction(struct fw_transaction *transaction, struct fw_card
{
struct fw_transaction *t = NULL, *iter;
scoped_guard(spinlock_irqsave, &card->lock) {
list_for_each_entry(iter, &card->transaction_list, link) {
// 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->tlabel_mask &= ~(1ULL << iter->tlabel);
card->transactions.tlabel_mask &= ~(1ULL << iter->tlabel);
t = iter;
}
break;
@@ -117,11 +119,11 @@ static void split_transaction_timeout_callback(struct timer_list *timer)
struct fw_transaction *t = timer_container_of(t, timer, split_timeout_timer);
struct fw_card *card = t->card;
scoped_guard(spinlock_irqsave, &card->lock) {
scoped_guard(spinlock_irqsave, &card->transactions.lock) {
if (list_empty(&t->link))
return;
list_del(&t->link);
card->tlabel_mask &= ~(1ULL << t->tlabel);
card->transactions.tlabel_mask &= ~(1ULL << t->tlabel);
}
if (!t->with_tstamp) {
@@ -135,14 +137,18 @@ static void split_transaction_timeout_callback(struct timer_list *timer)
static void start_split_transaction_timeout(struct fw_transaction *t,
struct fw_card *card)
{
guard(spinlock_irqsave)(&card->lock);
unsigned long delta;
if (list_empty(&t->link) || WARN_ON(t->is_split_transaction))
return;
t->is_split_transaction = true;
mod_timer(&t->split_timeout_timer,
jiffies + card->split_timeout_jiffies);
// 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->split_timeout.lock)
delta = card->split_timeout.jiffies;
mod_timer(&t->split_timeout_timer, jiffies + delta);
}
static u32 compute_split_timeout_timestamp(struct fw_card *card, u32 request_timestamp);
@@ -162,8 +168,12 @@ static void transmit_complete_callback(struct fw_packet *packet,
break;
case ACK_PENDING:
{
t->split_timeout_cycle =
compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff;
// 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->split_timeout.lock) {
t->split_timeout_cycle =
compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff;
}
start_split_transaction_timeout(t, card);
break;
}
@@ -259,18 +269,21 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
}
static int allocate_tlabel(struct fw_card *card)
__must_hold(&card->transactions_lock)
{
int tlabel;
tlabel = card->current_tlabel;
while (card->tlabel_mask & (1ULL << tlabel)) {
lockdep_assert_held(&card->transactions.lock);
tlabel = card->transactions.current_tlabel;
while (card->transactions.tlabel_mask & (1ULL << tlabel)) {
tlabel = (tlabel + 1) & 0x3f;
if (tlabel == card->current_tlabel)
if (tlabel == card->transactions.current_tlabel)
return -EBUSY;
}
card->current_tlabel = (tlabel + 1) & 0x3f;
card->tlabel_mask |= 1ULL << tlabel;
card->transactions.current_tlabel = (tlabel + 1) & 0x3f;
card->transactions.tlabel_mask |= 1ULL << tlabel;
return tlabel;
}
@@ -331,7 +344,6 @@ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode
void *payload, size_t length, union fw_transaction_callback callback,
bool with_tstamp, void *callback_data)
{
unsigned long flags;
int tlabel;
/*
@@ -339,11 +351,11 @@ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode
* the list while holding the card spinlock.
*/
spin_lock_irqsave(&card->lock, flags);
tlabel = allocate_tlabel(card);
// 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)
tlabel = allocate_tlabel(card);
if (tlabel < 0) {
spin_unlock_irqrestore(&card->lock, flags);
if (!with_tstamp) {
callback.without_tstamp(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
} else {
@@ -368,15 +380,22 @@ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode
t->callback = callback;
t->with_tstamp = with_tstamp;
t->callback_data = callback_data;
fw_fill_request(&t->packet, tcode, t->tlabel, destination_id, card->node_id, generation,
speed, offset, payload, length);
t->packet.callback = transmit_complete_callback;
list_add_tail(&t->link, &card->transaction_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->lock) {
// The node_id field of fw_card can be updated when handling SelfIDComplete.
fw_fill_request(&t->packet, tcode, t->tlabel, destination_id, card->node_id,
generation, speed, offset, payload, length);
}
spin_unlock_irqrestore(&card->lock, flags);
// 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_add_tail(&t->link, &card->transactions.list);
// Safe with no lock, since the index field of fw_card is immutable once assigned.
trace_async_request_outbound_initiate((uintptr_t)t, card->index, generation, speed,
t->packet.header, payload,
tcode_is_read_request(tcode) ? 0 : length / 4);
@@ -458,7 +477,7 @@ static struct fw_packet phy_config_packet = {
void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count)
{
long timeout = DIV_ROUND_UP(HZ, 10);
long timeout = msecs_to_jiffies(100);
u32 data = 0;
phy_packet_set_packet_identifier(&data, PHY_PACKET_PACKET_IDENTIFIER_PHY_CONFIG);
@@ -779,11 +798,14 @@ EXPORT_SYMBOL(fw_fill_response);
static u32 compute_split_timeout_timestamp(struct fw_card *card,
u32 request_timestamp)
__must_hold(&card->split_timeout.lock)
{
unsigned int cycles;
u32 timestamp;
cycles = card->split_timeout_cycles;
lockdep_assert_held(&card->split_timeout.lock);
cycles = card->split_timeout.cycles;
cycles += request_timestamp & 0x1fff;
timestamp = request_timestamp & ~0x1fff;
@@ -834,9 +856,12 @@ static struct fw_request *allocate_request(struct fw_card *card,
return NULL;
kref_init(&request->kref);
// 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->split_timeout.lock)
request->response.timestamp = compute_split_timeout_timestamp(card, p->timestamp);
request->response.speed = p->speed;
request->response.timestamp =
compute_split_timeout_timestamp(card, p->timestamp);
request->response.generation = p->generation;
request->response.ack = 0;
request->response.callback = free_response_callback;
@@ -1111,12 +1136,14 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
break;
}
scoped_guard(spinlock_irqsave, &card->lock) {
list_for_each_entry(iter, &card->transaction_list, link) {
// 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->tlabel_mask &= ~(1ULL << iter->tlabel);
card->transactions.tlabel_mask &= ~(1ULL << iter->tlabel);
t = iter;
}
break;
@@ -1196,7 +1223,11 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
}
start = (offset - topology_map_region.start) / 4;
memcpy(payload, &card->topology_map[start], length);
// 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->topology_map.lock)
memcpy(payload, &card->topology_map.buffer[start], length);
fw_send_response(card, request, RCODE_COMPLETE);
}
@@ -1211,16 +1242,17 @@ static const struct fw_address_region registers_region =
.end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };
static void update_split_timeout(struct fw_card *card)
__must_hold(&card->split_timeout.lock)
{
unsigned int cycles;
cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19);
cycles = card->split_timeout.hi * 8000 + (card->split_timeout.lo >> 19);
/* minimum per IEEE 1394, maximum which doesn't overflow OHCI */
cycles = clamp(cycles, 800u, 3u * 8000u);
card->split_timeout_cycles = cycles;
card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000);
card->split_timeout.cycles = cycles;
card->split_timeout.jiffies = isoc_cycles_to_jiffies(cycles);
}
static void handle_registers(struct fw_card *card, struct fw_request *request,
@@ -1270,12 +1302,15 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
case CSR_SPLIT_TIMEOUT_HI:
if (tcode == TCODE_READ_QUADLET_REQUEST) {
*data = cpu_to_be32(card->split_timeout_hi);
*data = cpu_to_be32(card->split_timeout.hi);
} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
guard(spinlock_irqsave)(&card->lock);
card->split_timeout_hi = be32_to_cpu(*data) & 7;
update_split_timeout(card);
// 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->split_timeout.lock) {
card->split_timeout.hi = be32_to_cpu(*data) & 7;
update_split_timeout(card);
}
} else {
rcode = RCODE_TYPE_ERROR;
}
@@ -1283,12 +1318,15 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
case CSR_SPLIT_TIMEOUT_LO:
if (tcode == TCODE_READ_QUADLET_REQUEST) {
*data = cpu_to_be32(card->split_timeout_lo);
*data = cpu_to_be32(card->split_timeout.lo);
} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
guard(spinlock_irqsave)(&card->lock);
card->split_timeout_lo = be32_to_cpu(*data) & 0xfff80000;
update_split_timeout(card);
// 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->split_timeout.lock) {
card->split_timeout.lo = be32_to_cpu(*data) & 0xfff80000;
update_split_timeout(card);
}
} else {
rcode = RCODE_TYPE_ERROR;
}
+20 -2
View File
@@ -27,6 +27,11 @@ struct fw_packet;
/* -card */
// This is the arbitrary value we use to indicate a mismatched gap count.
#define GAP_COUNT_MISMATCHED 0
#define isoc_cycles_to_jiffies(cycles) usecs_to_jiffies((u32)div_u64((u64)cycles * USEC_PER_SEC, 8000))
extern __printf(2, 3)
void fw_err(const struct fw_card *card, const char *fmt, ...);
extern __printf(2, 3)
@@ -167,6 +172,9 @@ static inline void fw_iso_context_init_work(struct fw_iso_context *ctx, work_fun
/* -topology */
// The initial value of BUS_MANAGER_ID register, to express nothing registered.
#define BUS_MANAGER_ID_NOT_REGISTERED 0x3f
enum {
FW_NODE_CREATED,
FW_NODE_UPDATED,
@@ -194,8 +202,8 @@ struct fw_node {
/* For serializing node topology into a list. */
struct list_head link;
/* Upper layer specific data. */
void *data;
// The device when already associated, else NULL.
struct fw_device *device;
struct fw_node *ports[] __counted_by(port_count);
};
@@ -219,6 +227,16 @@ static inline void fw_node_put(struct fw_node *node)
kref_put(&node->kref, release_node);
}
static inline struct fw_device *fw_node_get_device(struct fw_node *node)
{
return node->device;
}
static inline void fw_node_set_device(struct fw_node *node, struct fw_device *device)
{
node->device = device;
}
void fw_core_handle_bus_reset(struct fw_card *card, int node_id,
int generation, int self_id_count, u32 *self_ids, bool bm_abdicate);
void fw_destroy_nodes(struct fw_card *card);
+47 -269
View File
File diff suppressed because it is too large Load Diff
+21 -12
View File
@@ -88,23 +88,30 @@ struct fw_card {
int node_id;
int generation;
int current_tlabel;
u64 tlabel_mask;
struct list_head transaction_list;
u64 reset_jiffies;
u32 split_timeout_hi;
u32 split_timeout_lo;
unsigned int split_timeout_cycles;
unsigned int split_timeout_jiffies;
struct {
int current_tlabel;
u64 tlabel_mask;
struct list_head list;
spinlock_t lock;
} transactions;
struct {
u32 hi;
u32 lo;
unsigned int cycles;
unsigned int jiffies;
spinlock_t lock;
} split_timeout;
unsigned long long guid;
unsigned max_receive;
int link_speed;
int config_rom_generation;
spinlock_t lock; /* Take this lock when handling the lists in
* this struct. */
spinlock_t lock;
struct fw_node *local_node;
struct fw_node *root_node;
struct fw_node *irm_node;
@@ -115,8 +122,6 @@ struct fw_card {
int index;
struct list_head link;
struct list_head phy_receiver_list;
struct delayed_work br_work; /* bus reset job */
bool br_short;
@@ -131,7 +136,11 @@ struct fw_card {
bool broadcast_channel_allocated;
u32 broadcast_channel;
__be32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
struct {
__be32 buffer[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
spinlock_t lock;
} topology_map;
__be32 maint_utility_register;