Skip to content

Commit

Permalink
firewire: octlet AT payloads can be stack-allocated
Browse files Browse the repository at this point in the history
We do not need slab allocations anymore in order to satisfy
streaming DMA mapping constraints, thanks to commit da28947
"firewire: ohci: avoid separate DMA mapping for small AT payloads".

(Besides, the slab-allocated buffers that firewire-core, firewire-sbp2,
and firedtv used to provide for 8-byte write and lock requests were
still not fully portable since they crossed cacheline boundaries or
shared a cacheline with unrelated CPU-accessed data.  snd-firewire-lib
got this aspect right by using an extra kmalloc/ kfree just for the
8-byte transaction buffer.)

This change replaces kmalloc'ed lock transaction scratch buffers in
firewire-core, firedtv, and snd-firewire-lib by local stack allocations.
Perhaps the most notable result of the change is simpler locking because
there is no need to serialize usages of preallocated per-device buffers
anymore.  Also, allocations and deallocations are simpler.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Acked-by: Clemens Ladisch <clemens@ladisch.de>
  • Loading branch information
Stefan Richter committed May 10, 2011
1 parent 020abf0 commit f30e6d3
Show file tree
Hide file tree
Showing 9 changed files with 30 additions and 52 deletions.
16 changes: 8 additions & 8 deletions drivers/firewire/core-card.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)

if (!card->broadcast_channel_allocated) {
fw_iso_resource_manage(card, generation, 1ULL << 31,
&channel, &bandwidth, true,
card->bm_transaction_data);
&channel, &bandwidth, true);
if (channel != 31) {
fw_notify("failed to allocate broadcast channel\n");
return;
Expand Down Expand Up @@ -294,6 +293,7 @@ static void bm_work(struct work_struct *work)
bool root_device_is_cmc;
bool irm_is_1394_1995_only;
bool keep_this_irm;
__be32 transaction_data[2];

spin_lock_irq(&card->lock);

Expand Down Expand Up @@ -355,21 +355,21 @@ static void bm_work(struct work_struct *work)
goto pick_me;
}

card->bm_transaction_data[0] = cpu_to_be32(0x3f);
card->bm_transaction_data[1] = cpu_to_be32(local_id);
transaction_data[0] = cpu_to_be32(0x3f);
transaction_data[1] = cpu_to_be32(local_id);

spin_unlock_irq(&card->lock);

rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
irm_id, generation, SCODE_100,
CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
card->bm_transaction_data, 8);
transaction_data, 8);

if (rcode == RCODE_GENERATION)
/* Another bus reset, BM work has been rescheduled. */
goto out;

bm_id = be32_to_cpu(card->bm_transaction_data[0]);
bm_id = be32_to_cpu(transaction_data[0]);

spin_lock_irq(&card->lock);
if (rcode == RCODE_COMPLETE && generation == card->generation)
Expand Down Expand Up @@ -490,11 +490,11 @@ static void bm_work(struct work_struct *work)
/*
* Make sure that the cycle master sends cycle start packets.
*/
card->bm_transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR);
transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR);
rcode = fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST,
root_id, generation, SCODE_100,
CSR_REGISTER_BASE + CSR_STATE_SET,
card->bm_transaction_data, 4);
transaction_data, 4);
if (rcode == RCODE_GENERATION)
goto out;
}
Expand Down
4 changes: 1 addition & 3 deletions drivers/firewire/core-cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ struct iso_resource {
int generation;
u64 channels;
s32 bandwidth;
__be32 transaction_data[2];
struct iso_resource_event *e_alloc, *e_dealloc;
};

Expand Down Expand Up @@ -1229,8 +1228,7 @@ static void iso_resource_work(struct work_struct *work)
r->channels, &channel, &bandwidth,
todo == ISO_RES_ALLOC ||
todo == ISO_RES_REALLOC ||
todo == ISO_RES_ALLOC_ONCE,
r->transaction_data);
todo == ISO_RES_ALLOC_ONCE);
/*
* Is this generation outdated already? As long as this resource sticks
* in the idr, it will be scheduled again for a newer generation or at
Expand Down
21 changes: 11 additions & 10 deletions drivers/firewire/core-iso.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,10 @@ EXPORT_SYMBOL(fw_iso_context_stop);
*/

