Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 495c0217 authored by Mahesh Rajashekhara's avatar Mahesh Rajashekhara Committed by James Bottomley
Browse files

aacraid: MSI-x support

parent b836439f
Loading
Loading
Loading
Loading
+73 −7
Original line number Diff line number Diff line
@@ -6,11 +6,61 @@
#define nblank(x) _nblank(x)[0]

#include <linux/interrupt.h>
#include <linux/pci.h>

/*------------------------------------------------------------------------------
 *              D E F I N E S
 *----------------------------------------------------------------------------*/

#define AAC_MAX_MSIX		32	/* vectors */
#define AAC_PCI_MSI_ENABLE	0x8000

enum {
	AAC_ENABLE_INTERRUPT	= 0x0,
	AAC_DISABLE_INTERRUPT,
	AAC_ENABLE_MSIX,
	AAC_DISABLE_MSIX,
	AAC_CLEAR_AIF_BIT,
	AAC_CLEAR_SYNC_BIT,
	AAC_ENABLE_INTX
};

#define AAC_INT_MODE_INTX		(1<<0)
#define AAC_INT_MODE_MSI		(1<<1)
#define AAC_INT_MODE_AIF		(1<<2)
#define AAC_INT_MODE_SYNC		(1<<3)

#define AAC_INT_ENABLE_TYPE1_INTX	0xfffffffb
#define AAC_INT_ENABLE_TYPE1_MSIX	0xfffffffa
#define AAC_INT_DISABLE_ALL		0xffffffff

/* Bit definitions in IOA->Host Interrupt Register */
#define PMC_TRANSITION_TO_OPERATIONAL	(1<<31)
#define PMC_IOARCB_TRANSFER_FAILED	(1<<28)
#define PMC_IOA_UNIT_CHECK		(1<<27)
#define PMC_NO_HOST_RRQ_FOR_CMD_RESPONSE (1<<26)
#define PMC_CRITICAL_IOA_OP_IN_PROGRESS	(1<<25)
#define PMC_IOARRIN_LOST		(1<<4)
#define PMC_SYSTEM_BUS_MMIO_ERROR	(1<<3)
#define PMC_IOA_PROCESSOR_IN_ERROR_STATE (1<<2)
#define PMC_HOST_RRQ_VALID		(1<<1)
#define PMC_OPERATIONAL_STATUS		(1<<31)
#define PMC_ALLOW_MSIX_VECTOR0		(1<<0)

#define PMC_IOA_ERROR_INTERRUPTS	(PMC_IOARCB_TRANSFER_FAILED | \
					 PMC_IOA_UNIT_CHECK | \
					 PMC_NO_HOST_RRQ_FOR_CMD_RESPONSE | \
					 PMC_IOARRIN_LOST | \
					 PMC_SYSTEM_BUS_MMIO_ERROR | \
					 PMC_IOA_PROCESSOR_IN_ERROR_STATE)

#define PMC_ALL_INTERRUPT_BITS		(PMC_IOA_ERROR_INTERRUPTS | \
					 PMC_HOST_RRQ_VALID | \
					 PMC_TRANSITION_TO_OPERATIONAL | \
					 PMC_ALLOW_MSIX_VECTOR0)
#define	PMC_GLOBAL_INT_BIT2		0x00000004
#define	PMC_GLOBAL_INT_BIT0		0x00000001

#ifndef AAC_DRIVER_BUILD
# define AAC_DRIVER_BUILD 30300
# define AAC_DRIVER_BRANCH "-ms"
@@ -36,6 +86,7 @@
#define CONTAINER_TO_ID(cont)		(cont)
#define CONTAINER_TO_LUN(cont)		(0)

#define PMC_DEVICE_S6	0x28b
#define PMC_DEVICE_S7	0x28c
#define PMC_DEVICE_S8	0x28d
#define PMC_DEVICE_S9	0x28f
@@ -434,7 +485,7 @@ enum fib_xfer_state {
struct aac_init
{
	__le32	InitStructRevision;
	__le32	MiniPortRevision;
	__le32	Sa_MSIXVectors;
	__le32	fsrev;
	__le32	CommHeaderAddress;
	__le32	FastIoCommAreaAddress;
@@ -755,7 +806,8 @@ struct rkt_registers {

struct src_mu_registers {
				/*	PCI*| Name */
	__le32	reserved0[8];	/*	00h | Reserved */
	__le32	reserved0[6];	/*	00h | Reserved */
	__le32	IOAR[2];	/*	18h | IOA->host interrupt register */
	__le32	IDR;		/*	20h | Inbound Doorbell Register */
	__le32	IISR;		/*	24h | Inbound Int. Status Register */
	__le32	reserved1[3];	/*	28h | Reserved */
@@ -767,17 +819,18 @@ struct src_mu_registers {
	__le32	OMR;		/*	bch | Outbound Message Register */
	__le32	IQ_L;		/*  c0h | Inbound Queue (Low address) */
	__le32	IQ_H;		/*  c4h | Inbound Queue (High address) */
	__le32	ODR_MSI;	/*  c8h | MSI register for sync./AIF */
};

struct src_registers {
	struct src_mu_registers MUnit;	/* 00h - c7h */
	struct src_mu_registers MUnit;	/* 00h - cbh */
	union {
		struct {
			__le32 reserved1[130790];	/* c8h - 7fc5fh */
			__le32 reserved1[130789];	/* cch - 7fc5fh */
			struct src_inbound IndexRegs;	/* 7fc60h */
		} tupelo;
		struct {
			__le32 reserved1[974];		/* c8h - fffh */
			__le32 reserved1[973];		/* cch - fffh */
			struct src_inbound IndexRegs;	/* 1000h */
		} denali;
	} u;
@@ -1029,6 +1082,11 @@ struct aac_bus_info_response {
#define AAC_OPT_NEW_COMM_TYPE3		cpu_to_le32(1<<30)
#define AAC_OPT_NEW_COMM_TYPE4		cpu_to_le32(1<<31)

/* MSIX context */
struct aac_msix_ctx {
	int		vector_no;
	struct aac_dev	*dev;
};

struct aac_dev
{
@@ -1084,8 +1142,10 @@ struct aac_dev
						 * if AAC_COMM_MESSAGE_TYPE1 */

	dma_addr_t		host_rrq_pa;	/* phys. address */
	u32			host_rrq_idx;	/* index into rrq buffer */

	/* index into rrq buffer */
	u32			host_rrq_idx[AAC_MAX_MSIX];
	atomic_t		rrq_outstanding[AAC_MAX_MSIX];
	u32			fibs_pushed_no;
	struct pci_dev		*pdev;		/* Our PCI interface */
	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
	void *			comm_addr;	/* Base address of Comm area */
@@ -1154,6 +1214,11 @@ struct aac_dev
	int			sync_mode;
	struct fib		*sync_fib;
	struct list_head	sync_fib_list;
	u32			max_msix;	/* max. MSI-X vectors */
	u32			vector_cap;	/* MSI-X vector capab.*/
	int			msi_enabled;	/* MSI/MSI-X enabled */
	struct msix_entry	msixentry[AAC_MAX_MSIX];
	struct aac_msix_ctx	aac_msix[AAC_MAX_MSIX]; /* context */
};

#define aac_adapter_interrupt(dev) \
@@ -2036,6 +2101,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
int aac_fib_complete(struct fib * context);
#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data)
struct aac_dev *aac_init_adapter(struct aac_dev *dev);
void aac_src_access_devreg(struct aac_dev *dev, int mode);
int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev);
int aac_scsi_cmd(struct scsi_cmnd *cmd);
+92 −3
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@

#include "aacraid.h"

static void aac_define_int_mode(struct aac_dev *dev);

struct aac_common aac_config = {
	.irq_mod = 1
};
@@ -91,7 +93,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
	init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
	if (dev->max_fib_size != sizeof(struct hw_fib))
		init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4);
	init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION);
	init->Sa_MSIXVectors = cpu_to_le32(Sa_MINIPORT_REVISION);
	init->fsrev = cpu_to_le32(dev->fsrev);

	/*
@@ -140,7 +142,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
			INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED);
		init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32));
		init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff));
		init->MiniPortRevision = cpu_to_le32(0L);		/* number of MSI-X */
		/* number of MSI-X */
		init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
		dprintk((KERN_WARNING"aacraid: New Comm Interface type2 enabled\n"));
	}

@@ -228,6 +231,11 @@ int aac_send_shutdown(struct aac_dev * dev)
	/* FIB should be freed only after getting the response from the F/W */
	if (status != -ERESTARTSYS)
		aac_fib_free(fibctx);
	if ((dev->pdev->device == PMC_DEVICE_S7 ||
	     dev->pdev->device == PMC_DEVICE_S8 ||
	     dev->pdev->device == PMC_DEVICE_S9) &&
	     dev->msi_enabled)
		aac_src_access_devreg(dev, AAC_ENABLE_INTX);
	return status;
}

@@ -388,6 +396,8 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
			}
		}
	}
	dev->max_msix = 0;
	dev->msi_enabled = 0;
	if ((!aac_adapter_sync_cmd(dev, GET_COMM_PREFERRED_SETTINGS,
	  0, 0, 0, 0, 0, 0,
	  status+0, status+1, status+2, status+3, status+4))
@@ -461,6 +471,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
	if (host->can_queue > AAC_NUM_IO_FIB)
		host->can_queue = AAC_NUM_IO_FIB;

	if (dev->pdev->device == PMC_DEVICE_S6 ||
	    dev->pdev->device == PMC_DEVICE_S7 ||
	    dev->pdev->device == PMC_DEVICE_S8 ||
	    dev->pdev->device == PMC_DEVICE_S9)
		aac_define_int_mode(dev);
	/*
	 *	Ok now init the communication subsystem
	 */
@@ -489,4 +504,78 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
	return dev;
}

static void aac_define_int_mode(struct aac_dev *dev)
{

	int i, msi_count;

	/* max. vectors from GET_COMM_PREFERRED_SETTINGS */
	if (dev->max_msix == 0 ||
	    dev->pdev->device == PMC_DEVICE_S6 ||
	    dev->sync_mode) {
		dev->max_msix = 1;
		dev->vector_cap =
			dev->scsi_host_ptr->can_queue +
			AAC_NUM_MGT_FIB;
		return;
	}

	msi_count = min(dev->max_msix,
		(unsigned int)num_online_cpus());

	dev->max_msix = msi_count;

	if (msi_count > AAC_MAX_MSIX)
		msi_count = AAC_MAX_MSIX;

	for (i = 0; i < msi_count; i++)
		dev->msixentry[i].entry = i;

	if (msi_count > 1 &&
	    pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) {
		i = pci_enable_msix(dev->pdev,
				    dev->msixentry,
				    msi_count);
		 /* Check how many MSIX vectors are allocated */
		if (i >= 0) {
			dev->msi_enabled = 1;
			if (i) {
				msi_count = i;
				if (pci_enable_msix(dev->pdev,
				    dev->msixentry,
				    msi_count)) {
					dev->msi_enabled = 0;
					printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
							dev->name, dev->id, i);
				}
			}
		} else {
			dev->msi_enabled = 0;
			printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
					dev->name, dev->id, i);
		}
	}

	if (!dev->msi_enabled) {
		msi_count = 1;
		i = pci_enable_msi(dev->pdev);

		if (!i) {
			dev->msi_enabled = 1;
			dev->msi = 1;
		} else {
			printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n",
					dev->name, dev->id, i);
		}
	}

	if (!dev->msi_enabled)
		dev->max_msix = msi_count = 1;
	else {
		if (dev->max_msix > msi_count)
			dev->max_msix = msi_count;
	}
	dev->vector_cap =
		(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) /
		msi_count;
}
+17 −3
Original line number Diff line number Diff line
@@ -868,7 +868,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
 *	dispatches it to the appropriate routine for handling.
 */

#define AIF_SNIFF_TIMEOUT	(30*HZ)
#define AIF_SNIFF_TIMEOUT	(500*HZ)
static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
{
	struct hw_fib * hw_fib = fibptr->hw_fib_va;
@@ -1251,7 +1251,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
{
	int index, quirks;
	int retval;
	int retval, i;
	struct Scsi_Host *host;
	struct scsi_device *dev;
	struct scsi_cmnd *command;
@@ -1319,7 +1319,21 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
	aac->comm_phys = 0;
	kfree(aac->queues);
	aac->queues = NULL;
	if (aac->pdev->device == PMC_DEVICE_S6 ||
	    aac->pdev->device == PMC_DEVICE_S7 ||
	    aac->pdev->device == PMC_DEVICE_S8 ||
	    aac->pdev->device == PMC_DEVICE_S9) {
		if (aac->max_msix > 1) {
			for (i = 0; i < aac->max_msix; i++)
				free_irq(aac->msixentry[i].vector,
					 &(aac->aac_msix[i]));
			pci_disable_msix(aac->pdev);
		} else {
			free_irq(aac->pdev->irq, &(aac->aac_msix[0]));
		}
	} else {
		free_irq(aac->pdev->irq, aac);
	}
	if (aac->msi)
		pci_disable_msi(aac->pdev);
	kfree(aac->fsa_dev);
+7 −2
Original line number Diff line number Diff line
@@ -389,8 +389,13 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
			 *	NOTE:  we cannot touch the fib after this
			 *	    call, because it may have been deallocated.
			 */
			if (likely(fib->callback && fib->callback_data)) {
				fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
				fib->callback(fib->callback_data, fib);
			} else {
				aac_fib_complete(fib);
				aac_fib_free(fib);
			}
		} else {
			unsigned long flagv;
	  		dprintk((KERN_INFO "event_wait up\n"));
+19 −1
Original line number Diff line number Diff line
@@ -1082,6 +1082,8 @@ static struct scsi_host_template aac_driver_template = {

static void __aac_shutdown(struct aac_dev * aac)
{
	int i;

	if (aac->aif_thread) {
		int i;
		/* Clear out events first */
@@ -1095,9 +1097,25 @@ static void __aac_shutdown(struct aac_dev * aac)
	}
	aac_send_shutdown(aac);
	aac_adapter_disable_int(aac);
	if (aac->pdev->device == PMC_DEVICE_S6 ||
	    aac->pdev->device == PMC_DEVICE_S7 ||
	    aac->pdev->device == PMC_DEVICE_S8 ||
	    aac->pdev->device == PMC_DEVICE_S9) {
		if (aac->max_msix > 1) {
			for (i = 0; i < aac->max_msix; i++)
				free_irq(aac->msixentry[i].vector,
					 &(aac->aac_msix[i]));
		} else {
			free_irq(aac->pdev->irq,
				 &(aac->aac_msix[0]));
		}
	} else {
		free_irq(aac->pdev->irq, aac);
	}
	if (aac->msi)
		pci_disable_msi(aac->pdev);
	else if (aac->max_msix > 1)
		pci_disable_msix(aac->pdev);
}

static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
Loading