Commit f30e6d3e authored by Stefan Richter's avatar Stefan Richter

firewire: octlet AT payloads can be stack-allocated

We do not need slab allocations anymore in order to satisfy
streaming DMA mapping constraints, thanks to commit da28947e
"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: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
Acked-by: default avatarClemens Ladisch <clemens@ladisch.de>
parent 020abf03
...@@ -258,8 +258,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation) ...@@ -258,8 +258,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
if (!card->broadcast_channel_allocated) { if (!card->broadcast_channel_allocated) {
fw_iso_resource_manage(card, generation, 1ULL << 31, fw_iso_resource_manage(card, generation, 1ULL << 31,
&channel, &bandwidth, true, &channel, &bandwidth, true);
card->bm_transaction_data);
if (channel != 31) { if (channel != 31) {
fw_notify("failed to allocate broadcast channel\n"); fw_notify("failed to allocate broadcast channel\n");
return; return;
...@@ -294,6 +293,7 @@ static void bm_work(struct work_struct *work) ...@@ -294,6 +293,7 @@ static void bm_work(struct work_struct *work)
bool root_device_is_cmc; bool root_device_is_cmc;
bool irm_is_1394_1995_only; bool irm_is_1394_1995_only;
bool keep_this_irm; bool keep_this_irm;
__be32 transaction_data[2];
spin_lock_irq(&card->lock); spin_lock_irq(&card->lock);
...@@ -355,21 +355,21 @@ static void bm_work(struct work_struct *work) ...@@ -355,21 +355,21 @@ static void bm_work(struct work_struct *work)
goto pick_me; goto pick_me;
} }
card->bm_transaction_data[0] = cpu_to_be32(0x3f); transaction_data[0] = cpu_to_be32(0x3f);
card->bm_transaction_data[1] = cpu_to_be32(local_id); transaction_data[1] = cpu_to_be32(local_id);
spin_unlock_irq(&card->lock); spin_unlock_irq(&card->lock);
rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
irm_id, generation, SCODE_100, irm_id, generation, SCODE_100,
CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
card->bm_transaction_data, 8); transaction_data, 8);
if (rcode == RCODE_GENERATION) if (rcode == RCODE_GENERATION)
/* Another bus reset, BM work has been rescheduled. */ /* Another bus reset, BM work has been rescheduled. */
goto out; 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); spin_lock_irq(&card->lock);
if (rcode == RCODE_COMPLETE && generation == card->generation) if (rcode == RCODE_COMPLETE && generation == card->generation)
...@@ -490,11 +490,11 @@ static void bm_work(struct work_struct *work) ...@@ -490,11 +490,11 @@ static void bm_work(struct work_struct *work)
/* /*
* Make sure that the cycle master sends cycle start packets. * 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, rcode = fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST,
root_id, generation, SCODE_100, root_id, generation, SCODE_100,
CSR_REGISTER_BASE + CSR_STATE_SET, CSR_REGISTER_BASE + CSR_STATE_SET,
card->bm_transaction_data, 4); transaction_data, 4);
if (rcode == RCODE_GENERATION) if (rcode == RCODE_GENERATION)
goto out; goto out;
} }
......
...@@ -141,7 +141,6 @@ struct iso_resource { ...@@ -141,7 +141,6 @@ struct iso_resource {
int generation; int generation;
u64 channels; u64 channels;
s32 bandwidth; s32 bandwidth;
__be32 transaction_data[2];
struct iso_resource_event *e_alloc, *e_dealloc; struct iso_resource_event *e_alloc, *e_dealloc;
}; };
...@@ -1229,8 +1228,7 @@ static void iso_resource_work(struct work_struct *work) ...@@ -1229,8 +1228,7 @@ static void iso_resource_work(struct work_struct *work)
r->channels, &channel, &bandwidth, r->channels, &channel, &bandwidth,
todo == ISO_RES_ALLOC || todo == ISO_RES_ALLOC ||
todo == ISO_RES_REALLOC || todo == ISO_RES_REALLOC ||
todo == ISO_RES_ALLOC_ONCE, todo == ISO_RES_ALLOC_ONCE);
r->transaction_data);
/* /*
* Is this generation outdated already? As long as this resource sticks * 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 * in the idr, it will be scheduled again for a newer generation or at
......
...@@ -196,9 +196,10 @@ EXPORT_SYMBOL(fw_iso_context_stop); ...@@ -196,9 +196,10 @@ EXPORT_SYMBOL(fw_iso_context_stop);
*/ */
static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, 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; int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0;
__be32 data[2];
/* /*
* On a 1394a IRM with low contention, try < 1 is enough. * On a 1394a IRM with low contention, try < 1 is enough.
...@@ -233,9 +234,10 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, ...@@ -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, 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 bit, all, old;
__be32 data[2];
int channel, ret = -EIO, retry = 5; int channel, ret = -EIO, retry = 5;
old = all = allocate ? cpu_to_be32(~0) : 0; old = all = allocate ? cpu_to_be32(~0) : 0;
...@@ -284,7 +286,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation, ...@@ -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, static void deallocate_channel(struct fw_card *card, int irm_id,
int generation, int channel, __be32 buffer[2]) int generation, int channel)
{ {
u32 mask; u32 mask;
u64 offset; u64 offset;
...@@ -293,7 +295,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id, ...@@ -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 : offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO; 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);
} }
/** /**
...@@ -322,7 +324,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id, ...@@ -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, void fw_iso_resource_manage(struct fw_card *card, int generation,
u64 channels_mask, int *channel, int *bandwidth, u64 channels_mask, int *channel, int *bandwidth,
bool allocate, __be32 buffer[2]) bool allocate)
{ {
u32 channels_hi = channels_mask; /* channels 31...0 */ u32 channels_hi = channels_mask; /* channels 31...0 */
u32 channels_lo = channels_mask >> 32; /* channels 63...32 */ u32 channels_lo = channels_mask >> 32; /* channels 63...32 */
...@@ -335,11 +337,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, ...@@ -335,11 +337,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
if (channels_hi) if (channels_hi)
c = manage_channel(card, irm_id, generation, channels_hi, c = manage_channel(card, irm_id, generation, channels_hi,
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI,
allocate, buffer); allocate);
if (channels_lo && c < 0) { if (channels_lo && c < 0) {
c = manage_channel(card, irm_id, generation, channels_lo, c = manage_channel(card, irm_id, generation, channels_lo,
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO,
allocate, buffer); allocate);
if (c >= 0) if (c >= 0)
c += 32; c += 32;
} }
...@@ -351,14 +353,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, ...@@ -351,14 +353,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
if (*bandwidth == 0) if (*bandwidth == 0)
return; return;
ret = manage_bandwidth(card, irm_id, generation, *bandwidth, ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate);
allocate, buffer);
if (ret < 0) if (ret < 0)
*bandwidth = 0; *bandwidth = 0;
if (allocate && ret < 0) { if (allocate && ret < 0) {
if (c >= 0) if (c >= 0)
deallocate_channel(card, irm_id, generation, c, buffer); deallocate_channel(card, irm_id, generation, c);
*channel = ret; *channel = ret;
} }
} }
......
...@@ -326,8 +326,8 @@ static int allocate_tlabel(struct fw_card *card) ...@@ -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. * 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 * 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 * @length <= 8 or of local (loopback) requests. Hence make sure that the
* the buffer complies with the restrictions for DMA-mapped memory. The * buffer complies with the restrictions of the streaming DMA mapping API.
* @payload must not be freed before the @callback is called. * @payload must not be freed before the @callback is called.
* *
* In case of request types without payload, @data is NULL and @length is 0. * In case of request types without payload, @data is NULL and @length is 0.
...@@ -411,7 +411,8 @@ static void transaction_callback(struct fw_card *card, int rcode, ...@@ -411,7 +411,8 @@ static void transaction_callback(struct fw_card *card, int rcode,
* *
* Returns the RCODE. See fw_send_request() for parameter documentation. * Returns the RCODE. See fw_send_request() for parameter documentation.
* Unlike fw_send_request(), @data points to the payload of the request or/and * 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 fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset, int generation, int speed, unsigned long long offset,
......
...@@ -1320,14 +1320,10 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data) ...@@ -1320,14 +1320,10 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
{ {
int ret; int ret;
mutex_lock(&fdtv->avc_mutex);
ret = fdtv_read(fdtv, addr, data); ret = fdtv_read(fdtv, addr, data);
if (ret < 0) if (ret < 0)
dev_err(fdtv->device, "CMP: read I/O error\n"); dev_err(fdtv->device, "CMP: read I/O error\n");
mutex_unlock(&fdtv->avc_mutex);
return ret; return ret;
} }
...@@ -1335,18 +1331,9 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[]) ...@@ -1335,18 +1331,9 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
{ {
int ret; int ret;
mutex_lock(&fdtv->avc_mutex); ret = fdtv_lock(fdtv, addr, data);
/* data[] is stack-allocated and should not be DMA-mapped. */
memcpy(fdtv->avc_data, data, 8);
ret = fdtv_lock(fdtv, addr, fdtv->avc_data);
if (ret < 0) if (ret < 0)
dev_err(fdtv->device, "CMP: lock I/O error\n"); dev_err(fdtv->device, "CMP: lock I/O error\n");
else
memcpy(data, fdtv->avc_data, 8);
mutex_unlock(&fdtv->avc_mutex);
return ret; return ret;
} }
......
...@@ -125,7 +125,6 @@ struct fw_card { ...@@ -125,7 +125,6 @@ struct fw_card {
struct delayed_work bm_work; /* bus manager job */ struct delayed_work bm_work; /* bus manager job */
int bm_retries; int bm_retries;
int bm_generation; int bm_generation;
__be32 bm_transaction_data[2];
int bm_node_id; int bm_node_id;
bool bm_abdicate; bool bm_abdicate;
...@@ -447,6 +446,6 @@ int fw_iso_context_stop(struct fw_iso_context *ctx); ...@@ -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_context_destroy(struct fw_iso_context *ctx);
void fw_iso_resource_manage(struct fw_card *card, int generation, void fw_iso_resource_manage(struct fw_card *card, int generation,
u64 channels_mask, int *channel, int *bandwidth, u64 channels_mask, int *channel, int *bandwidth,
bool allocate, __be32 buffer[2]); bool allocate);
#endif /* _LINUX_FIREWIRE_H */ #endif /* _LINUX_FIREWIRE_H */
...@@ -49,10 +49,9 @@ static int pcr_modify(struct cmp_connection *c, ...@@ -49,10 +49,9 @@ static int pcr_modify(struct cmp_connection *c,
enum bus_reset_handling bus_reset_handling) enum bus_reset_handling bus_reset_handling)
{ {
struct fw_device *device = fw_parent_device(c->resources.unit); struct fw_device *device = fw_parent_device(c->resources.unit);
__be32 *buffer = c->resources.buffer;
int generation = c->resources.generation; int generation = c->resources.generation;
int rcode, errors = 0; int rcode, errors = 0;
__be32 old_arg; __be32 old_arg, buffer[2];
int err; int err;
buffer[0] = c->last_pcr_value; buffer[0] = c->last_pcr_value;
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include "iso-resources.h" #include "iso-resources.h"
...@@ -25,10 +24,6 @@ ...@@ -25,10 +24,6 @@
*/ */
int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) 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->channels_mask = ~0uLL;
r->unit = fw_unit_get(unit); r->unit = fw_unit_get(unit);
mutex_init(&r->mutex); mutex_init(&r->mutex);
...@@ -44,7 +39,6 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) ...@@ -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) void fw_iso_resources_destroy(struct fw_iso_resources *r)
{ {
WARN_ON(r->allocated); WARN_ON(r->allocated);
kfree(r->buffer);
mutex_destroy(&r->mutex); mutex_destroy(&r->mutex);
fw_unit_put(r->unit); fw_unit_put(r->unit);
} }
...@@ -131,7 +125,7 @@ int fw_iso_resources_allocate(struct fw_iso_resources *r, ...@@ -131,7 +125,7 @@ int fw_iso_resources_allocate(struct fw_iso_resources *r,
bandwidth = r->bandwidth + r->bandwidth_overhead; bandwidth = r->bandwidth + r->bandwidth_overhead;
fw_iso_resource_manage(card, r->generation, r->channels_mask, fw_iso_resource_manage(card, r->generation, r->channels_mask,
&channel, &bandwidth, true, r->buffer); &channel, &bandwidth, true);
if (channel == -EAGAIN) { if (channel == -EAGAIN) {
mutex_unlock(&r->mutex); mutex_unlock(&r->mutex);
goto retry_after_bus_reset; goto retry_after_bus_reset;
...@@ -184,7 +178,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r) ...@@ -184,7 +178,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
bandwidth = r->bandwidth + r->bandwidth_overhead; bandwidth = r->bandwidth + r->bandwidth_overhead;
fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, 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 * When another bus reset happens, pretend that the allocation
* succeeded; we will try again for the new generation later. * succeeded; we will try again for the new generation later.
...@@ -220,7 +214,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r) ...@@ -220,7 +214,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
if (r->allocated) { if (r->allocated) {
bandwidth = r->bandwidth + r->bandwidth_overhead; bandwidth = r->bandwidth + r->bandwidth_overhead;
fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
&channel, &bandwidth, false, r->buffer); &channel, &bandwidth, false);
if (channel < 0) if (channel < 0)
dev_err(&r->unit->device, dev_err(&r->unit->device,
"isochronous resource deallocation failed\n"); "isochronous resource deallocation failed\n");
......
...@@ -24,7 +24,6 @@ struct fw_iso_resources { ...@@ -24,7 +24,6 @@ struct fw_iso_resources {
unsigned int bandwidth_overhead; unsigned int bandwidth_overhead;
int generation; /* in which allocation is valid */ int generation; /* in which allocation is valid */
bool allocated; bool allocated;
__be32 *buffer;
}; };
int fw_iso_resources_init(struct fw_iso_resources *r, int fw_iso_resources_init(struct fw_iso_resources *r,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment