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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 93 | 84.55% | 1 | 50.00% | 
| philip j kelleher | philip j kelleher | 17 | 15.45% | 1 | 50.00% | 
 | Total | 110 | 100.00% | 2 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 93 | 84.55% | 1 | 50.00% | 
| philip j kelleher | philip j kelleher | 17 | 15.45% | 1 | 50.00% | 
 | Total | 110 | 100.00% | 2 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 89 | 73.55% | 1 | 50.00% | 
| philip j kelleher | philip j kelleher | 32 | 26.45% | 1 | 50.00% | 
 | Total | 121 | 100.00% | 2 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 107 | 100.00% | 1 | 100.00% | 
 | Total | 107 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 200 | 99.01% | 1 | 50.00% | 
| philip j kelleher | philip j kelleher | 2 | 0.99% | 1 | 50.00% | 
 | Total | 202 | 100.00% | 2 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 117 | 78.52% | 1 | 33.33% | 
| philip j kelleher | philip j kelleher | 32 | 21.48% | 2 | 66.67% | 
 | Total | 149 | 100.00% | 3 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 320 | 90.40% | 1 | 33.33% | 
| philip j kelleher | philip j kelleher | 34 | 9.60% | 2 | 66.67% | 
 | Total | 354 | 100.00% | 3 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 283 | 98.95% | 1 | 33.33% | 
| philip j kelleher | philip j kelleher | 3 | 1.05% | 2 | 66.67% | 
 | Total | 286 | 100.00% | 3 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 57 | 100.00% | 1 | 100.00% | 
 | Total | 57 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 193 | 94.61% | 1 | 33.33% | 
| philip j kelleher | philip j kelleher | 11 | 5.39% | 2 | 66.67% | 
 | Total | 204 | 100.00% | 3 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 118 | 100.00% | 1 | 100.00% | 
 | Total | 118 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 40 | 100.00% | 1 | 100.00% | 
 | Total | 40 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 40 | 100.00% | 1 | 100.00% | 
 | Total | 40 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 33 | 100.00% | 1 | 100.00% | 
 | Total | 33 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 60 | 100.00% | 1 | 100.00% | 
 | Total | 60 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 33 | 100.00% | 1 | 100.00% | 
 | Total | 33 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 32 | 100.00% | 1 | 100.00% | 
 | Total | 32 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 31 | 100.00% | 1 | 100.00% | 
 | Total | 31 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 234 | 100.00% | 1 | 100.00% | 
 | Total | 234 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 57 | 100.00% | 1 | 100.00% | 
 | Total | 57 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 199 | 100.00% | 1 | 100.00% | 
 | Total | 199 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 62 | 100.00% | 1 | 100.00% | 
 | Total | 62 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 58 | 100.00% | 1 | 100.00% | 
 | Total | 58 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 124 | 91.18% | 1 | 50.00% | 
| philip j kelleher | philip j kelleher | 12 | 8.82% | 1 | 50.00% | 
 | Total | 136 | 100.00% | 2 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| philip j kelleher | philip j kelleher | 99 | 100.00% | 1 | 100.00% | 
 | Total | 99 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| philip j kelleher | philip j kelleher | 48 | 100.00% | 1 | 100.00% | 
 | Total | 48 | 100.00% | 1 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 80 | 75.47% | 1 | 33.33% | 
| philip j kelleher | philip j kelleher | 26 | 24.53% | 2 | 66.67% | 
 | Total | 106 | 100.00% | 3 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 197 | 98.99% | 1 | 50.00% | 
| philip j kelleher | philip j kelleher | 2 | 1.01% | 1 | 50.00% | 
 | Total | 199 | 100.00% | 2 | 100.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
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 28 | 100.00% | 1 | 100.00% | 
 | Total | 28 | 100.00% | 1 | 100.00% | 
void rsxx_creg_cleanup(void)
{
	kmem_cache_destroy(creg_cmd_pool);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 12 | 100.00% | 1 | 100.00% | 
 | Total | 12 | 100.00% | 1 | 100.00% | 
Overall Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| josh h. morris | josh h. morris | 3119 | 90.27% | 1 | 14.29% | 
| philip j kelleher | philip j kelleher | 336 | 9.73% | 6 | 85.71% | 
 | Total | 3455 | 100.00% | 7 | 100.00% | 
  
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.