/**
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Device Driver Control Block (DDCB) queue support. Definition of
* interrupt handlers for queue support as well as triggering the
* health monitor code in case of problems. The current hardware uses
* an MSI interrupt which is shared between error handling and
* functional code.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/crc-itu-t.h>
#include "card_base.h"
#include "card_ddcb.h"
/*
* N: next DDCB, this is where the next DDCB will be put.
* A: active DDCB, this is where the code will look for the next completion.
* x: DDCB is enqueued, we are waiting for its completion.
* Situation (1): Empty queue
* +---+---+---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
* | | | | | | | | |
* +---+---+---+---+---+---+---+---+
* A/N
* enqueued_ddcbs = A - N = 2 - 2 = 0
*
* Situation (2): Wrapped, N > A
* +---+---+---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
* | | | x | x | | | | |
* +---+---+---+---+---+---+---+---+
* A N
* enqueued_ddcbs = N - A = 4 - 2 = 2
*
* Situation (3): Queue wrapped, A > N
* +---+---+---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
* | x | x | | | x | x | x | x |
* +---+---+---+---+---+---+---+---+
* N A
* enqueued_ddcbs = queue_max - (A - N) = 8 - (4 - 2) = 6
*
* Situation (4a): Queue full N > A
* +---+---+---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
* | x | x | x | x | x | x | x | |
* +---+---+---+---+---+---+---+---+
* A N
*
* enqueued_ddcbs = N - A = 7 - 0 = 7
*
* Situation (4a): Queue full A > N
* +---+---+---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
* | x | x | x | | x | x | x | x |
* +---+---+---+---+---+---+---+---+
* N A
* enqueued_ddcbs = queue_max - (A - N) = 8 - (4 - 3) = 7
*/
static int queue_empty(struct ddcb_queue *queue)
{
return queue->ddcb_next == queue->ddcb_act;
}
static int queue_enqueued_ddcbs(struct ddcb_queue *queue)
{
if (queue->ddcb_next >= queue->ddcb_act)
return queue->ddcb_next - queue->ddcb_act;
return queue->ddcb_max