Commit 124b4dcb authored by Dave Olson's avatar Dave Olson Committed by Roland Dreier
Browse files

IB/ipath: add calls to new 7220 code and enable in build



This patch adds the initialization calls into the new 7220 HCA files,
changes the Makefile to compile and link the new files, and code to
handle send DMA.
Signed-off-by: default avatarDave Olson <dave.olson@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent bb917144
......@@ -20,17 +20,20 @@ ib_ipath-y := \
ipath_qp.o \
ipath_rc.o \
ipath_ruc.o \
ipath_sdma.o \
ipath_srq.o \
ipath_stats.o \
ipath_sysfs.o \
ipath_uc.o \
ipath_ud.o \
ipath_user_pages.o \
ipath_user_sdma.o \
ipath_verbs_mcast.o \
ipath_verbs.o
ib_ipath-$(CONFIG_HT_IRQ) += ipath_iba6110.o
ib_ipath-$(CONFIG_PCI_MSI) += ipath_iba6120.o
ib_ipath-$(CONFIG_PCI_MSI) += ipath_iba7220.o ipath_sd7220.o ipath_sd7220_img.o
ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o
ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o
......@@ -447,8 +447,9 @@ struct ipath_user_info {
#define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */
#define IPATH_CMD_POLL_TYPE 28 /* set the kind of polling we want */
#define IPATH_CMD_ARMLAUNCH_CTRL 29 /* armlaunch detection control */
#define IPATH_CMD_MAX 29
/* 30 is unused */
#define IPATH_CMD_SDMA_INFLIGHT 31 /* sdma inflight counter request */
#define IPATH_CMD_SDMA_COMPLETE 32 /* sdma completion counter request */
/*
* Poll types
......@@ -486,6 +487,17 @@ struct ipath_cmd {
union {
struct ipath_tid_info tid_info;
struct ipath_user_info user_info;
/*
* address in userspace where we should put the sdma
* inflight counter
*/
__u64 sdma_inflight;
/*
* address in userspace where we should put the sdma
* completion counter
*/
__u64 sdma_complete;
/* address in userspace of struct ipath_port_info to
write result to */
__u64 port_info;
......
......@@ -129,8 +129,10 @@ static int __devinit ipath_init_one(struct pci_dev *,
/* Only needed for registration, nothing else needs this info */
#define PCI_VENDOR_ID_PATHSCALE 0x1fc1
#define PCI_VENDOR_ID_QLOGIC 0x1077
#define PCI_DEVICE_ID_INFINIPATH_HT 0xd
#define PCI_DEVICE_ID_INFINIPATH_PE800 0x10
#define PCI_DEVICE_ID_INFINIPATH_7220 0x7220
/* Number of seconds before our card status check... */
#define STATUS_TIMEOUT 60
......@@ -138,6 +140,7 @@ static int __devinit ipath_init_one(struct pci_dev *,
static const struct pci_device_id ipath_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) },
{ PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_INFINIPATH_7220) },
{ 0, }
};
......@@ -532,6 +535,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
"CONFIG_PCI_MSI is not enabled\n", ent->device);
return -ENODEV;
#endif
case PCI_DEVICE_ID_INFINIPATH_7220:
#ifndef CONFIG_PCI_MSI
ipath_dbg("CONFIG_PCI_MSI is not enabled, "
"using IntX for unit %u\n", dd->ipath_unit);
#endif
ipath_init_iba7220_funcs(dd);
break;
default:
ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
"failing\n", ent->device);
......@@ -887,13 +897,47 @@ int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs)
return (dd->ipath_flags & state) ? 0 : -ETIMEDOUT;
}
static void decode_sdma_errs(struct ipath_devdata *dd, ipath_err_t err,
char *buf, size_t blen)
{
static const struct {
ipath_err_t err;
const char *msg;
} errs[] = {
{ INFINIPATH_E_SDMAGENMISMATCH, "SDmaGenMismatch" },
{ INFINIPATH_E_SDMAOUTOFBOUND, "SDmaOutOfBound" },
{ INFINIPATH_E_SDMATAILOUTOFBOUND, "SDmaTailOutOfBound" },
{ INFINIPATH_E_SDMABASE, "SDmaBase" },
{ INFINIPATH_E_SDMA1STDESC, "SDma1stDesc" },
{ INFINIPATH_E_SDMARPYTAG, "SDmaRpyTag" },
{ INFINIPATH_E_SDMADWEN, "SDmaDwEn" },
{ INFINIPATH_E_SDMAMISSINGDW, "SDmaMissingDw" },
{ INFINIPATH_E_SDMAUNEXPDATA, "SDmaUnexpData" },
{ INFINIPATH_E_SDMADESCADDRMISALIGN, "SDmaDescAddrMisalign" },
{ INFINIPATH_E_SENDBUFMISUSE, "SendBufMisuse" },
{ INFINIPATH_E_SDMADISABLED, "SDmaDisabled" },
};
int i;
int expected;
size_t bidx = 0;
for (i = 0; i < ARRAY_SIZE(errs); i++) {
expected = (errs[i].err != INFINIPATH_E_SDMADISABLED) ? 0 :
test_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
if ((err & errs[i].err) && !expected)
bidx += snprintf(buf + bidx, blen - bidx,
"%s ", errs[i].msg);
}
}
/*
* Decode the error status into strings, deciding whether to always
* print * it or not depending on "normal packet errors" vs everything
* else. Return 1 if "real" errors, otherwise 0 if only packet
* errors, so caller can decide what to print with the string.
*/
int ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
int ipath_decode_err(struct ipath_devdata *dd, char *buf, size_t blen,
ipath_err_t err)
{
int iserr = 1;
*buf = '\0';
......@@ -975,6 +1019,8 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
strlcat(buf, "hardware ", blen);
if (err & INFINIPATH_E_RESET)
strlcat(buf, "reset ", blen);
if (err & INFINIPATH_E_SDMAERRS)
decode_sdma_errs(dd, err, buf, blen);
if (err & INFINIPATH_E_INVALIDEEPCMD)
strlcat(buf, "invalideepromcmd ", blen);
done:
......@@ -1730,30 +1776,80 @@ bail:
*/
void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
{
unsigned long flags;
if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) {
ipath_cdbg(VERBOSE, "Ignore while in autonegotiation\n");
goto bail;
}
/*
* If we have SDMA, and it's not disabled, we have to kick off the
* abort state machine, provided we aren't already aborting.
* If we are in the process of aborting SDMA (!DISABLED, but ABORTING),
* we skip the rest of this routine. It is already "in progress"
*/
if (dd->ipath_flags & IPATH_HAS_SEND_DMA) {
int skip_cancel;
u64 *statp = &dd->ipath_sdma_status;
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
skip_cancel =
!test_bit(IPATH_SDMA_DISABLED, statp) &&
test_and_set_bit(IPATH_SDMA_ABORTING, statp);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (skip_cancel)
goto bail;
}
ipath_dbg("Cancelling all in-progress send buffers\n");
/* skip armlaunch errs for a while */
dd->ipath_lastcancel = jiffies + HZ / 2;
/*
* the abort bit is auto-clearing. We read scratch to be sure
* that cancels and the abort have taken effect in the chip.
* The abort bit is auto-clearing. We also don't want pioavail
* update happening during this, and we don't want any other
* sends going out, so turn those off for the duration. We read
* the scratch register to be sure that cancels and the abort
* have taken effect in the chip. Otherwise two parts are same
* as ipath_force_pio_avail_update()
*/
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl &= ~(INFINIPATH_S_PIOBUFAVAILUPD
| INFINIPATH_S_PIOENABLE);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
INFINIPATH_S_ABORT);
dd->ipath_sendctrl | INFINIPATH_S_ABORT);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
/* disarm all send buffers */
ipath_disarm_piobufs(dd, 0,
(unsigned)(dd->ipath_piobcnt2k + dd->ipath_piobcnt4k));
if (restore_sendctrl) /* else done by caller later */
dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
if (restore_sendctrl) {
/* else done by caller later if needed */
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl |= INFINIPATH_S_PIOBUFAVAILUPD |
INFINIPATH_S_PIOENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
dd->ipath_sendctrl);
/* and again, be sure all have hit the chip */
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
}
/* and again, be sure all have hit the chip */
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
if ((dd->ipath_flags & IPATH_HAS_SEND_DMA) &&
!test_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status) &&
test_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status)) {
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
/* only wait so long for intr */
dd->ipath_sdma_abort_intr_timeout = jiffies + HZ;
dd->ipath_sdma_reset_wait = 200;
__set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
}
bail:;
}
......@@ -1952,7 +2048,7 @@ bail:
* sanity checking on this, and we don't deal with what happens to
* programs that are already running when the size changes.
* NOTE: changing the MTU will usually cause the IBC to go back to
* link initialize (IPATH_IBSTATE_INIT) state...
* link INIT state...
*/
int ipath_set_mtu(struct ipath_devdata *dd, u16 arg)
{
......@@ -2092,9 +2188,8 @@ static void ipath_run_led_override(unsigned long opaque)
* but leave that to per-chip functions.
*/
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
dd->ibcs_lts_mask;
lstate = (val >> dd->ibcs_ls_shift) & INFINIPATH_IBCS_LINKSTATE_MASK;
ltstate = ipath_ib_linktrstate(dd, val);
lstate = ipath_ib_linkstate(dd, val);
dd->ipath_f_setextled(dd, lstate, ltstate);
mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff);
......@@ -2170,6 +2265,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
teardown_sdma(dd);
/*
* gracefully stop all sends allowing any in progress to trickle out
* first.
......@@ -2187,9 +2285,16 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
*/
udelay(5);
dd->ipath_f_setextled(dd, 0, 0); /* make sure LEDs are off */
ipath_set_ib_lstate(dd, 0, INFINIPATH_IBCC_LINKINITCMD_DISABLE);
ipath_cancel_sends(dd, 0);
/*
* we are shutting down, so tell components that care. We don't do
* this on just a link state change, much like ethernet, a cable
* unplug, etc. doesn't change driver state
*/
signal_ib_event(dd, IB_EVENT_PORT_ERR);
/* disable IBC */
......@@ -2214,6 +2319,10 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
del_timer_sync(&dd->ipath_intrchk_timer);
dd->ipath_intrchk_timer.data = 0;
}
if (atomic_read(&dd->ipath_led_override_timer_active)) {
del_timer_sync(&dd->ipath_led_override_timer);
atomic_set(&dd->ipath_led_override_timer_active, 0);
}
/*
* clear all interrupts and errors, so that the next time the driver
......@@ -2408,13 +2517,18 @@ int ipath_reset_device(int unit)
}
}
if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
teardown_sdma(dd);
dd->ipath_flags &= ~IPATH_INITTED;
ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
ret = dd->ipath_f_reset(dd);
if (ret != 1)
ipath_dbg("reset was not successful\n");
ipath_dbg("Trying to reinitialize unit %u after reset attempt\n",
unit);
ret = ipath_init_chip(dd, 1);
if (ret == 1) {
ipath_dbg("Reinitializing unit %u after reset attempt\n",
unit);
ret = ipath_init_chip(dd, 1);
} else
ret = -EAGAIN;
if (ret)
ipath_dev_err(dd, "Reinitialize unit %u after "
"reset failed with %d\n", unit, ret);
......
......@@ -36,21 +36,28 @@
#include <linux/cdev.h>
#include <linux/swap.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <asm/pgtable.h>
#include "ipath_kernel.h"
#include "ipath_common.h"
#include "ipath_user_sdma.h"
static int ipath_open(struct inode *, struct file *);
static int ipath_close(struct inode *, struct file *);
static ssize_t ipath_write(struct file *, const char __user *, size_t,
loff_t *);
static ssize_t ipath_writev(struct kiocb *, const struct iovec *,
unsigned long , loff_t);
static unsigned int ipath_poll(struct file *, struct poll_table_struct *);
static int ipath_mmap(struct file *, struct vm_area_struct *);
static const struct file_operations ipath_file_ops = {
.owner = THIS_MODULE,
.write = ipath_write,
.aio_write = ipath_writev,
.open = ipath_open,
.release = ipath_close,
.poll = ipath_poll,
......@@ -1870,10 +1877,9 @@ static int ipath_assign_port(struct file *fp,
if (ipath_compatible_subports(swmajor, swminor) &&
uinfo->spu_subport_cnt &&
(ret = find_shared_port(fp, uinfo))) {
mutex_unlock(&ipath_mutex);
if (ret > 0)
ret = 0;
goto done;
goto done_chk_sdma;
}
i_minor = iminor(fp->f_path.dentry->d_inode) - IPATH_USER_MINOR_BASE;
......@@ -1885,6 +1891,21 @@ static int ipath_assign_port(struct file *fp,
else
ret = find_best_unit(fp, uinfo);
done_chk_sdma:
if (!ret) {
struct ipath_filedata *fd = fp->private_data;
const struct ipath_portdata *pd = fd->pd;
const struct ipath_devdata *dd = pd->port_dd;
fd->pq = ipath_user_sdma_queue_create(&dd->pcidev->dev,
dd->ipath_unit,
pd->port_port,
fd->subport);
if (!fd->pq)
ret = -ENOMEM;
}
mutex_unlock(&ipath_mutex);
done:
......@@ -2042,6 +2063,13 @@ static int ipath_close(struct inode *in, struct file *fp)
mutex_unlock(&ipath_mutex);
goto bail;
}
dd = pd->port_dd;
/* drain user sdma queue */
ipath_user_sdma_queue_drain(dd, fd->pq);
ipath_user_sdma_queue_destroy(fd->pq);
if (--pd->port_cnt) {
/*
* XXX If the master closes the port before the slave(s),
......@@ -2054,7 +2082,6 @@ static int ipath_close(struct inode *in, struct file *fp)
goto bail;
}
port = pd->port_port;
dd = pd->port_dd;
if (pd->port_hdrqfull) {
ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors "
......@@ -2176,6 +2203,35 @@ static int ipath_get_slave_info(struct ipath_portdata *pd,
return ret;
}
static int ipath_sdma_get_inflight(struct ipath_user_sdma_queue *pq,
u32 __user *inflightp)
{
const u32 val = ipath_user_sdma_inflight_counter(pq);
if (put_user(val, inflightp))
return -EFAULT;
return 0;
}
static int ipath_sdma_get_complete(struct ipath_devdata *dd,
struct ipath_user_sdma_queue *pq,
u32 __user *completep)
{
u32 val;
int err;
err = ipath_user_sdma_make_progress(dd, pq);
if (err < 0)
return err;
val = ipath_user_sdma_complete_counter(pq);
if (put_user(val, completep))
return -EFAULT;
return 0;
}
static ssize_t ipath_write(struct file *fp, const char __user *data,
size_t count, loff_t *off)
{
......@@ -2250,6 +2306,16 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
dest = &cmd.cmd.armlaunch_ctrl;
src = &ucmd->cmd.armlaunch_ctrl;
break;
case IPATH_CMD_SDMA_INFLIGHT:
copy = sizeof(cmd.cmd.sdma_inflight);
dest = &cmd.cmd.sdma_inflight;
src = &ucmd->cmd.sdma_inflight;
break;
case IPATH_CMD_SDMA_COMPLETE:
copy = sizeof(cmd.cmd.sdma_complete);
dest = &cmd.cmd.sdma_complete;
src = &ucmd->cmd.sdma_complete;
break;
default:
ret = -EINVAL;
goto bail;
......@@ -2331,6 +2397,17 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
else
ipath_disable_armlaunch(pd->port_dd);
break;
case IPATH_CMD_SDMA_INFLIGHT:
ret = ipath_sdma_get_inflight(user_sdma_queue_fp(fp),
(u32 __user *) (unsigned long)
cmd.cmd.sdma_inflight);
break;
case IPATH_CMD_SDMA_COMPLETE:
ret = ipath_sdma_get_complete(pd->port_dd,
user_sdma_queue_fp(fp),
(u32 __user *) (unsigned long)
cmd.cmd.sdma_complete);
break;
}
if (ret >= 0)
......@@ -2340,6 +2417,20 @@ bail:
return ret;
}
static ssize_t ipath_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long dim, loff_t off)
{
struct file *filp = iocb->ki_filp;
struct ipath_filedata *fp = filp->private_data;
struct ipath_portdata *pd = port_fp(filp);
struct ipath_user_sdma_queue *pq = fp->pq;
if (!dim)
return -EINVAL;
return ipath_user_sdma_writev(pd->port_dd, pq, iov, dim);
}
static struct class *ipath_class;
static int init_cdev(int minor, char *name, const struct file_operations *fops,
......
......@@ -980,6 +980,10 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
dd->ipath_stats_timer_active = 1;
}
/* Set up SendDMA if chip supports it */
if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
ret = setup_sdma(dd);
/* Set up HoL state */
init_timer(&dd->ipath_hol_timer);
dd->ipath_hol_timer.function = ipath_hol_event;
......
......@@ -433,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
| IPATH_LINKDOWN | IPATH_LINKARMED |
IPATH_NOCABLE);
if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
ipath_restart_sdma(dd);
signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
/* LED active not handled in chip _f_updown */
dd->ipath_f_setextled(dd, lstate, ltstate);
......@@ -480,7 +482,7 @@ done:
}
static void handle_supp_msgs(struct ipath_devdata *dd,
unsigned supp_msgs, char *msg, int msgsz)
unsigned supp_msgs, char *msg, u32 msgsz)
{
/*
* Print the message unless it's ibc status change only, which
......@@ -488,12 +490,19 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
*/
if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) {
int iserr;
iserr = ipath_decode_err(msg, msgsz,
ipath_err_t mask;
iserr = ipath_decode_err(dd, msg, msgsz,
dd->ipath_lasterror &
~INFINIPATH_E_IBSTATUSCHANGED);
if (dd->ipath_lasterror &
~(INFINIPATH_E_RRCVEGRFULL |
INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
mask = INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
INFINIPATH_E_PKTERRS | INFINIPATH_E_SDMADISABLED;
/* if we're in debug, then don't mask SDMADISABLED msgs */
if (ipath_debug & __IPATH_DBG)
mask &= ~INFINIPATH_E_SDMADISABLED;
if (dd->ipath_lasterror & ~mask)
ipath_dev_err(dd, "Suppressed %u messages for "
"fast-repeating errors (%s) (%llx)\n",
supp_msgs, msg,
......@@ -520,7 +529,7 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
static unsigned handle_frequent_errors(struct ipath_devdata *dd,
ipath_err_t errs, char *msg,
int msgsz, int *noprint)
u32 msgsz, int *noprint)
{
unsigned long nc;
static unsigned long nextmsg_time;
......@@ -550,19 +559,125 @@ static unsigned handle_frequent_errors(struct ipath_devdata *dd,
return supp_msgs;
}
static void handle_sdma_errors(struct ipath_devdata *dd, ipath_err_t errs)
{
unsigned long flags;
int expected;
if (ipath_debug & __IPATH_DBG) {
char msg[128];
ipath_decode_err(dd, msg, sizeof msg, errs &
INFINIPATH_E_SDMAERRS);
ipath_dbg("errors %lx (%s)\n", (unsigned long)errs, msg);
}
if (ipath_debug & __IPATH_VERBDBG) {
unsigned long tl, hd, status, lengen;
tl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmatail);
hd = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmahead);
status = ipath_read_kreg64(dd
, dd->ipath_kregs->kr_senddmastatus);
lengen = ipath_read_kreg64(dd,
dd->ipath_kregs->kr_senddmalengen);
ipath_cdbg(VERBOSE, "sdma tl 0x%lx hd 0x%lx status 0x%lx "
"lengen 0x%lx\n", tl, hd, status, lengen);
}
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
__set_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
expected = test_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (!expected)
ipath_cancel_sends(dd, 1);
}
static void handle_sdma_intr(struct ipath_devdata *dd, u64 istat)
{
unsigned long flags;
int expected;
if ((istat & INFINIPATH_I_SDMAINT) &&
!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
ipath_sdma_intr(dd);
if (istat & INFINIPATH_I_SDMADISABLED) {
expected = test_bit(IPATH_SDMA_ABORTING,
&dd->ipath_sdma_status);
ipath_dbg("%s SDmaDisabled intr\n",
expected ? "expected" : "unexpected");
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
__set_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (!expected)
ipath_cancel_sends(dd, 1);
if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
}
}