s390/zcrypt: Fixed reset and interrupt handling of AP queues
In case of request timeouts an AP queue reset will be triggered to recover and reinitialize the AP queue. The previous behavior was an immediate reset execution regardless of current/pending requests. Due to newly changed firmware behavior the reset may be delayed, based on the priority of pending request. The device driver's waiting time frame was limited, hence it did not received the reset response. As a consequence interrupts would not be enabled afterwards. The RAPQ (queue reset) and AQIC (interrupt control) commands will be treated fully asynchronous now. The device driver will check the reset and interrupt states periodically, thus it can handle the reinitialization properly. Signed-off-by: Ingo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Родитель
3c8e5105e7
Коммит
c50a160c17
|
@ -60,7 +60,7 @@ static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags);
|
|||
static int ap_device_remove(struct device *dev);
|
||||
static int ap_device_probe(struct device *dev);
|
||||
static void ap_interrupt_handler(struct airq_struct *airq);
|
||||
static void ap_reset(struct ap_device *ap_dev);
|
||||
static void ap_reset(struct ap_device *ap_dev, unsigned long *flags);
|
||||
static void ap_config_timeout(unsigned long ptr);
|
||||
static int ap_select_domain(void);
|
||||
static void ap_query_configuration(void);
|
||||
|
@ -310,35 +310,26 @@ static inline int __ap_query_configuration(struct ap_config_info *config)
|
|||
static int ap_query_functions(ap_qid_t qid, unsigned int *functions)
|
||||
{
|
||||
struct ap_queue_status status;
|
||||
int i;
|
||||
|
||||
status = __ap_query_functions(qid, functions);
|
||||
|
||||
for (i = 0; i < AP_MAX_RESET; i++) {
|
||||
if (ap_queue_status_invalid_test(&status))
|
||||
return -ENODEV;
|
||||
if (ap_queue_status_invalid_test(&status))
|
||||
return -ENODEV;
|
||||
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
return 0;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
case AP_RESPONSE_BUSY:
|
||||
break;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
case AP_RESPONSE_INVALID_ADDRESS:
|
||||
return -ENODEV;
|
||||
case AP_RESPONSE_OTHERWISE_CHANGED:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (i < AP_MAX_RESET - 1) {
|
||||
udelay(5);
|
||||
status = __ap_query_functions(qid, functions);
|
||||
}
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
return 0;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
case AP_RESPONSE_INVALID_ADDRESS:
|
||||
return -ENODEV;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
case AP_RESPONSE_BUSY:
|
||||
case AP_RESPONSE_OTHERWISE_CHANGED:
|
||||
default:
|
||||
return -EBUSY;
|
||||
}
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -350,47 +341,25 @@ static int ap_query_functions(ap_qid_t qid, unsigned int *functions)
|
|||
* on the return value it waits a while and tests the AP queue if interrupts
|
||||
* have been switched on using ap_test_queue().
|
||||
*/
|
||||
static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
|
||||
static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind)
|
||||
{
|
||||
struct ap_queue_status status;
|
||||
int t_depth, t_device_type, rc, i;
|
||||
|
||||
rc = -EBUSY;
|
||||
status = ap_queue_interruption_control(qid, ind);
|
||||
|
||||
for (i = 0; i < AP_MAX_RESET; i++) {
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
if (status.int_enabled)
|
||||
return 0;
|
||||
break;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
case AP_RESPONSE_BUSY:
|
||||
if (i < AP_MAX_RESET - 1) {
|
||||
udelay(5);
|
||||
status = ap_queue_interruption_control(qid,
|
||||
ind);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
case AP_RESPONSE_INVALID_ADDRESS:
|
||||
return -ENODEV;
|
||||
case AP_RESPONSE_OTHERWISE_CHANGED:
|
||||
if (status.int_enabled)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (i < AP_MAX_RESET - 1) {
|
||||
udelay(5);
|
||||
status = ap_test_queue(qid, &t_depth, &t_device_type);
|
||||
}
|
||||
status = ap_queue_interruption_control(ap_dev->qid, ind);
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
case AP_RESPONSE_OTHERWISE_CHANGED:
|
||||
return 0;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
case AP_RESPONSE_INVALID_ADDRESS:
|
||||
return -ENODEV;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
case AP_RESPONSE_BUSY:
|
||||
default:
|
||||
return -EBUSY;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -510,110 +479,95 @@ int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
|
|||
}
|
||||
EXPORT_SYMBOL(ap_recv);
|
||||
|
||||
/**
|
||||
* __ap_schedule_poll_timer(): Schedule poll timer.
|
||||
*
|
||||
* Set up the timer to run the poll tasklet
|
||||
*/
|
||||
static inline void __ap_schedule_poll_timer(void)
|
||||
{
|
||||
ktime_t hr_time;
|
||||
|
||||
spin_lock_bh(&ap_poll_timer_lock);
|
||||
if (!hrtimer_is_queued(&ap_poll_timer) && !ap_suspend_flag) {
|
||||
hr_time = ktime_set(0, poll_timeout);
|
||||
hrtimer_forward_now(&ap_poll_timer, hr_time);
|
||||
hrtimer_restart(&ap_poll_timer);
|
||||
}
|
||||
spin_unlock_bh(&ap_poll_timer_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* ap_schedule_poll_timer(): Schedule poll timer.
|
||||
*
|
||||
* Set up the timer to run the poll tasklet
|
||||
*/
|
||||
static inline void ap_schedule_poll_timer(void)
|
||||
{
|
||||
if (ap_using_interrupts())
|
||||
return;
|
||||
__ap_schedule_poll_timer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ap_query_queue(): Check if an AP queue is available.
|
||||
* @qid: The AP queue number
|
||||
* @queue_depth: Pointer to queue depth value
|
||||
* @device_type: Pointer to device type value
|
||||
*
|
||||
* The test is repeated for AP_MAX_RESET times.
|
||||
*/
|
||||
static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type)
|
||||
{
|
||||
struct ap_queue_status status;
|
||||
int t_depth, t_device_type, rc, i;
|
||||
int t_depth, t_device_type;
|
||||
|
||||
rc = -EBUSY;
|
||||
for (i = 0; i < AP_MAX_RESET; i++) {
|
||||
status = ap_test_queue(qid, &t_depth, &t_device_type);
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
*queue_depth = t_depth + 1;
|
||||
*device_type = t_device_type;
|
||||
rc = 0;
|
||||
break;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
rc = -ENODEV;
|
||||
break;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
break;
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
rc = -ENODEV;
|
||||
break;
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
rc = -ENODEV;
|
||||
break;
|
||||
case AP_RESPONSE_INVALID_ADDRESS:
|
||||
rc = -ENODEV;
|
||||
break;
|
||||
case AP_RESPONSE_OTHERWISE_CHANGED:
|
||||
break;
|
||||
case AP_RESPONSE_BUSY:
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
if (rc != -EBUSY)
|
||||
break;
|
||||
if (i < AP_MAX_RESET - 1)
|
||||
udelay(5);
|
||||
status = ap_test_queue(qid, &t_depth, &t_device_type);
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
*queue_depth = t_depth + 1;
|
||||
*device_type = t_device_type;
|
||||
return 0;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
case AP_RESPONSE_INVALID_ADDRESS:
|
||||
return -ENODEV;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
case AP_RESPONSE_OTHERWISE_CHANGED:
|
||||
case AP_RESPONSE_BUSY:
|
||||
return -EBUSY;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ap_init_queue(): Reset an AP queue.
|
||||
* @qid: The AP queue number
|
||||
*
|
||||
* Reset an AP queue and wait for it to become available again.
|
||||
* Submit the Reset command to an AP queue.
|
||||
* Since the reset is asynchron set the state to 'RESET_IN_PROGRESS'
|
||||
* and check later via ap_poll_queue() if the reset is done.
|
||||
*/
|
||||
static int ap_init_queue(ap_qid_t qid)
|
||||
static int ap_init_queue(struct ap_device *ap_dev)
|
||||
{
|
||||
struct ap_queue_status status;
|
||||
int rc, dummy, i;
|
||||
|
||||
rc = -ENODEV;
|
||||
status = ap_reset_queue(qid);
|
||||
for (i = 0; i < AP_MAX_RESET; i++) {
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
if (status.queue_empty)
|
||||
rc = 0;
|
||||
break;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
i = AP_MAX_RESET; /* return with -ENODEV */
|
||||
break;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
rc = -EBUSY;
|
||||
case AP_RESPONSE_BUSY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (rc != -ENODEV && rc != -EBUSY)
|
||||
break;
|
||||
if (i < AP_MAX_RESET - 1) {
|
||||
/* Time we are waiting until we give up (0.7sec * 90).
|
||||
* Since the actual request (in progress) will not
|
||||
* interrupted immediately for the reset command,
|
||||
* we have to be patient. In worst case we have to
|
||||
* wait 60sec + reset time (some msec).
|
||||
*/
|
||||
schedule_timeout(AP_RESET_TIMEOUT);
|
||||
status = ap_test_queue(qid, &dummy, &dummy);
|
||||
}
|
||||
status = ap_reset_queue(ap_dev->qid);
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
ap_dev->interrupt = AP_INTR_DISABLED;
|
||||
ap_dev->reset = AP_RESET_IN_PROGRESS;
|
||||
return 0;
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
case AP_RESPONSE_BUSY:
|
||||
return -EBUSY;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
if (rc == 0 && ap_using_interrupts()) {
|
||||
rc = ap_queue_enable_interruption(qid, ap_airq.lsi_ptr);
|
||||
/* If interruption mode is supported by the machine,
|
||||
* but an AP can not be enabled for interruption then
|
||||
* the AP will be discarded. */
|
||||
if (rc)
|
||||
pr_err("Registering adapter interrupts for "
|
||||
"AP %d failed\n", AP_QID_DEVICE(qid));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -729,10 +683,63 @@ static ssize_t ap_pendingq_count_show(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL);
|
||||
|
||||
static ssize_t ap_reset_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ap_device *ap_dev = to_ap_dev(dev);
|
||||
int rc = 0;
|
||||
|
||||
spin_lock_bh(&ap_dev->lock);
|
||||
switch (ap_dev->reset) {
|
||||
case AP_RESET_IGNORE:
|
||||
rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n");
|
||||
break;
|
||||
case AP_RESET_ARMED:
|
||||
rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n");
|
||||
break;
|
||||
case AP_RESET_DO:
|
||||
rc = snprintf(buf, PAGE_SIZE, "Reset Timer expired.\n");
|
||||
break;
|
||||
case AP_RESET_IN_PROGRESS:
|
||||
rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&ap_dev->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL);
|
||||
|
||||
static ssize_t ap_interrupt_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ap_device *ap_dev = to_ap_dev(dev);
|
||||
int rc = 0;
|
||||
|
||||
spin_lock_bh(&ap_dev->lock);
|
||||
switch (ap_dev->interrupt) {
|
||||
case AP_INTR_DISABLED:
|
||||
rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n");
|
||||
break;
|
||||
case AP_INTR_ENABLED:
|
||||
rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n");
|
||||
break;
|
||||
case AP_INTR_IN_PROGRESS:
|
||||
rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n");
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&ap_dev->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL);
|
||||
|
||||
static ssize_t ap_modalias_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "ap:t%02X", to_ap_dev(dev)->device_type);
|
||||
return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
|
||||
|
@ -753,6 +760,8 @@ static struct attribute *ap_dev_attrs[] = {
|
|||
&dev_attr_request_count.attr,
|
||||
&dev_attr_requestq_count.attr,
|
||||
&dev_attr_pendingq_count.attr,
|
||||
&dev_attr_reset.attr,
|
||||
&dev_attr_interrupt.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_ap_functions.attr,
|
||||
NULL
|
||||
|
@ -926,6 +935,10 @@ static int ap_device_probe(struct device *dev)
|
|||
spin_lock_bh(&ap_device_list_lock);
|
||||
list_del_init(&ap_dev->list);
|
||||
spin_unlock_bh(&ap_device_list_lock);
|
||||
} else {
|
||||
if (ap_dev->reset == AP_RESET_IN_PROGRESS ||
|
||||
ap_dev->interrupt == AP_INTR_IN_PROGRESS)
|
||||
__ap_schedule_poll_timer();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -1411,7 +1424,7 @@ static void ap_scan_bus(struct work_struct *unused)
|
|||
struct ap_device *ap_dev;
|
||||
struct device *dev;
|
||||
ap_qid_t qid;
|
||||
int queue_depth, device_type;
|
||||
int queue_depth = 0, device_type = 0;
|
||||
unsigned int device_functions;
|
||||
int rc, i;
|
||||
|
||||
|
@ -1429,15 +1442,9 @@ static void ap_scan_bus(struct work_struct *unused)
|
|||
else
|
||||
rc = -ENODEV;
|
||||
if (dev) {
|
||||
if (rc == -EBUSY) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout(AP_RESET_TIMEOUT);
|
||||
rc = ap_query_queue(qid, &queue_depth,
|
||||
&device_type);
|
||||
}
|
||||
ap_dev = to_ap_dev(dev);
|
||||
spin_lock_bh(&ap_dev->lock);
|
||||
if (rc || ap_dev->unregistered) {
|
||||
if (rc == -ENODEV || ap_dev->unregistered) {
|
||||
spin_unlock_bh(&ap_dev->lock);
|
||||
if (ap_dev->unregistered)
|
||||
i--;
|
||||
|
@ -1449,15 +1456,17 @@ static void ap_scan_bus(struct work_struct *unused)
|
|||
put_device(dev);
|
||||
continue;
|
||||
}
|
||||
if (rc)
|
||||
continue;
|
||||
rc = ap_init_queue(qid);
|
||||
if (rc)
|
||||
continue;
|
||||
ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL);
|
||||
if (!ap_dev)
|
||||
break;
|
||||
ap_dev->qid = qid;
|
||||
rc = ap_init_queue(ap_dev);
|
||||
if ((rc != 0) && (rc != -EBUSY)) {
|
||||
kfree(ap_dev);
|
||||
continue;
|
||||
}
|
||||
ap_dev->queue_depth = queue_depth;
|
||||
ap_dev->unregistered = 1;
|
||||
spin_lock_init(&ap_dev->lock);
|
||||
|
@ -1519,36 +1528,6 @@ ap_config_timeout(unsigned long ptr)
|
|||
add_timer(&ap_config_timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* __ap_schedule_poll_timer(): Schedule poll timer.
|
||||
*
|
||||
* Set up the timer to run the poll tasklet
|
||||
*/
|
||||
static inline void __ap_schedule_poll_timer(void)
|
||||
{
|
||||
ktime_t hr_time;
|
||||
|
||||
spin_lock_bh(&ap_poll_timer_lock);
|
||||
if (!hrtimer_is_queued(&ap_poll_timer) && !ap_suspend_flag) {
|
||||
hr_time = ktime_set(0, poll_timeout);
|
||||
hrtimer_forward_now(&ap_poll_timer, hr_time);
|
||||
hrtimer_restart(&ap_poll_timer);
|
||||
}
|
||||
spin_unlock_bh(&ap_poll_timer_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* ap_schedule_poll_timer(): Schedule poll timer.
|
||||
*
|
||||
* Set up the timer to run the poll tasklet
|
||||
*/
|
||||
static inline void ap_schedule_poll_timer(void)
|
||||
{
|
||||
if (ap_using_interrupts())
|
||||
return;
|
||||
__ap_schedule_poll_timer();
|
||||
}
|
||||
|
||||
/**
|
||||
* ap_poll_read(): Receive pending reply messages from an AP device.
|
||||
* @ap_dev: pointer to the AP device
|
||||
|
@ -1568,6 +1547,7 @@ static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
|
|||
ap_dev->reply->message, ap_dev->reply->length);
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
ap_dev->interrupt = status.int_enabled;
|
||||
atomic_dec(&ap_poll_requests);
|
||||
ap_decrease_queue_count(ap_dev);
|
||||
list_for_each_entry(ap_msg, &ap_dev->pendingq, list) {
|
||||
|
@ -1582,6 +1562,7 @@ static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
|
|||
*flags |= 1;
|
||||
break;
|
||||
case AP_RESPONSE_NO_PENDING_REPLY:
|
||||
ap_dev->interrupt = status.int_enabled;
|
||||
if (status.queue_empty) {
|
||||
/* The card shouldn't forget requests but who knows. */
|
||||
atomic_sub(ap_dev->queue_count, &ap_poll_requests);
|
||||
|
@ -1612,7 +1593,8 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
|
|||
struct ap_message *ap_msg;
|
||||
|
||||
if (ap_dev->requestq_count <= 0 ||
|
||||
ap_dev->queue_count >= ap_dev->queue_depth)
|
||||
(ap_dev->queue_count >= ap_dev->queue_depth) ||
|
||||
(ap_dev->reset == AP_RESET_IN_PROGRESS))
|
||||
return 0;
|
||||
/* Start the next request on the queue. */
|
||||
ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
|
||||
|
@ -1646,6 +1628,8 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
|
|||
|
||||
/**
|
||||
* ap_poll_queue(): Poll AP device for pending replies and send new messages.
|
||||
* Check if the queue has a pending reset. In case it's done re-enable
|
||||
* interrupts, otherwise reschedule the poll_timer for another attempt.
|
||||
* @ap_dev: pointer to the bus device
|
||||
* @flags: pointer to control flags, bit 2^0 is set if another poll is
|
||||
* required, bit 2^1 is set if the poll timer needs to get armed
|
||||
|
@ -1656,7 +1640,51 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
|
|||
*/
|
||||
static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags)
|
||||
{
|
||||
int rc;
|
||||
int rc, depth, type;
|
||||
struct ap_queue_status status;
|
||||
|
||||
|
||||
if (ap_dev->reset == AP_RESET_IN_PROGRESS) {
|
||||
status = ap_test_queue(ap_dev->qid, &depth, &type);
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
ap_dev->reset = AP_RESET_IGNORE;
|
||||
if (ap_using_interrupts()) {
|
||||
rc = ap_queue_enable_interruption(
|
||||
ap_dev, ap_airq.lsi_ptr);
|
||||
if (!rc)
|
||||
ap_dev->interrupt = AP_INTR_IN_PROGRESS;
|
||||
else if (rc == -ENODEV) {
|
||||
pr_err("Registering adapter interrupts for "
|
||||
"AP %d failed\n", AP_QID_DEVICE(ap_dev->qid));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case AP_RESPONSE_BUSY:
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
*flags |= AP_POLL_AFTER_TIMEOUT;
|
||||
break;
|
||||
case AP_RESPONSE_Q_NOT_AVAIL:
|
||||
case AP_RESPONSE_DECONFIGURED:
|
||||
case AP_RESPONSE_CHECKSTOPPED:
|
||||
return -ENODEV;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ap_dev->reset != AP_RESET_IN_PROGRESS) &&
|
||||
(ap_dev->interrupt == AP_INTR_IN_PROGRESS)) {
|
||||
status = ap_test_queue(ap_dev->qid, &depth, &type);
|
||||
if (ap_using_interrupts()) {
|
||||
if (status.int_enabled == 1)
|
||||
ap_dev->interrupt = AP_INTR_ENABLED;
|
||||
else
|
||||
*flags |= AP_POLL_AFTER_TIMEOUT;
|
||||
} else
|
||||
ap_dev->interrupt = AP_INTR_DISABLED;
|
||||
}
|
||||
|
||||
rc = ap_poll_read(ap_dev, flags);
|
||||
if (rc)
|
||||
|
@ -1676,7 +1704,8 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms
|
|||
struct ap_queue_status status;
|
||||
|
||||
if (list_empty(&ap_dev->requestq) &&
|
||||
ap_dev->queue_count < ap_dev->queue_depth) {
|
||||
(ap_dev->queue_count < ap_dev->queue_depth) &&
|
||||
(ap_dev->reset != AP_RESET_IN_PROGRESS)) {
|
||||
status = __ap_send(ap_dev->qid, ap_msg->psmid,
|
||||
ap_msg->message, ap_msg->length,
|
||||
ap_msg->special);
|
||||
|
@ -1789,21 +1818,20 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused)
|
|||
* Reset a not responding AP device and move all requests from the
|
||||
* pending queue to the request queue.
|
||||
*/
|
||||
static void ap_reset(struct ap_device *ap_dev)
|
||||
static void ap_reset(struct ap_device *ap_dev, unsigned long *flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ap_dev->reset = AP_RESET_IGNORE;
|
||||
atomic_sub(ap_dev->queue_count, &ap_poll_requests);
|
||||
ap_dev->queue_count = 0;
|
||||
list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
|
||||
ap_dev->requestq_count += ap_dev->pendingq_count;
|
||||
ap_dev->pendingq_count = 0;
|
||||
rc = ap_init_queue(ap_dev->qid);
|
||||
rc = ap_init_queue(ap_dev);
|
||||
if (rc == -ENODEV)
|
||||
ap_dev->unregistered = 1;
|
||||
else
|
||||
__ap_schedule_poll_timer();
|
||||
*flags |= AP_POLL_AFTER_TIMEOUT;
|
||||
}
|
||||
|
||||
static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags)
|
||||
|
@ -1812,7 +1840,7 @@ static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags)
|
|||
if (ap_poll_queue(ap_dev, flags))
|
||||
ap_dev->unregistered = 1;
|
||||
if (ap_dev->reset == AP_RESET_DO)
|
||||
ap_reset(ap_dev);
|
||||
ap_reset(ap_dev, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1845,9 +1873,9 @@ static void ap_poll_all(unsigned long dummy)
|
|||
spin_unlock(&ap_dev->lock);
|
||||
}
|
||||
spin_unlock(&ap_device_list_lock);
|
||||
} while (flags & 1);
|
||||
if (flags & 2)
|
||||
ap_schedule_poll_timer();
|
||||
} while (flags & AP_POLL_IMMEDIATELY);
|
||||
if (flags & AP_POLL_AFTER_TIMEOUT)
|
||||
__ap_schedule_poll_timer();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,11 +32,13 @@
|
|||
|
||||
#define AP_DEVICES 64 /* Number of AP devices. */
|
||||
#define AP_DOMAINS 256 /* Number of AP domains. */
|
||||
#define AP_MAX_RESET 90 /* Maximum number of resets. */
|
||||
#define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */
|
||||
#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */
|
||||
#define AP_POLL_TIME 1 /* Time in ticks between receive polls. */
|
||||
|
||||
#define AP_POLL_IMMEDIATELY 1 /* continue running poll tasklet */
|
||||
#define AP_POLL_AFTER_TIMEOUT 2 /* run poll tasklet again after timout */
|
||||
|
||||
extern int ap_domain_index;
|
||||
|
||||
/**
|
||||
|
@ -135,6 +137,14 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
|
|||
#define AP_RESET_IGNORE 0 /* request timeout will be ignored */
|
||||
#define AP_RESET_ARMED 1 /* request timeout timer is active */
|
||||
#define AP_RESET_DO 2 /* AP reset required */
|
||||
#define AP_RESET_IN_PROGRESS 3 /* AP reset in progress */
|
||||
|
||||
/*
|
||||
* AP interrupt states
|
||||
*/
|
||||
#define AP_INTR_DISABLED 0 /* AP interrupt disabled */
|
||||
#define AP_INTR_ENABLED 1 /* AP interrupt enabled */
|
||||
#define AP_INTR_IN_PROGRESS 3 /* AP interrupt in progress */
|
||||
|
||||
struct ap_device;
|
||||
struct ap_message;
|
||||
|
@ -168,6 +178,7 @@ struct ap_device {
|
|||
struct timer_list timeout; /* Timer for request timeouts. */
|
||||
int reset; /* Reset required after req. timeout. */
|
||||
|
||||
int interrupt; /* indicate if interrupts are enabled */
|
||||
int queue_count; /* # messages currently on AP queue. */
|
||||
|
||||
struct list_head pendingq; /* List of message sent to AP queue. */
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
* But the maximum time limit managed by the stomper code is set to 60sec.
|
||||
* Hence we have to wait at least that time period.
|
||||
*/
|
||||
#define CEX4_CLEANUP_TIME (61*HZ)
|
||||
#define CEX4_CLEANUP_TIME (900*HZ)
|
||||
|
||||
static struct ap_device_id zcrypt_cex4_ids[] = {
|
||||
{ AP_DEVICE(AP_DEVICE_TYPE_CEX4) },
|
||||
|
|
Загрузка…
Ссылка в новой задаче