static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
int bandwidth, bool allocate, __be32 data[2])
int bandwidth, bool allocate)
{
int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0;
__be32 data[2];

/*
* On a 1394a IRM with low contention, try < 1 is enough.
Expand Down Expand Up @@ -233,9 +234,10 @@ 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,
u32 channels_mask, u64 offset, bool allocate, __be32 data[2])
u32 channels_mask, u64 offset, bool allocate)
{
__be32 bit, all, old;
__be32 data[2];
int channel, ret = -EIO, retry = 5;

old = all = allocate ? cpu_to_be32(~0) : 0;
Expand Down Expand Up @@ -284,7 +286,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation,
}

static void deallocate_channel(struct fw_card *card, int irm_id,
int generation, int channel, __be32 buffer[2])
int generation, int channel)
{
u32 mask;
u64 offset;
Expand All @@ -293,7 +295,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO;

manage_channel(card, irm_id, generation, mask, offset, false, buffer);
manage_channel(card, irm_id, generation, mask, offset, false);
}

/**
Expand Down Expand Up @@ -322,7 +324,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
*/
void fw_iso_resource_manage(struct fw_card *card, int generation,
u64 channels_mask, int *channel, int *bandwidth,
bool allocate, __be32 buffer[2])
bool allocate)
{
u32 channels_hi = channels_mask; /* channels 31...0 */
u32 channels_lo = channels_mask >> 32; /* channels 63...32 */
Expand All @@ -335,11 +337,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
if (channels_hi)
c = manage_channel(card, irm_id, generation, channels_hi,
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI,
allocate, buffer);
allocate);
if (channels_lo && c < 0) {
c = manage_channel(card, irm_id, generation, channels_lo,
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO,
allocate, buffer);
allocate);
if (c >= 0)
c += 32;
}
Expand All @@ -351,14 +353,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
if (*bandwidth == 0)
return;

ret = manage_bandwidth(card, irm_id, generation, *bandwidth,
allocate, buffer);
ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate);
if (ret < 0)
*bandwidth = 0;

