18722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/*
28722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* Filename: cregs.c
38722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*
48722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*
58722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* Authors: Joshua Morris <josh.h.morris@us.ibm.com>
68722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*	Philip Kelleher <pjk1939@linux.vnet.ibm.com>
78722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*
88722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* (C) Copyright 2013 IBM Corporation
98722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*
108722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* This program is free software; you can redistribute it and/or
118722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* modify it under the terms of the GNU General Public License as
128722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* published by the Free Software Foundation; either version 2 of the
138722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* License, or (at your option) any later version.
148722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*
158722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* This program is distributed in the hope that it will be useful, but
168722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* WITHOUT ANY WARRANTY; without even the implied warranty of
178722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
188722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* General Public License for more details.
198722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*
208722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* You should have received a copy of the GNU General Public License
218722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* along with this program; if not, write to the Free Software Foundation,
228722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
238722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com*/
248722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
258722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#include <linux/completion.h>
268722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#include <linux/slab.h>
278722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
288722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#include "rsxx_priv.h"
298722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
308722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#define CREG_TIMEOUT_MSEC	10000
318722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
328722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comtypedef void (*creg_cmd_cb)(struct rsxx_cardinfo *card,
338722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			    struct creg_cmd *cmd,
348722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			    int st);
358722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
368722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstruct creg_cmd {
378722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct list_head list;
388722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	creg_cmd_cb cb;
398722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	void *cb_private;
408722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int op;
418722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int addr;
428722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int cnt8;
438722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	void *buf;
448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int stream;
458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int status;
468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com};
478722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic struct kmem_cache *creg_cmd_pool;
498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/*------------ Private Functions --------------*/
528722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
538722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#if defined(__LITTLE_ENDIAN)
548722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#define LITTLE_ENDIAN 1
558722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#elif defined(__BIG_ENDIAN)
568722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#define LITTLE_ENDIAN 0
578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#else
588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#error Unknown endianess!!! Aborting...
598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com#endif
608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
61c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleherstatic int copy_to_creg_data(struct rsxx_cardinfo *card,
628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			      int cnt8,
638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			      void *buf,
648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			      unsigned int stream)
658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int i = 0;
678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	u32 *data = buf;
688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
69c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	if (unlikely(card->eeh_state))
70c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		return -EIO;
71c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	for (i = 0; cnt8 > 0; i++, cnt8 -= 4) {
738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		/*
748722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * Firmware implementation makes it necessary to byte swap on
758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * little endian processors.
768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 */
778722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (LITTLE_ENDIAN && stream)
788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			iowrite32be(data[i], card->regmap + CREG_DATA(i));
798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		else
808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			iowrite32(data[i], card->regmap + CREG_DATA(i));
818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
82c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
83c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	return 0;
848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
868722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
87c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleherstatic int copy_from_creg_data(struct rsxx_cardinfo *card,
888722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				int cnt8,
898722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				void *buf,
908722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				unsigned int stream)
918722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int i = 0;
938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	u32 *data = buf;
948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
95c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	if (unlikely(card->eeh_state))
96c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		return -EIO;
97c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	for (i = 0; cnt8 > 0; i++, cnt8 -= 4) {
998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		/*
1008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * Firmware implementation makes it necessary to byte swap on
1018722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * little endian processors.
1028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 */
1038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (LITTLE_ENDIAN && stream)
1048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			data[i] = ioread32be(card->regmap + CREG_DATA(i));
1058722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		else
1068722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			data[i] = ioread32(card->regmap + CREG_DATA(i));
1078722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
108c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
109c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	return 0;
1108722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
1118722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1128722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd)
1138722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
114c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	int st;
115c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
116c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	if (unlikely(card->eeh_state))
117c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		return;
118c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
1198722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	iowrite32(cmd->addr, card->regmap + CREG_ADD);
1208722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	iowrite32(cmd->cnt8, card->regmap + CREG_CNT);
1218722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1228722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd->op == CREG_OP_WRITE) {
123c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		if (cmd->buf) {
124c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher			st = copy_to_creg_data(card, cmd->cnt8,
125c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher					       cmd->buf, cmd->stream);
126c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher			if (st)
127c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher				return;
128c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		}
1298722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
1308722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
131c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	if (unlikely(card->eeh_state))
132c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		return;
133c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
1348722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/* Setting the valid bit will kick off the command. */
1358722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	iowrite32(cmd->op, card->regmap + CREG_CMD);
1368722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
1378722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1388722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void creg_kick_queue(struct rsxx_cardinfo *card)
1398722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
1408722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (card->creg_ctrl.active || list_empty(&card->creg_ctrl.queue))
1418722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return;
1428722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1438722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.active = 1;
1448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.active_cmd = list_first_entry(&card->creg_ctrl.queue,
1458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com						      struct creg_cmd, list);
1468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	list_del(&card->creg_ctrl.active_cmd->list);
1478722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.q_depth--;
1488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/*
1508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * We have to set the timer before we push the new command. Otherwise,
1518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * we could create a race condition that would occur if the timer
1528722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * was not canceled, and expired after the new command was pushed,
1538722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * but before the command was issued to hardware.
1548722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 */
1558722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	mod_timer(&card->creg_ctrl.cmd_timer,
1568722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				jiffies + msecs_to_jiffies(CREG_TIMEOUT_MSEC));
1578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	creg_issue_cmd(card, card->creg_ctrl.active_cmd);
1598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
1608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1618722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic int creg_queue_cmd(struct rsxx_cardinfo *card,
1628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			  unsigned int op,
1638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			  unsigned int addr,
1648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			  unsigned int cnt8,
1658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			  void *buf,
1668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			  int stream,
1678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			  creg_cmd_cb callback,
1688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			  void *cb_private)
1698722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
1708722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_cmd *cmd;
1718722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/* Don't queue stuff up if we're halted. */
1738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (unlikely(card->halt))
1748722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -EINVAL;
1758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (card->creg_ctrl.reset)
1778722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -EAGAIN;
1788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cnt8 > MAX_CREG_DATA8)
1808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -EINVAL;
1818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1828722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd = kmem_cache_alloc(creg_cmd_pool, GFP_KERNEL);
1838722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (!cmd)
1848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -ENOMEM;
1858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1868722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	INIT_LIST_HEAD(&cmd->list);
1878722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
1888722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->op		= op;
1898722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->addr	= addr;
1908722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->cnt8	= cnt8;
1918722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->buf	= buf;
1928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->stream	= stream;
1938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->cb		= callback;
1948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->cb_private = cb_private;
1958722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->status	= 0;
1968722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
19703ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_lock_bh(&card->creg_ctrl.lock);
1988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	list_add_tail(&cmd->list, &card->creg_ctrl.queue);
1998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.q_depth++;
2008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	creg_kick_queue(card);
20103ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_unlock_bh(&card->creg_ctrl.lock);
2028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return 0;
2048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
2058722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2068722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void creg_cmd_timed_out(unsigned long data)
2078722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
2088722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct rsxx_cardinfo *card = (struct rsxx_cardinfo *) data;
2098722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_cmd *cmd;
2108722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
21103ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_lock(&card->creg_ctrl.lock);
21203ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	cmd = card->creg_ctrl.active_cmd;
21303ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	card->creg_ctrl.active_cmd = NULL;
21403ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_unlock(&card->creg_ctrl.lock);
21503ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher
2168722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd == NULL) {
2178722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		card->creg_ctrl.creg_stats.creg_timeout++;
2188722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_warn(CARD_TO_DEV(card),
2198722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"No active command associated with timeout!\n");
2208722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return;
2218722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
2228722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2238722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd->cb)
2248722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		cmd->cb(card, cmd, -ETIMEDOUT);
2258722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2268722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	kmem_cache_free(creg_cmd_pool, cmd);
2278722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
228c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher
229c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	spin_lock(&card->creg_ctrl.lock);
2308722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.active = 0;
2318722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	creg_kick_queue(card);
232c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	spin_unlock(&card->creg_ctrl.lock);
2338722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
2348722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2358722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2368722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void creg_cmd_done(struct work_struct *work)
2378722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
2388722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct rsxx_cardinfo *card;
2398722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_cmd *cmd;
2408722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int st = 0;
2418722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2428722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card = container_of(work, struct rsxx_cardinfo,
2438722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			    creg_ctrl.done_work);
2448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/*
2468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * The timer could not be cancelled for some reason,
2478722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * race to pop the active command.
2488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 */
2498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (del_timer_sync(&card->creg_ctrl.cmd_timer) == 0)
2508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		card->creg_ctrl.creg_stats.failed_cancel_timer++;
2518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
25203ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_lock_bh(&card->creg_ctrl.lock);
25303ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	cmd = card->creg_ctrl.active_cmd;
25403ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	card->creg_ctrl.active_cmd = NULL;
25503ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_unlock_bh(&card->creg_ctrl.lock);
25603ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher
2578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd == NULL) {
2588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_err(CARD_TO_DEV(card),
2598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"Spurious creg interrupt!\n");
2608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return;
2618722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
2628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.creg_stats.stat = ioread32(card->regmap + CREG_STAT);
2648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd->status = card->creg_ctrl.creg_stats.stat;
2658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if ((cmd->status & CREG_STAT_STATUS_MASK) == 0) {
2668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_err(CARD_TO_DEV(card),
2678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"Invalid status on creg command\n");
2688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		/*
2698722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * At this point we're probably reading garbage from HW. Don't
2708722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * do anything else that could mess up the system and let
2718722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * the sync function return an error.
2728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 */
2738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		st = -EIO;
2748722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		goto creg_done;
2758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	} else if (cmd->status & CREG_STAT_ERROR) {
2768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		st = -EIO;
2778722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
2788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if ((cmd->op == CREG_OP_READ)) {
2808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		unsigned int cnt8 = ioread32(card->regmap + CREG_CNT);
2818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2828722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		/* Paranoid Sanity Checks */
2838722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (!cmd->buf) {
2848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			dev_err(CARD_TO_DEV(card),
2858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				"Buffer not given for read.\n");
2868722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			st = -EIO;
2878722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			goto creg_done;
2888722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		}
2898722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (cnt8 != cmd->cnt8) {
2908722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			dev_err(CARD_TO_DEV(card),
2918722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				"count mismatch\n");
2928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			st = -EIO;
2938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			goto creg_done;
2948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		}
2958722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
296c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		st = copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream);
2978722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
2988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
2998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comcreg_done:
3008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd->cb)
3018722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		cmd->cb(card, cmd, st);
3028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	kmem_cache_free(creg_cmd_pool, cmd);
3048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
30503ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_lock_bh(&card->creg_ctrl.lock);
3068722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.active = 0;
3078722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	creg_kick_queue(card);
30803ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_unlock_bh(&card->creg_ctrl.lock);
3098722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
3108722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3118722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void creg_reset(struct rsxx_cardinfo *card)
3128722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
3138722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_cmd *cmd = NULL;
3148722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_cmd *tmp;
3158722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned long flags;
3168722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
317c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	/*
318c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	 * mutex_trylock is used here because if reset_lock is taken then a
319c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	 * reset is already happening. So, we can just go ahead and return.
320c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	 */
3218722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (!mutex_trylock(&card->creg_ctrl.reset_lock))
3228722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return;
3238722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3248722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.reset = 1;
3258722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	spin_lock_irqsave(&card->irq_lock, flags);
3268722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	rsxx_disable_ier_and_isr(card, CR_INTR_CREG | CR_INTR_EVENT);
3278722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	spin_unlock_irqrestore(&card->irq_lock, flags);
3288722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3298722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	dev_warn(CARD_TO_DEV(card),
3308722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		"Resetting creg interface for recovery\n");
3318722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3328722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/* Cancel outstanding commands */
33303ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_lock_bh(&card->creg_ctrl.lock);
3348722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) {
3358722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		list_del(&cmd->list);
3368722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		card->creg_ctrl.q_depth--;
3378722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (cmd->cb)
3388722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			cmd->cb(card, cmd, -ECANCELED);
3398722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		kmem_cache_free(creg_cmd_pool, cmd);
3408722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
3418722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3428722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd = card->creg_ctrl.active_cmd;
3438722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.active_cmd = NULL;
3448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd) {
3458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (timer_pending(&card->creg_ctrl.cmd_timer))
3468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			del_timer_sync(&card->creg_ctrl.cmd_timer);
3478722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (cmd->cb)
3498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			cmd->cb(card, cmd, -ECANCELED);
3508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		kmem_cache_free(creg_cmd_pool, cmd);
3518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3528722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		card->creg_ctrl.active = 0;
3538722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
35403ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_unlock_bh(&card->creg_ctrl.lock);
3558722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3568722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.reset = 0;
3578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	spin_lock_irqsave(&card->irq_lock, flags);
3588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	rsxx_enable_ier_and_isr(card, CR_INTR_CREG | CR_INTR_EVENT);
3598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	spin_unlock_irqrestore(&card->irq_lock, flags);
3608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3618722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	mutex_unlock(&card->creg_ctrl.reset_lock);
3628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
3638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/* Used for synchronous accesses */
3658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstruct creg_completion {
3668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct completion	*cmd_done;
3678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int			st;
3688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	u32			creg_status;
3698722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com};
3708722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3718722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void creg_cmd_done_cb(struct rsxx_cardinfo *card,
3728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			     struct creg_cmd *cmd,
3738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			     int st)
3748722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
3758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_completion *cmd_completion;
3768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
377c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	cmd_completion = cmd->cb_private;
3788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	BUG_ON(!cmd_completion);
3798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd_completion->st = st;
3818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd_completion->creg_status = cmd->status;
3828722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	complete(cmd_completion->cmd_done);
3838722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
3848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic int __issue_creg_rw(struct rsxx_cardinfo *card,
3868722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			   unsigned int op,
3878722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			   unsigned int addr,
3888722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			   unsigned int cnt8,
3898722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			   void *buf,
3908722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			   int stream,
3918722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			   unsigned int *hw_stat)
3928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
3938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	DECLARE_COMPLETION_ONSTACK(cmd_done);
3948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_completion completion;
3958722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned long timeout;
3968722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int st;
3978722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
3988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	completion.cmd_done = &cmd_done;
3998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	completion.st = 0;
4008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	completion.creg_status = 0;
4018722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	st = creg_queue_cmd(card, op, addr, cnt8, buf, stream, creg_cmd_done_cb,
4038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			    &completion);
4048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st)
4058722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return st;
4068722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
407c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	/*
408f37912039eb04979f269de0a7dc1a601702df51aPhilip J Kelleher	 * This timeout is necessary for unresponsive hardware. The additional
409c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	 * 20 seconds to used to guarantee that each cregs requests has time to
410c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	 * complete.
411c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	 */
412f37912039eb04979f269de0a7dc1a601702df51aPhilip J Kelleher	timeout = msecs_to_jiffies(CREG_TIMEOUT_MSEC *
413f37912039eb04979f269de0a7dc1a601702df51aPhilip J Kelleher				   card->creg_ctrl.q_depth + 20000);
4148722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4158722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/*
4168722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * The creg interface is guaranteed to complete. It has a timeout
4178722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * mechanism that will kick in if hardware does not respond.
4188722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 */
4198722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	st = wait_for_completion_timeout(completion.cmd_done, timeout);
4208722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st == 0) {
4218722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		/*
4228722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * This is really bad, because the kernel timer did not
4238722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * expire and notify us of a timeout!
4248722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 */
4258722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_crit(CARD_TO_DEV(card),
4268722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"cregs timer failed\n");
4278722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		creg_reset(card);
4288722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -EIO;
4298722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
4308722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4318722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	*hw_stat = completion.creg_status;
4328722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4338722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (completion.st) {
434b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		/*
435b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		* This read is needed to verify that there has not been any
436b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		* extreme errors that might have occurred, i.e. EEH. The
437b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		* function iowrite32 will not detect EEH errors, so it is
438b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		* necessary that we recover if such an error is the reason
439b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		* for the timeout. This is a dummy read.
440b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		*/
441b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher		ioread32(card->regmap + SCRATCH);
442b8b225da139f5770d7689b189fd5debc58f4b35dPhilip J Kelleher
4438722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_warn(CARD_TO_DEV(card),
4448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"creg command failed(%d x%08x)\n",
4458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			completion.st, addr);
4468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return completion.st;
4478722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
4488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return 0;
4508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
4518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4528722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic int issue_creg_rw(struct rsxx_cardinfo *card,
4538722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			 u32 addr,
4548722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			 unsigned int size8,
4558722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			 void *data,
4568722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			 int stream,
4578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			 int read)
4588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
4598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int hw_stat;
4608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int xfer;
4618722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int op;
4628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int st;
4638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	op = read ? CREG_OP_READ : CREG_OP_WRITE;
4658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	do {
4678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		xfer = min_t(unsigned int, size8, MAX_CREG_DATA8);
4688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4698722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		st = __issue_creg_rw(card, op, addr, xfer,
4708722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				     data, stream, &hw_stat);
4718722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (st)
4728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			return st;
4738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
474c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher		data   = (char *)data + xfer;
4758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		addr  += xfer;
4768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		size8 -= xfer;
4778722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	} while (size8);
4788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return 0;
4808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
4818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4828722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/* ---------------------------- Public API ---------------------------------- */
4838722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_creg_write(struct rsxx_cardinfo *card,
4848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			u32 addr,
4858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			unsigned int size8,
4868722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			void *data,
4878722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			int byte_stream)
4888722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
4898722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return issue_creg_rw(card, addr, size8, data, byte_stream, 0);
4908722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
4918722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
4928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_creg_read(struct rsxx_cardinfo *card,
4938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		       u32 addr,
4948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		       unsigned int size8,
4958722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		       void *data,
4968722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		       int byte_stream)
4978722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
4988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return issue_creg_rw(card, addr, size8, data, byte_stream, 1);
4998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
5008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5018722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_get_card_state(struct rsxx_cardinfo *card, unsigned int *state)
5028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
5038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return rsxx_creg_read(card, CREG_ADD_CARD_STATE,
5048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				  sizeof(*state), state, 0);
5058722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
5068722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5078722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_get_card_size8(struct rsxx_cardinfo *card, u64 *size8)
5088722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
5098722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int size;
5108722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int st;
5118722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5128722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	st = rsxx_creg_read(card, CREG_ADD_CARD_SIZE,
5138722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				sizeof(size), &size, 0);
5148722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st)
5158722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return st;
5168722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5178722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	*size8 = (u64)size * RSXX_HW_BLK_SIZE;
5188722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return 0;
5198722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
5208722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5218722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_get_num_targets(struct rsxx_cardinfo *card,
5228722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			     unsigned int *n_targets)
5238722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
5248722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return rsxx_creg_read(card, CREG_ADD_NUM_TARGETS,
5258722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				  sizeof(*n_targets), n_targets, 0);
5268722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
5278722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5288722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_get_card_capabilities(struct rsxx_cardinfo *card,
5298722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				   u32 *capabilities)
5308722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
5318722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return rsxx_creg_read(card, CREG_ADD_CAPABILITIES,
5328722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				  sizeof(*capabilities), capabilities, 0);
5338722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
5348722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5358722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_issue_card_cmd(struct rsxx_cardinfo *card, u32 cmd)
5368722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
5378722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return rsxx_creg_write(card, CREG_ADD_CARD_CMD,
5388722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				   sizeof(cmd), &cmd, 0);
5398722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
5408722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5418722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5428722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/*----------------- HW Log Functions -------------------*/
5438722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void hw_log_msg(struct rsxx_cardinfo *card, const char *str, int len)
5448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
5458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	static char level;
5468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5478722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/*
5488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * New messages start with "<#>", where # is the log level. Messages
5498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 * that extend past the log buffer will use the previous level
5508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	 */
5518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if ((len > 3) && (str[0] == '<') && (str[2] == '>')) {
5528722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		level = str[1];
5538722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		str += 3; /* Skip past the log level. */
5548722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		len -= 3;
5558722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
5568722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	switch (level) {
5588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '0':
5598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_emerg(CARD_TO_DEV(card), "HW: %.*s", len, str);
5608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5618722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '1':
5628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_alert(CARD_TO_DEV(card), "HW: %.*s", len, str);
5638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '2':
5658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_crit(CARD_TO_DEV(card), "HW: %.*s", len, str);
5668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '3':
5688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_err(CARD_TO_DEV(card), "HW: %.*s", len, str);
5698722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5708722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '4':
5718722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_warn(CARD_TO_DEV(card), "HW: %.*s", len, str);
5728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '5':
5748722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_notice(CARD_TO_DEV(card), "HW: %.*s", len, str);
5758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '6':
5778722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_info(CARD_TO_DEV(card), "HW: %.*s", len, str);
5788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	case '7':
5808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_dbg(CARD_TO_DEV(card), "HW: %.*s", len, str);
5818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5828722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	default:
5838722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_info(CARD_TO_DEV(card), "HW: %.*s", len, str);
5848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		break;
5858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
5868722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
5878722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5888722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/*
589c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher * The substrncpy function copies the src string (which includes the
590c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher * terminating '\0' character), up to the count into the dest pointer.
591c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher * Returns the number of bytes copied to dest.
5928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com */
5938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic int substrncpy(char *dest, const char *src, int count)
5948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
5958722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int max_cnt = count;
5968722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
5978722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	while (count) {
5988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		count--;
5998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		*dest = *src;
6008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (*dest == '\0')
6018722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			break;
6028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		src++;
6038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dest++;
6048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
6058722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return max_cnt - count;
6068722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
6078722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6088722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6098722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic void read_hw_log_done(struct rsxx_cardinfo *card,
6108722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			     struct creg_cmd *cmd,
6118722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			     int st)
6128722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
6138722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	char *buf;
6148722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	char *log_str;
6158722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int cnt;
6168722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int len;
6178722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int off;
6188722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6198722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	buf = cmd->buf;
6208722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	off = 0;
6218722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6228722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/* Failed getting the log message */
6238722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st)
6248722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return;
6258722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6268722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	while (off < cmd->cnt8) {
6278722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		log_str = &card->log.buf[card->log.buf_len];
6288722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		cnt = min(cmd->cnt8 - off, LOG_BUF_SIZE8 - card->log.buf_len);
6298722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		len = substrncpy(log_str, &buf[off], cnt);
6308722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6318722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		off += len;
6328722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		card->log.buf_len += len;
6338722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6348722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		/*
6358722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * Flush the log if we've hit the end of a message or if we've
6368722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 * run out of buffer space.
6378722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		 */
6388722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if ((log_str[len - 1] == '\0')  ||
6398722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		    (card->log.buf_len == LOG_BUF_SIZE8)) {
6408722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			if (card->log.buf_len != 1) /* Don't log blank lines. */
6418722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com				hw_log_msg(card, card->log.buf,
6428722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com					   card->log.buf_len);
6438722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			card->log.buf_len = 0;
6448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		}
6458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
6478722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd->status & CREG_STAT_LOG_PENDING)
6498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		rsxx_read_hw_log(card);
6508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
6518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6528722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_read_hw_log(struct rsxx_cardinfo *card)
6538722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
6548722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int st;
6558722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6568722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	st = creg_queue_cmd(card, CREG_OP_READ, CREG_ADD_LOG,
6578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			    sizeof(card->log.tmp), card->log.tmp,
6588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			    1, read_hw_log_done, NULL);
6598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st)
6608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_err(CARD_TO_DEV(card),
6618722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"Failed getting log text\n");
6628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return st;
6648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
6658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/*-------------- IOCTL REG Access ------------------*/
6678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comstatic int issue_reg_cmd(struct rsxx_cardinfo *card,
6688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			 struct rsxx_reg_access *cmd,
6698722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			 int read)
6708722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
6718722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	unsigned int op = read ? CREG_OP_READ : CREG_OP_WRITE;
6728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return __issue_creg_rw(card, op, cmd->addr, cmd->cnt, cmd->data,
6748722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			       cmd->stream, &cmd->stat);
6758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
6768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6778722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_reg_access(struct rsxx_cardinfo *card,
6788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			struct rsxx_reg_access __user *ucmd,
6798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			int read)
6808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
6818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct rsxx_reg_access cmd;
6828722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int st;
6838722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	st = copy_from_user(&cmd, ucmd, sizeof(cmd));
6858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st)
6868722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -EFAULT;
6878722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
688c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	if (cmd.cnt > RSXX_MAX_REG_CNT)
689c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher		return -EFAULT;
690c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher
6918722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	st = issue_reg_cmd(card, &cmd, read);
6928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st)
6938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return st;
6948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6958722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	st = put_user(cmd.stat, &ucmd->stat);
6968722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (st)
6978722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -EFAULT;
6988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
6998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (read) {
7008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		st = copy_to_user(ucmd->data, cmd.data, cmd.cnt);
7018722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (st)
7028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			return -EFAULT;
7038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
7048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7058722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return 0;
7068722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
7078722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
708c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kellehervoid rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card)
709c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher{
710c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	struct creg_cmd *cmd = NULL;
711c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
712c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	cmd = card->creg_ctrl.active_cmd;
713c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	card->creg_ctrl.active_cmd = NULL;
714c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
715c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	if (cmd) {
716c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		del_timer_sync(&card->creg_ctrl.cmd_timer);
717c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
718c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		spin_lock_bh(&card->creg_ctrl.lock);
719c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		list_add(&cmd->list, &card->creg_ctrl.queue);
720c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		card->creg_ctrl.q_depth++;
721c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		card->creg_ctrl.active = 0;
722c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		spin_unlock_bh(&card->creg_ctrl.lock);
723c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	}
724c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher}
725c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
726c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kellehervoid rsxx_kick_creg_queue(struct rsxx_cardinfo *card)
727c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher{
728c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	spin_lock_bh(&card->creg_ctrl.lock);
729c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	if (!list_empty(&card->creg_ctrl.queue))
730c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher		creg_kick_queue(card);
731c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher	spin_unlock_bh(&card->creg_ctrl.lock);
732c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher}
733c95246c3a2ac796cfa43e76200ede59cb4a1644fPhilip J Kelleher
7348722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com/*------------ Initialization & Setup --------------*/
7358722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_creg_setup(struct rsxx_cardinfo *card)
7368722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
7378722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.active_cmd = NULL;
7388722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
739a3299ab18591d36ad5622f5064619123c439b779Philip J Kelleher	card->creg_ctrl.creg_wq =
740a3299ab18591d36ad5622f5064619123c439b779Philip J Kelleher			create_singlethread_workqueue(DRIVER_NAME"_creg");
741a3299ab18591d36ad5622f5064619123c439b779Philip J Kelleher	if (!card->creg_ctrl.creg_wq)
742a3299ab18591d36ad5622f5064619123c439b779Philip J Kelleher		return -ENOMEM;
743a3299ab18591d36ad5622f5064619123c439b779Philip J Kelleher
7448722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	INIT_WORK(&card->creg_ctrl.done_work, creg_cmd_done);
7458722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	mutex_init(&card->creg_ctrl.reset_lock);
7468722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	INIT_LIST_HEAD(&card->creg_ctrl.queue);
747c206c70924737db6836382c09ad2dacd04bb6204Philip J Kelleher	spin_lock_init(&card->creg_ctrl.lock);
7488722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	setup_timer(&card->creg_ctrl.cmd_timer, creg_cmd_timed_out,
7498722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		    (unsigned long) card);
7508722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7518722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return 0;
7528722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
7538722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7548722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comvoid rsxx_creg_destroy(struct rsxx_cardinfo *card)
7558722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
7568722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_cmd *cmd;
7578722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	struct creg_cmd *tmp;
7588722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	int cnt = 0;
7598722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7608722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	/* Cancel outstanding commands */
76103ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_lock_bh(&card->creg_ctrl.lock);
7628722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) {
7638722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		list_del(&cmd->list);
7648722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (cmd->cb)
7658722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			cmd->cb(card, cmd, -ECANCELED);
7668722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		kmem_cache_free(creg_cmd_pool, cmd);
7678722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		cnt++;
7688722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
7698722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7708722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cnt)
7718722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_info(CARD_TO_DEV(card),
7728722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"Canceled %d queue creg commands\n", cnt);
7738722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7748722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cmd = card->creg_ctrl.active_cmd;
7758722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	card->creg_ctrl.active_cmd = NULL;
7768722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (cmd) {
7778722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (timer_pending(&card->creg_ctrl.cmd_timer))
7788722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			del_timer_sync(&card->creg_ctrl.cmd_timer);
7798722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7808722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		if (cmd->cb)
7818722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			cmd->cb(card, cmd, -ECANCELED);
7828722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		dev_info(CARD_TO_DEV(card),
7838722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com			"Canceled active creg command\n");
7848722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		kmem_cache_free(creg_cmd_pool, cmd);
7858722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	}
78603ac03a8971bd7e9f8c8b20a309b61beaf154d60Philip J Kelleher	spin_unlock_bh(&card->creg_ctrl.lock);
7878722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7888722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	cancel_work_sync(&card->creg_ctrl.done_work);
7898722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
7908722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7918722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7928722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comint rsxx_creg_init(void)
7938722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
7948722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	creg_cmd_pool = KMEM_CACHE(creg_cmd, SLAB_HWCACHE_ALIGN);
7958722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	if (!creg_cmd_pool)
7968722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com		return -ENOMEM;
7978722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
7988722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	return 0;
7998722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
8008722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com
8018722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.comvoid rsxx_creg_cleanup(void)
8028722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com{
8038722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com	kmem_cache_destroy(creg_cmd_pool);
8048722ff8cdbfac9c1b20e67bb067b455c48cb8e93josh.h.morris@us.ibm.com}
805