cregit-Linux how code gets into the kernel

Release 4.7 drivers/block/rsxx/cregs.c

/*
* Filename: cregs.c
*
*
* Authors: Joshua Morris <josh.h.morris@us.ibm.com>
*       Philip Kelleher <pjk1939@linux.vnet.ibm.com>
*
* (C) Copyright 2013 IBM Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <linux/completion.h>
#include <linux/slab.h>

#include "rsxx_priv.h"


#define CREG_TIMEOUT_MSEC	10000


typedef void (*creg_cmd_cb)(struct rsxx_cardinfo *card,
			    struct creg_cmd *cmd,
			    int st);


struct creg_cmd {
	
struct list_head list;
	
creg_cmd_cb cb;
	
void *cb_private;
	
unsigned int op;
	
unsigned int addr;
	
int cnt8;
	
void *buf;
	
unsigned int stream;
	
unsigned int status;
};


static struct kmem_cache *creg_cmd_pool;


/*------------ Private Functions --------------*/

#if defined(__LITTLE_ENDIAN)

#define LITTLE_ENDIAN 1
#elif defined(__BIG_ENDIAN)

#define LITTLE_ENDIAN 0
#else
#error Unknown endianess!!! Aborting...
#endif


static int copy_to_creg_data(struct rsxx_cardinfo *card, int cnt8, void *buf, unsigned int stream) { int i = 0; u32 *data = buf; if (unlikely(card->eeh_state)) return -EIO; for (i = 0; cnt8 > 0; i++, cnt8 -= 4) { /* * Firmware implementation makes it necessary to byte swap on * little endian processors. */ if (LITTLE_ENDIAN && stream) iowrite32be(data[i], card->regmap + CREG_DATA(i)); else iowrite32(data[i], card->regmap + CREG_DATA(i)); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris9384.55%150.00%
philip j kelleherphilip j kelleher1715.45%150.00%
Total110100.00%2100.00%


static int copy_from_creg_data(struct rsxx_cardinfo *card, int cnt8, void *buf, unsigned int stream) { int i = 0; u32 *data = buf; if (unlikely(card->eeh_state)) return -EIO; for (i = 0; cnt8 > 0; i++, cnt8 -= 4) { /* * Firmware implementation makes it necessary to byte swap on * little endian processors. */ if (LITTLE_ENDIAN && stream) data[i] = ioread32be(card->regmap + CREG_DATA(i)); else data[i] = ioread32(card->regmap + CREG_DATA(i)); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris9384.55%150.00%
philip j kelleherphilip j kelleher1715.45%150.00%
Total110100.00%2100.00%


static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd) { int st; if (unlikely(card->eeh_state)) return; iowrite32(cmd->addr, card->regmap + CREG_ADD); iowrite32(cmd->cnt8, card->regmap + CREG_CNT); if (cmd->op == CREG_OP_WRITE) { if (cmd->buf) { st = copy_to_creg_data(card, cmd->cnt8, cmd->buf, cmd->stream); if (st) return; } } if (unlikely(card->eeh_state)) return; /* Setting the valid bit will kick off the command. */ iowrite32(cmd->op, card->regmap + CREG_CMD); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris8973.55%150.00%
philip j kelleherphilip j kelleher3226.45%150.00%
Total121100.00%2100.00%


static void creg_kick_queue(struct rsxx_cardinfo *card) { if (card->creg_ctrl.active || list_empty(&card->creg_ctrl.queue)) return; card->creg_ctrl.active = 1; card->creg_ctrl.active_cmd = list_first_entry(&card->creg_ctrl.queue, struct creg_cmd, list); list_del(&card->creg_ctrl.active_cmd->list); card->creg_ctrl.q_depth--; /* * We have to set the timer before we push the new command. Otherwise, * we could create a race condition that would occur if the timer * was not canceled, and expired after the new command was pushed, * but before the command was issued to hardware. */ mod_timer(&card->creg_ctrl.cmd_timer, jiffies + msecs_to_jiffies(CREG_TIMEOUT_MSEC)); creg_issue_cmd(card, card->creg_ctrl.active_cmd); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris107100.00%1100.00%
Total107100.00%1100.00%


static int creg_queue_cmd(struct rsxx_cardinfo *card, unsigned int op, unsigned int addr, unsigned int cnt8, void *buf, int stream, creg_cmd_cb callback, void *cb_private) { struct creg_cmd *cmd; /* Don't queue stuff up if we're halted. */ if (unlikely(card->halt)) return -EINVAL; if (card->creg_ctrl.reset) return -EAGAIN; if (cnt8 > MAX_CREG_DATA8) return -EINVAL; cmd = kmem_cache_alloc(creg_cmd_pool, GFP_KERNEL); if (!cmd) return -ENOMEM; INIT_LIST_HEAD(&cmd->list); cmd->op = op; cmd->addr = addr; cmd->cnt8 = cnt8; cmd->buf = buf; cmd->stream = stream; cmd->cb = callback; cmd->cb_private = cb_private; cmd->status = 0; spin_lock_bh(&card->creg_ctrl.lock); list_add_tail(&cmd->list, &card->creg_ctrl.queue); card->creg_ctrl.q_depth++; creg_kick_queue(card); spin_unlock_bh(&card->creg_ctrl.lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris20099.01%150.00%
philip j kelleherphilip j kelleher20.99%150.00%
Total202100.00%2100.00%


static void creg_cmd_timed_out(unsigned long data) { struct rsxx_cardinfo *card = (struct rsxx_cardinfo *) data; struct creg_cmd *cmd; spin_lock(&card->creg_ctrl.lock); cmd = card->creg_ctrl.active_cmd; card->creg_ctrl.active_cmd = NULL; spin_unlock(&card->creg_ctrl.lock); if (cmd == NULL) { card->creg_ctrl.creg_stats.creg_timeout++; dev_warn(CARD_TO_DEV(card), "No active command associated with timeout!\n"); return; } if (cmd->cb) cmd->cb(card, cmd, -ETIMEDOUT); kmem_cache_free(creg_cmd_pool, cmd); spin_lock(&card->creg_ctrl.lock); card->creg_ctrl.active = 0; creg_kick_queue(card); spin_unlock(&card->creg_ctrl.lock); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris11778.52%133.33%
philip j kelleherphilip j kelleher3221.48%266.67%
Total149100.00%3100.00%


static void creg_cmd_done(struct work_struct *work) { struct rsxx_cardinfo *card; struct creg_cmd *cmd; int st = 0; card = container_of(work, struct rsxx_cardinfo, creg_ctrl.done_work); /* * The timer could not be cancelled for some reason, * race to pop the active command. */ if (del_timer_sync(&card->creg_ctrl.cmd_timer) == 0) card->creg_ctrl.creg_stats.failed_cancel_timer++; spin_lock_bh(&card->creg_ctrl.lock); cmd = card->creg_ctrl.active_cmd; card->creg_ctrl.active_cmd = NULL; spin_unlock_bh(&card->creg_ctrl.lock); if (cmd == NULL) { dev_err(CARD_TO_DEV(card), "Spurious creg interrupt!\n"); return; } card->creg_ctrl.creg_stats.stat = ioread32(card->regmap + CREG_STAT); cmd->status = card->creg_ctrl.creg_stats.stat; if ((cmd->status & CREG_STAT_STATUS_MASK) == 0) { dev_err(CARD_TO_DEV(card), "Invalid status on creg command\n"); /* * At this point we're probably reading garbage from HW. Don't * do anything else that could mess up the system and let * the sync function return an error. */ st = -EIO; goto creg_done; } else if (cmd->status & CREG_STAT_ERROR) { st = -EIO; } if ((cmd->op == CREG_OP_READ)) { unsigned int cnt8 = ioread32(card->regmap + CREG_CNT); /* Paranoid Sanity Checks */ if (!cmd->buf) { dev_err(CARD_TO_DEV(card), "Buffer not given for read.\n"); st = -EIO; goto creg_done; } if (cnt8 != cmd->cnt8) { dev_err(CARD_TO_DEV(card), "count mismatch\n"); st = -EIO; goto creg_done; } st = copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream); } creg_done: if (cmd->cb) cmd->cb(card, cmd, st); kmem_cache_free(creg_cmd_pool, cmd); spin_lock_bh(&card->creg_ctrl.lock); card->creg_ctrl.active = 0; creg_kick_queue(card); spin_unlock_bh(&card->creg_ctrl.lock); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris32090.40%133.33%
philip j kelleherphilip j kelleher349.60%266.67%
Total354100.00%3100.00%


static void creg_reset(struct rsxx_cardinfo *card) { struct creg_cmd *cmd = NULL; struct creg_cmd *tmp; unsigned long flags; /* * mutex_trylock is used here because if reset_lock is taken then a * reset is already happening. So, we can just go ahead and return. */ if (!mutex_trylock(&card->creg_ctrl.reset_lock)) return; card->creg_ctrl.reset = 1; spin_lock_irqsave(&card->irq_lock, flags); rsxx_disable_ier_and_isr(card, CR_INTR_CREG | CR_INTR_EVENT); spin_unlock_irqrestore(&card->irq_lock, flags); dev_warn(CARD_TO_DEV(card), "Resetting creg interface for recovery\n"); /* Cancel outstanding commands */ spin_lock_bh(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); card->creg_ctrl.q_depth--; if (cmd->cb) cmd->cb(card, cmd, -ECANCELED); kmem_cache_free(creg_cmd_pool, cmd); } cmd = card->creg_ctrl.active_cmd; card->creg_ctrl.active_cmd = NULL; if (cmd) { if (timer_pending(&card->creg_ctrl.cmd_timer)) del_timer_sync(&card->creg_ctrl.cmd_timer); if (cmd->cb) cmd->cb(card, cmd, -ECANCELED); kmem_cache_free(creg_cmd_pool, cmd); card->creg_ctrl.active = 0; } spin_unlock_bh(&card->creg_ctrl.lock); card->creg_ctrl.reset = 0; spin_lock_irqsave(&card->irq_lock, flags); rsxx_enable_ier_and_isr(card, CR_INTR_CREG | CR_INTR_EVENT); spin_unlock_irqrestore(&card->irq_lock, flags); mutex_unlock(&card->creg_ctrl.reset_lock); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris28398.95%133.33%
philip j kelleherphilip j kelleher31.05%266.67%
Total286100.00%3100.00%

/* Used for synchronous accesses */ struct creg_completion { struct completion *cmd_done; int st; u32 creg_status; };
static void creg_cmd_done_cb(struct rsxx_cardinfo *card, struct creg_cmd *cmd, int st) { struct creg_completion *cmd_completion; cmd_completion = cmd->cb_private; BUG_ON(!cmd_completion); cmd_completion->st = st; cmd_completion->creg_status = cmd->status; complete(cmd_completion->cmd_done); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris57100.00%1100.00%
Total57100.00%1100.00%


static int __issue_creg_rw(struct rsxx_cardinfo *card, unsigned int op, unsigned int addr, unsigned int cnt8, void *buf, int stream, unsigned int *hw_stat) { DECLARE_COMPLETION_ONSTACK(cmd_done); struct creg_completion completion; unsigned long timeout; int st; completion.cmd_done = &cmd_done; completion.st = 0; completion.creg_status = 0; st = creg_queue_cmd(card, op, addr, cnt8, buf, stream, creg_cmd_done_cb, &completion); if (st) return st; /* * This timeout is necessary for unresponsive hardware. The additional * 20 seconds to used to guarantee that each cregs requests has time to * complete. */ timeout = msecs_to_jiffies(CREG_TIMEOUT_MSEC * card->creg_ctrl.q_depth + 20000); /* * The creg interface is guaranteed to complete. It has a timeout * mechanism that will kick in if hardware does not respond. */ st = wait_for_completion_timeout(completion.cmd_done, timeout); if (st == 0) { /* * This is really bad, because the kernel timer did not * expire and notify us of a timeout! */ dev_crit(CARD_TO_DEV(card), "cregs timer failed\n"); creg_reset(card); return -EIO; } *hw_stat = completion.creg_status; if (completion.st) { /* * This read is needed to verify that there has not been any * extreme errors that might have occurred, i.e. EEH. The * function iowrite32 will not detect EEH errors, so it is * necessary that we recover if such an error is the reason * for the timeout. This is a dummy read. */ ioread32(card->regmap + SCRATCH); dev_warn(CARD_TO_DEV(card), "creg command failed(%d x%08x)\n", completion.st, addr); return completion.st; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris19394.61%133.33%
philip j kelleherphilip j kelleher115.39%266.67%
Total204100.00%3100.00%


static int issue_creg_rw(struct rsxx_cardinfo *card, u32 addr, unsigned int size8, void *data, int stream, int read) { unsigned int hw_stat; unsigned int xfer; unsigned int op; int st; op = read ? CREG_OP_READ : CREG_OP_WRITE; do { xfer = min_t(unsigned int, size8, MAX_CREG_DATA8); st = __issue_creg_rw(card, op, addr, xfer, data, stream, &hw_stat); if (st) return st; data = (char *)data + xfer; addr += xfer; size8 -= xfer; } while (size8); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris118100.00%1100.00%
Total118100.00%1100.00%

/* ---------------------------- Public API ---------------------------------- */
int rsxx_creg_write(struct rsxx_cardinfo *card, u32 addr, unsigned int size8, void *data, int byte_stream) { return issue_creg_rw(card, addr, size8, data, byte_stream, 0); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris40100.00%1100.00%
Total40100.00%1100.00%


int rsxx_creg_read(struct rsxx_cardinfo *card, u32 addr, unsigned int size8, void *data, int byte_stream) { return issue_creg_rw(card, addr, size8, data, byte_stream, 1); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris40100.00%1100.00%
Total40100.00%1100.00%


int rsxx_get_card_state(struct rsxx_cardinfo *card, unsigned int *state) { return rsxx_creg_read(card, CREG_ADD_CARD_STATE, sizeof(*state), state, 0); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris33100.00%1100.00%
Total33100.00%1100.00%


int rsxx_get_card_size8(struct rsxx_cardinfo *card, u64 *size8) { unsigned int size; int st; st = rsxx_creg_read(card, CREG_ADD_CARD_SIZE, sizeof(size), &size, 0); if (st) return st; *size8 = (u64)size * RSXX_HW_BLK_SIZE; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris60100.00%1100.00%
Total60100.00%1100.00%


int rsxx_get_num_targets(struct rsxx_cardinfo *card, unsigned int *n_targets) { return rsxx_creg_read(card, CREG_ADD_NUM_TARGETS, sizeof(*n_targets), n_targets, 0); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris33100.00%1100.00%
Total33100.00%1100.00%


int rsxx_get_card_capabilities(struct rsxx_cardinfo *card, u32 *capabilities) { return rsxx_creg_read(card, CREG_ADD_CAPABILITIES, sizeof(*capabilities), capabilities, 0); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris32100.00%1100.00%
Total32100.00%1100.00%


int rsxx_issue_card_cmd(struct rsxx_cardinfo *card, u32 cmd) { return rsxx_creg_write(card, CREG_ADD_CARD_CMD, sizeof(cmd), &cmd, 0); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris31100.00%1100.00%
Total31100.00%1100.00%

/*----------------- HW Log Functions -------------------*/
static void hw_log_msg(struct rsxx_cardinfo *card, const char *str, int len) { static char level; /* * New messages start with "<#>", where # is the log level. Messages * that extend past the log buffer will use the previous level */ if ((len > 3) && (str[0] == '<') && (str[2] == '>')) { level = str[1]; str += 3; /* Skip past the log level. */ len -= 3; } switch (level) { case '0': dev_emerg(CARD_TO_DEV(card), "HW: %.*s", len, str); break; case '1': dev_alert(CARD_TO_DEV(card), "HW: %.*s", len, str); break; case '2': dev_crit(CARD_TO_DEV(card), "HW: %.*s", len, str); break; case '3': dev_err(CARD_TO_DEV(card), "HW: %.*s", len, str); break; case '4': dev_warn(CARD_TO_DEV(card), "HW: %.*s", len, str); break; case '5': dev_notice(CARD_TO_DEV(card), "HW: %.*s", len, str); break; case '6': dev_info(CARD_TO_DEV(card), "HW: %.*s", len, str); break; case '7': dev_dbg(CARD_TO_DEV(card), "HW: %.*s", len, str); break; default: dev_info(CARD_TO_DEV(card), "HW: %.*s", len, str); break; } }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris234100.00%1100.00%
Total234100.00%1100.00%

/* * The substrncpy function copies the src string (which includes the * terminating '\0' character), up to the count into the dest pointer. * Returns the number of bytes copied to dest. */
static int substrncpy(char *dest, const char *src, int count) { int max_cnt = count; while (count) { count--; *dest = *src; if (*dest == '\0') break; src++; dest++; } return max_cnt - count; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris57100.00%1100.00%
Total57100.00%1100.00%


static void read_hw_log_done(struct rsxx_cardinfo *card, struct creg_cmd *cmd, int st) { char *buf; char *log_str; int cnt; int len; int off; buf = cmd->buf; off = 0; /* Failed getting the log message */ if (st) return; while (off < cmd->cnt8) { log_str = &card->log.buf[card->log.buf_len]; cnt = min(cmd->cnt8 - off, LOG_BUF_SIZE8 - card->log.buf_len); len = substrncpy(log_str, &buf[off], cnt); off += len; card->log.buf_len += len; /* * Flush the log if we've hit the end of a message or if we've * run out of buffer space. */ if ((log_str[len - 1] == '\0') || (card->log.buf_len == LOG_BUF_SIZE8)) { if (card->log.buf_len != 1) /* Don't log blank lines. */ hw_log_msg(card, card->log.buf, card->log.buf_len); card->log.buf_len = 0; } } if (cmd->status & CREG_STAT_LOG_PENDING) rsxx_read_hw_log(card); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris199100.00%1100.00%
Total199100.00%1100.00%


int rsxx_read_hw_log(struct rsxx_cardinfo *card) { int st; st = creg_queue_cmd(card, CREG_OP_READ, CREG_ADD_LOG, sizeof(card->log.tmp), card->log.tmp, 1, read_hw_log_done, NULL); if (st) dev_err(CARD_TO_DEV(card), "Failed getting log text\n"); return st; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris62100.00%1100.00%
Total62100.00%1100.00%

/*-------------- IOCTL REG Access ------------------*/
static int issue_reg_cmd(struct rsxx_cardinfo *card, struct rsxx_reg_access *cmd, int read) { unsigned int op = read ? CREG_OP_READ : CREG_OP_WRITE; return __issue_creg_rw(card, op, cmd->addr, cmd->cnt, cmd->data, cmd->stream, &cmd->stat); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris58100.00%1100.00%
Total58100.00%1100.00%


int rsxx_reg_access(struct rsxx_cardinfo *card, struct rsxx_reg_access __user *ucmd, int read) { struct rsxx_reg_access cmd; int st; st = copy_from_user(&cmd, ucmd, sizeof(cmd)); if (st) return -EFAULT; if (cmd.cnt > RSXX_MAX_REG_CNT) return -EFAULT; st = issue_reg_cmd(card, &cmd, read); if (st) return st; st = put_user(cmd.stat, &ucmd->stat); if (st) return -EFAULT; if (read) { st = copy_to_user(ucmd->data, cmd.data, cmd.cnt); if (st) return -EFAULT; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris12491.18%150.00%
philip j kelleherphilip j kelleher128.82%150.00%
Total136100.00%2100.00%


void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card) { struct creg_cmd *cmd = NULL; cmd = card->creg_ctrl.active_cmd; card->creg_ctrl.active_cmd = NULL; if (cmd) { del_timer_sync(&card->creg_ctrl.cmd_timer); spin_lock_bh(&card->creg_ctrl.lock); list_add(&cmd->list, &card->creg_ctrl.queue); card->creg_ctrl.q_depth++; card->creg_ctrl.active = 0; spin_unlock_bh(&card->creg_ctrl.lock); } }

Contributors

PersonTokensPropCommitsCommitProp
philip j kelleherphilip j kelleher99100.00%1100.00%
Total99100.00%1100.00%


void rsxx_kick_creg_queue(struct rsxx_cardinfo *card) { spin_lock_bh(&card->creg_ctrl.lock); if (!list_empty(&card->creg_ctrl.queue)) creg_kick_queue(card); spin_unlock_bh(&card->creg_ctrl.lock); }

Contributors

PersonTokensPropCommitsCommitProp
philip j kelleherphilip j kelleher48100.00%1100.00%
Total48100.00%1100.00%

/*------------ Initialization & Setup --------------*/
int rsxx_creg_setup(struct rsxx_cardinfo *card) { card->creg_ctrl.active_cmd = NULL; card->creg_ctrl.creg_wq = create_singlethread_workqueue(DRIVER_NAME"_creg"); if (!card->creg_ctrl.creg_wq) return -ENOMEM; INIT_WORK(&card->creg_ctrl.done_work, creg_cmd_done); mutex_init(&card->creg_ctrl.reset_lock); INIT_LIST_HEAD(&card->creg_ctrl.queue); spin_lock_init(&card->creg_ctrl.lock); setup_timer(&card->creg_ctrl.cmd_timer, creg_cmd_timed_out, (unsigned long) card); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris8075.47%133.33%
philip j kelleherphilip j kelleher2624.53%266.67%
Total106100.00%3100.00%


void rsxx_creg_destroy(struct rsxx_cardinfo *card) { struct creg_cmd *cmd; struct creg_cmd *tmp; int cnt = 0; /* Cancel outstanding commands */ spin_lock_bh(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); if (cmd->cb) cmd->cb(card, cmd, -ECANCELED); kmem_cache_free(creg_cmd_pool, cmd); cnt++; } if (cnt) dev_info(CARD_TO_DEV(card), "Canceled %d queue creg commands\n", cnt); cmd = card->creg_ctrl.active_cmd; card->creg_ctrl.active_cmd = NULL; if (cmd) { if (timer_pending(&card->creg_ctrl.cmd_timer)) del_timer_sync(&card->creg_ctrl.cmd_timer); if (cmd->cb) cmd->cb(card, cmd, -ECANCELED); dev_info(CARD_TO_DEV(card), "Canceled active creg command\n"); kmem_cache_free(creg_cmd_pool, cmd); } spin_unlock_bh(&card->creg_ctrl.lock); cancel_work_sync(&card->creg_ctrl.done_work); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris19798.99%150.00%
philip j kelleherphilip j kelleher21.01%150.00%
Total199100.00%2100.00%


int rsxx_creg_init(void) { creg_cmd_pool = KMEM_CACHE(creg_cmd, SLAB_HWCACHE_ALIGN); if (!creg_cmd_pool) return -ENOMEM; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris28100.00%1100.00%
Total28100.00%1100.00%


void rsxx_creg_cleanup(void) { kmem_cache_destroy(creg_cmd_pool); }

Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris12100.00%1100.00%
Total12100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
josh h. morrisjosh h. morris311990.27%114.29%
philip j kelleherphilip j kelleher3369.73%685.71%
Total3455100.00%7100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}