if (allocate && ret < 0) {
if (c >= 0)
deallocate_channel(card, irm_id, generation, c, buffer);
deallocate_channel(card, irm_id, generation, c);
*channel = ret;
}
}
Expand Down
7 changes: 4 additions & 3 deletions drivers/firewire/core-transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ static int allocate_tlabel(struct fw_card *card)
* It will contain tag, channel, and sy data instead of a node ID then.
*
* The payload buffer at @data is going to be DMA-mapped except in case of
* quadlet-sized payload or of local (loopback) requests. Hence make sure that
* the buffer complies with the restrictions for DMA-mapped memory. The
* @length <= 8 or of local (loopback) requests. Hence make sure that the
* buffer complies with the restrictions of the streaming DMA mapping API.
* @payload must not be freed before the @callback is called.
*
* In case of request types without payload, @data is NULL and @length is 0.
Expand Down Expand Up @@ -411,7 +411,8 @@ static void transaction_callback(struct fw_card *card, int rcode,
*
* Returns the RCODE. See fw_send_request() for parameter documentation.
* Unlike fw_send_request(), @data points to the payload of the request or/and
* to the payload of the response.
* to the payload of the response. DMA mapping restrictions apply to outbound
* request payloads of >= 8 bytes but not to inbound response payloads.
*/
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset,
Expand Down
15 changes: 1 addition & 14 deletions drivers/media/dvb/firewire/firedtv-avc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1320,33 +1320,20 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
{
int ret;

mutex_lock(&fdtv->avc_mutex);

ret = fdtv_read(fdtv, addr, data);
if (ret < 0)
dev_err(fdtv->device, "CMP: read I/O error\n");

mutex_unlock(&fdtv->avc_mutex);

return ret;
}

static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
{
int ret;

mutex_lock(&fdtv->avc_mutex);

/* data[] is stack-allocated and should not be DMA-mapped. */
memcpy(fdtv->avc_data, data, 8);

ret = fdtv_lock(fdtv, addr, fdtv->avc_data);
ret = fdtv_lock(fdtv, addr, data);
if (ret < 0)
dev_err(fdtv->device, "CMP: lock I/O error\n");
else
memcpy(data, fdtv->avc_data, 8);

mutex_unlock(&fdtv->avc_mutex);

return ret;
}
Expand Down
3 changes: 1 addition & 2 deletions include/linux/firewire.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ struct fw_card {
struct delayed_work bm_work; /* bus manager job */
int bm_retries;
int bm_generation;
__be32 bm_transaction_data[2];
int bm_node_id;
bool bm_abdicate;

Expand Down Expand Up @@ -447,6 +446,6 @@ int fw_iso_context_stop(struct fw_iso_context *ctx);
void fw_iso_context_destroy(struct fw_iso_context *ctx);
void fw_iso_resource_manage(struct fw_card *card, int generation,
u64 channels_mask, int *channel, int *bandwidth,
bool allocate, __be32 buffer[2]);
bool allocate);

#endif /* _LINUX_FIREWIRE_H */
3 changes: 1 addition & 2 deletions sound/firewire/cmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,9 @@ static int pcr_modify(struct cmp_connection *c,
enum bus_reset_handling bus_reset_handling)
{
struct fw_device *device = fw_parent_device(c->resources.unit);
__be32 *buffer = c->resources.buffer;
int generation = c->resources.generation;
int rcode, errors = 0;
__be32 old_arg;
__be32 old_arg, buffer[2];
int err;

buffer[0] = c->last_pcr_value;
Expand Down
12 changes: 3 additions & 9 deletions sound/firewire/iso-resources.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "iso-resources.h"

Expand All @@ -25,10 +24,6 @@
*/
int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
{
r->buffer = kmalloc(2 * 4, GFP_KERNEL);
if (!r->buffer)
return -ENOMEM;

r->channels_mask = ~0uLL;
r->unit = fw_unit_get(unit);
mutex_init(&r->mutex);
Expand All @@ -44,7 +39,6 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
void fw_iso_resources_destroy(struct fw_iso_resources *r)
{
WARN_ON(r->allocated);
kfree(r->buffer);
mutex_destroy(&r->mutex);
fw_unit_put(r->unit);
}
Expand Down Expand Up @@ -131,7 +125,7 @@ int fw_iso_resources_allocate(struct fw_iso_resources *r,

bandwidth = r->bandwidth + r->bandwidth_overhead;
fw_iso_resource_manage(card, r->generation, r->channels_mask,
&channel, &bandwidth, true, r->buffer);
&channel, &bandwidth, true);
if (channel == -EAGAIN) {
mutex_unlock(&r->mutex);
goto retry_after_bus_reset;
Expand Down Expand Up @@ -184,7 +178,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
bandwidth = r->bandwidth + r->bandwidth_overhead;

fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
&channel, &bandwidth, true, r->buffer);
&channel, &bandwidth, true);
/*
* When another bus reset happens, pretend that the allocation
* succeeded; we will try again for the new generation later.
Expand Down Expand Up @@ -220,7 +214,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
if (r->allocated) {
bandwidth = r->bandwidth + r->bandwidth_overhead;
fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
&channel, &bandwidth, false, r->buffer);
&channel, &bandwidth, false);
if (channel < 0)
dev_err(&r->unit->device,
"isochronous resource deallocation failed\n");
Expand Down
1 change: 0 additions & 1 deletion sound/firewire/iso-resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ struct fw_iso_resources {
unsigned int bandwidth_overhead;
int generation; /* in which allocation is valid */
bool allocated;
__be32 *buffer;
};

int fw_iso_resources_init(struct fw_iso_resources *r,
Expand Down

0 comments on commit f30e6d3

Please sign in to comment.