mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
firewire: allocate broadcast channel in hardware
On OHCI 1.1 controllers, let the hardware allocate the broadcast channel automatically. This removes a theoretical race condition directly after a bus reset where it could be possible to read the channel allocation register with channel 31 still being unallocated. Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
This commit is contained in:
parent
7e0e314f19
commit
e91b2787d0
@ -208,13 +208,19 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
|
||||
{
|
||||
int channel, bandwidth = 0;
|
||||
|
||||
fw_iso_resource_manage(card, generation, 1ULL << 31, &channel,
|
||||
&bandwidth, true, card->bm_transaction_data);
|
||||
if (channel == 31) {
|
||||
if (!card->broadcast_channel_allocated) {
|
||||
fw_iso_resource_manage(card, generation, 1ULL << 31,
|
||||
&channel, &bandwidth, true,
|
||||
card->bm_transaction_data);
|
||||
if (channel != 31) {
|
||||
fw_notify("failed to allocate broadcast channel\n");
|
||||
return;
|
||||
}
|
||||
card->broadcast_channel_allocated = true;
|
||||
device_for_each_child(card->device, (void *)(long)generation,
|
||||
fw_device_set_broadcast_channel);
|
||||
}
|
||||
|
||||
device_for_each_child(card->device, (void *)(long)generation,
|
||||
fw_device_set_broadcast_channel);
|
||||
}
|
||||
|
||||
static const char gap_count_table[] = {
|
||||
|
@ -543,7 +543,8 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
|
||||
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
|
||||
card->broadcast_channel_allocated = false;
|
||||
card->broadcast_channel_allocated = (card->driver->get_features(card) &
|
||||
FEATURE_CHANNEL_31_ALLOCATED) != 0;
|
||||
card->node_id = node_id;
|
||||
/*
|
||||
* Update node_id before generation to prevent anybody from using
|
||||
|
@ -39,6 +39,7 @@ struct fw_packet;
|
||||
#define BROADCAST_CHANNEL_VALID (1 << 30)
|
||||
|
||||
#define FEATURE_PRIORITY_BUDGET 0x01
|
||||
#define FEATURE_CHANNEL_31_ALLOCATED 0x02
|
||||
|
||||
#define CSR_STATE_BIT_CMSTR (1 << 8)
|
||||
#define CSR_STATE_BIT_ABDICATE (1 << 10)
|
||||
|
@ -171,6 +171,7 @@ struct fw_ohci {
|
||||
int request_generation; /* for timestamping incoming requests */
|
||||
unsigned quirks;
|
||||
unsigned int pri_req_max;
|
||||
unsigned int features;
|
||||
u32 bus_time;
|
||||
bool is_root;
|
||||
|
||||
@ -1694,7 +1695,7 @@ static int ohci_enable(struct fw_card *card,
|
||||
{
|
||||
struct fw_ohci *ohci = fw_ohci(card);
|
||||
struct pci_dev *dev = to_pci_dev(card->device);
|
||||
u32 lps, seconds, irqs;
|
||||
u32 lps, seconds, version, irqs;
|
||||
int i, ret;
|
||||
|
||||
if (software_reset(ohci)) {
|
||||
@ -1747,10 +1748,19 @@ static int ohci_enable(struct fw_card *card,
|
||||
reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
|
||||
ohci->bus_time = seconds & ~0x3f;
|
||||
|
||||
version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
|
||||
if (version >= OHCI_VERSION_1_1) {
|
||||
reg_write(ohci, OHCI1394_InitialChannelsAvailableHi,
|
||||
0xfffffffe);
|
||||
ohci->features |= FEATURE_CHANNEL_31_ALLOCATED;
|
||||
}
|
||||
|
||||
/* Get implemented bits of the priority arbitration request counter. */
|
||||
reg_write(ohci, OHCI1394_FairnessControl, 0x3f);
|
||||
ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f;
|
||||
reg_write(ohci, OHCI1394_FairnessControl, 0);
|
||||
if (ohci->pri_req_max != 0)
|
||||
ohci->features |= FEATURE_PRIORITY_BUDGET;
|
||||
|
||||
ar_context_run(&ohci->ar_request_ctx);
|
||||
ar_context_run(&ohci->ar_response_ctx);
|
||||
@ -2124,12 +2134,8 @@ static void ohci_write_csr_reg(struct fw_card *card, int csr_offset, u32 value)
|
||||
static unsigned int ohci_get_features(struct fw_card *card)
|
||||
{
|
||||
struct fw_ohci *ohci = fw_ohci(card);
|
||||
unsigned int features = 0;
|
||||
|
||||
if (ohci->pri_req_max != 0)
|
||||
features |= FEATURE_PRIORITY_BUDGET;
|
||||
|
||||
return features;
|
||||
return ohci->features;
|
||||
}
|
||||
|
||||
static void copy_iso_headers(struct iso_context *ctx, void *p)
|
||||
|
Loading…
Reference in New Issue
Block a user