wctdm24xxp: Use our own free list for IRQ commands.

Really only *necessary* when SLAB debugging is enabled, but in that
case, can reduce the chance of latency bumps when first loading the
driver. Otherwise the constant slab poisoning / checking in interrupt
context from the kmalloc / kfrees is too much.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Russ Meyerriecks <rmeyerriecks@digium.com>

git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10144 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
Shaun Ruffell 2011-08-18 19:21:44 +00:00
parent 1862d8040c
commit ad4489c7f4
2 changed files with 48 additions and 5 deletions

View File

@ -867,6 +867,8 @@ static void _cmd_decipher(struct wctdm *wc, const u8 *eframe, int card)
return; return;
} }
list_add(&cmd->node, &wc->free_isr_commands);
switch (mod->type) { switch (mod->type) {
case FXS: case FXS:
mod->isrshadow[(68 == address) ? 0 : 1] = value; mod->isrshadow[(68 == address) ? 0 : 1] = value;
@ -884,8 +886,6 @@ static void _cmd_decipher(struct wctdm *wc, const u8 *eframe, int card)
default: default:
break; break;
} }
kfree(cmd);
} }
/* Call with wc.reglock held and local interrupts disabled. */ /* Call with wc.reglock held and local interrupts disabled. */
@ -894,9 +894,15 @@ wctdm_isr_getreg(struct wctdm *wc, struct wctdm_module *const mod, u8 address)
{ {
struct wctdm_cmd *cmd; struct wctdm_cmd *cmd;
if (!list_empty(&wc->free_isr_commands)) {
cmd = list_entry(wc->free_isr_commands.next,
struct wctdm_cmd, node);
list_del(&cmd->node);
} else {
cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
if (unlikely(!cmd)) if (unlikely(!cmd))
return; return;
}
cmd->cmd = CMD_RD(address); cmd->cmd = CMD_RD(address);
cmd->complete = NULL; cmd->complete = NULL;
@ -4633,6 +4639,7 @@ static void wctdm_back_out_gracefully(struct wctdm *wc)
list_splice_init(&mod->pending_cmds, &local_list); list_splice_init(&mod->pending_cmds, &local_list);
list_splice_init(&mod->active_cmds, &local_list); list_splice_init(&mod->active_cmds, &local_list);
} }
list_splice_init(&wc->free_isr_commands, &local_list);
spin_unlock_irqrestore(&wc->reglock, flags); spin_unlock_irqrestore(&wc->reglock, flags);
while (!list_empty(&local_list)) { while (!list_empty(&local_list)) {
@ -5221,6 +5228,39 @@ static void wctdm_set_tdm410_leds(struct wctdm *wc)
} }
} }
/**
* wctdm_allocate_irq_commands - Preallocate some commands for use in interrupt context.
* @wc: The board which we're allocating for.
* @count: The number of IRQ commands to allocate.
*
* We need a minimum of 4 * the current latency worth of commands for each
* analog module. When the latency grows, new commands will be allocated, but
* this just represents are best guess as to the number of commands we'll need
* after probing for modules, and reduces the chance that we'll allocate
* memory in interrupt context when the driver first loads.
*
*/
static void wctdm_allocate_irq_commands(struct wctdm *wc, unsigned int count)
{
unsigned long flags;
LIST_HEAD(local_list);
if (!count)
return;
while (count--) {
struct wctdm_cmd *cmd;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
break;
list_add(&cmd->node, &local_list);
}
spin_lock_irqsave(&wc->reglock, flags);
list_splice(&local_list, &wc->free_isr_commands);
spin_unlock_irqrestore(&wc->reglock, flags);
}
#ifdef USE_ASYNC_INIT #ifdef USE_ASYNC_INIT
struct async_data { struct async_data {
struct pci_dev *pdev; struct pci_dev *pdev;
@ -5266,6 +5306,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
spin_lock_init(&wc->frame_list_lock); spin_lock_init(&wc->frame_list_lock);
init_waitqueue_head(&wc->regq); init_waitqueue_head(&wc->regq);
spin_lock_init(&wc->reglock); spin_lock_init(&wc->reglock);
INIT_LIST_HEAD(&wc->free_isr_commands);
wc->oldsync = -1; wc->oldsync = -1;
wc->board_name = kasprintf(GFP_KERNEL, "%s%d", wctdm_driver.name, pos); wc->board_name = kasprintf(GFP_KERNEL, "%s%d", wctdm_driver.name, pos);
@ -5492,6 +5533,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
} }
wctdm_allocate_irq_commands(wc, anamods * latency * 4);
wc->not_ready--; wc->not_ready--;
dev_info(&wc->vb.pdev->dev, dev_info(&wc->vb.pdev->dev,

View File

@ -255,6 +255,7 @@ struct wctdm {
spinlock_t reglock; /* held when accessing anything affecting the module array */ spinlock_t reglock; /* held when accessing anything affecting the module array */
wait_queue_head_t regq; wait_queue_head_t regq;
struct list_head free_isr_commands;
struct wctdm_module mods[NUM_MODULES]; struct wctdm_module mods[NUM_MODULES];