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

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 := \ ...@@ -20,17 +20,20 @@ ib_ipath-y := \
ipath_qp.o \ ipath_qp.o \
ipath_rc.o \ ipath_rc.o \
ipath_ruc.o \ ipath_ruc.o \
ipath_sdma.o \
ipath_srq.o \ ipath_srq.o \
ipath_stats.o \ ipath_stats.o \
ipath_sysfs.o \ ipath_sysfs.o \
ipath_uc.o \ ipath_uc.o \
ipath_ud.o \ ipath_ud.o \
ipath_user_pages.o \ ipath_user_pages.o \
ipath_user_sdma.o \
ipath_verbs_mcast.o \ ipath_verbs_mcast.o \
ipath_verbs.o ipath_verbs.o
ib_ipath-$(CONFIG_HT_IRQ) += ipath_iba6110.o ib_ipath-$(CONFIG_HT_IRQ) += ipath_iba6110.o
ib_ipath-$(CONFIG_PCI_MSI) += ipath_iba6120.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_X86_64) += ipath_wc_x86_64.o
ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o
...@@ -447,8 +447,9 @@ struct ipath_user_info { ...@@ -447,8 +447,9 @@ struct ipath_user_info {
#define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */ #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_POLL_TYPE 28 /* set the kind of polling we want */
#define IPATH_CMD_ARMLAUNCH_CTRL 29 /* armlaunch detection control */ #define IPATH_CMD_ARMLAUNCH_CTRL 29 /* armlaunch detection control */
/* 30 is unused */
#define IPATH_CMD_MAX 29 #define IPATH_CMD_SDMA_INFLIGHT 31 /* sdma inflight counter request */
#define IPATH_CMD_SDMA_COMPLETE 32 /* sdma completion counter request */
/* /*
* Poll types * Poll types
...@@ -486,6 +487,17 @@ struct ipath_cmd { ...@@ -486,6 +487,17 @@ struct ipath_cmd {
union { union {
struct ipath_tid_info tid_info; struct ipath_tid_info tid_info;
struct ipath_user_info user_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 /* address in userspace of struct ipath_port_info to
write result to */ write result to */
__u64 port_info; __u64 port_info;
......
...@@ -129,8 +129,10 @@ static int __devinit ipath_init_one(struct pci_dev *, ...@@ -129,8 +129,10 @@ static int __devinit ipath_init_one(struct pci_dev *,
/* Only needed for registration, nothing else needs this info */ /* Only needed for registration, nothing else needs this info */
#define PCI_VENDOR_ID_PATHSCALE 0x1fc1 #define PCI_VENDOR_ID_PATHSCALE 0x1fc1
#define PCI_VENDOR_ID_QLOGIC 0x1077
#define PCI_DEVICE_ID_INFINIPATH_HT 0xd #define PCI_DEVICE_ID_INFINIPATH_HT 0xd
#define PCI_DEVICE_ID_INFINIPATH_PE800 0x10 #define PCI_DEVICE_ID_INFINIPATH_PE800 0x10
#define PCI_DEVICE_ID_INFINIPATH_7220 0x7220
/* Number of seconds before our card status check... */ /* Number of seconds before our card status check... */
#define STATUS_TIMEOUT 60 #define STATUS_TIMEOUT 60
...@@ -138,6 +140,7 @@ static int __devinit ipath_init_one(struct pci_dev *, ...@@ -138,6 +140,7 @@ static int __devinit ipath_init_one(struct pci_dev *,
static const struct pci_device_id ipath_pci_tbl[] = { 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_HT) },
{ PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) }, { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_INFINIPATH_7220) },
{ 0, } { 0, }
}; };
...@@ -532,6 +535,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ...@@ -532,6 +535,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
"CONFIG_PCI_MSI is not enabled\n", ent->device); "CONFIG_PCI_MSI is not enabled\n", ent->device);
return -ENODEV; return -ENODEV;
#endif #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: default:
ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, " ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
"failing\n", ent->device); "failing\n", ent->device);
...@@ -887,13 +897,47 @@ int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs) ...@@ -887,13 +897,47 @@ int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs)
return (dd->ipath_flags & state) ? 0 : -ETIMEDOUT; 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 * Decode the error status into strings, deciding whether to always
* print * it or not depending on "normal packet errors" vs everything * print * it or not depending on "normal packet errors" vs everything
* else. Return 1 if "real" errors, otherwise 0 if only packet * else. Return 1 if "real" errors, otherwise 0 if only packet
* errors, so caller can decide what to print with the string. * 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; int iserr = 1;
*buf = '\0'; *buf = '\0';
...@@ -975,6 +1019,8 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err) ...@@ -975,6 +1019,8 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
strlcat(buf, "hardware ", blen); strlcat(buf, "hardware ", blen);
if (err & INFINIPATH_E_RESET) if (err & INFINIPATH_E_RESET)
strlcat(buf, "reset ", blen); strlcat(buf, "reset ", blen);
if (err & INFINIPATH_E_SDMAERRS)
decode_sdma_errs(dd, err, buf, blen);
if (err & INFINIPATH_E_INVALIDEEPCMD) if (err & INFINIPATH_E_INVALIDEEPCMD)
strlcat(buf, "invalideepromcmd ", blen); strlcat(buf, "invalideepromcmd ", blen);
done: done:
...@@ -1730,30 +1776,80 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd, ...@@ -1730,30 +1776,80 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
*/ */
void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
{ {
unsigned long flags;
if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) { if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) {
ipath_cdbg(VERBOSE, "Ignore while in autonegotiation\n"); ipath_cdbg(VERBOSE, "Ignore while in autonegotiation\n");
goto bail; 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"); ipath_dbg("Cancelling all in-progress send buffers\n");
/* skip armlaunch errs for a while */ /* skip armlaunch errs for a while */
dd->ipath_lastcancel = jiffies + HZ / 2; dd->ipath_lastcancel = jiffies + HZ / 2;
/* /*
* the abort bit is auto-clearing. We read scratch to be sure * The abort bit is auto-clearing. We also don't want pioavail
* that cancels and the abort have taken effect in the chip. * 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, 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); 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, ipath_disarm_piobufs(dd, 0,
(unsigned)(dd->ipath_piobcnt2k + dd->ipath_piobcnt4k)); dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
if (restore_sendctrl) /* else done by caller later */
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, 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 */ if ((dd->ipath_flags & IPATH_HAS_SEND_DMA) &&
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); !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:; bail:;
} }
...@@ -1952,7 +2048,7 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) ...@@ -1952,7 +2048,7 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
* sanity checking on this, and we don't deal with what happens to * sanity checking on this, and we don't deal with what happens to
* programs that are already running when the size changes. * programs that are already running when the size changes.
* NOTE: changing the MTU will usually cause the IBC to go back to * 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) int ipath_set_mtu(struct ipath_devdata *dd, u16 arg)
{ {
...@@ -2092,9 +2188,8 @@ static void ipath_run_led_override(unsigned long opaque) ...@@ -2092,9 +2188,8 @@ static void ipath_run_led_override(unsigned long opaque)
* but leave that to per-chip functions. * but leave that to per-chip functions.
*/ */
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus); val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & ltstate = ipath_ib_linktrstate(dd, val);
dd->ibcs_lts_mask; lstate = ipath_ib_linkstate(dd, val);
lstate = (val >> dd->ibcs_ls_shift) & INFINIPATH_IBCS_LINKSTATE_MASK;
dd->ipath_f_setextled(dd, lstate, ltstate); dd->ipath_f_setextled(dd, lstate, ltstate);
mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff); mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff);
...@@ -2170,6 +2265,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd) ...@@ -2170,6 +2265,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_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 * gracefully stop all sends allowing any in progress to trickle out
* first. * first.
...@@ -2187,9 +2285,16 @@ void ipath_shutdown_device(struct ipath_devdata *dd) ...@@ -2187,9 +2285,16 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
*/ */
udelay(5); 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_set_ib_lstate(dd, 0, INFINIPATH_IBCC_LINKINITCMD_DISABLE);
ipath_cancel_sends(dd, 0); 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); signal_ib_event(dd, IB_EVENT_PORT_ERR);
/* disable IBC */ /* disable IBC */
...@@ -2214,6 +2319,10 @@ void ipath_shutdown_device(struct ipath_devdata *dd) ...@@ -2214,6 +2319,10 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
del_timer_sync(&dd->ipath_intrchk_timer); del_timer_sync(&dd->ipath_intrchk_timer);
dd->ipath_intrchk_timer.data = 0; 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 * clear all interrupts and errors, so that the next time the driver
...@@ -2408,13 +2517,18 @@ int ipath_reset_device(int unit) ...@@ -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; dd->ipath_flags &= ~IPATH_INITTED;
ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
ret = dd->ipath_f_reset(dd); ret = dd->ipath_f_reset(dd);
if (ret != 1) if (ret == 1) {
ipath_dbg("reset was not successful\n"); ipath_dbg("Reinitializing unit %u after reset attempt\n",
ipath_dbg("Trying to reinitialize unit %u after reset attempt\n", unit);
unit); ret = ipath_init_chip(dd, 1);
ret = ipath_init_chip(dd, 1); } else
ret = -EAGAIN;
if (ret) if (ret)
ipath_dev_err(dd, "Reinitialize unit %u after " ipath_dev_err(dd, "Reinitialize unit %u after "
"reset failed with %d\n", unit, ret); "reset failed with %d\n", unit, ret);
......
...@@ -36,21 +36,28 @@ ...@@ -36,21 +36,28 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include "ipath_kernel.h" #include "ipath_kernel.h"
#include "ipath_common.h" #include "ipath_common.h"
#include "ipath_user_sdma.h"
static int ipath_open(struct inode *, struct file *); static int ipath_open(struct inode *, struct file *);
static int ipath_close(struct inode *, struct file *); static int ipath_close(struct inode *, struct file *);
static ssize_t ipath_write(struct file *, const char __user *, size_t, static ssize_t ipath_write(struct file *, const char __user *, size_t,
loff_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 unsigned int ipath_poll(struct file *, struct poll_table_struct *);
static int ipath_mmap(struct file *, struct vm_area_struct *); static int ipath_mmap(struct file *, struct vm_area_struct *);
static const struct file_operations ipath_file_ops = { static const struct file_operations ipath_file_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.write = ipath_write, .write = ipath_write,
.aio_write = ipath_writev,
.open = ipath_open, .open = ipath_open,
.release = ipath_close, .release = ipath_close,
.poll = ipath_poll, .poll = ipath_poll,
...@@ -1870,10 +1877,9 @@ static int ipath_assign_port(struct file *fp, ...@@ -1870,10 +1877,9 @@ static int ipath_assign_port(struct file *fp,
if (ipath_compatible_subports(swmajor, swminor) && if (ipath_compatible_subports(swmajor, swminor) &&
uinfo->spu_subport_cnt && uinfo->spu_subport_cnt &&
(ret = find_shared_port(fp, uinfo))) { (ret = find_shared_port(fp, uinfo))) {
mutex_unlock(&ipath_mutex);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
goto done; goto done_chk_sdma;
} }
i_minor = iminor(fp->f_path.dentry->d_inode) - IPATH_USER_MINOR_BASE; 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, ...@@ -1885,6 +1891,21 @@ static int ipath_assign_port(struct file *fp,
else else
ret = find_best_unit(fp, uinfo); 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); mutex_unlock(&ipath_mutex);
done: done:
...@@ -2042,6 +2063,13 @@ static int ipath_close(struct inode *in, struct file *fp) ...@@ -2042,6 +2063,13 @@ static int ipath_close(struct inode *in, struct file *fp)
mutex_unlock(&ipath_mutex); mutex_unlock(&ipath_mutex);
goto bail; 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) { if (--pd->port_cnt) {
/* /*
* XXX If the master closes the port before the slave(s), * 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) ...@@ -2054,7 +2082,6 @@ static int ipath_close(struct inode *in, struct file *fp)
goto bail; goto bail;
} }
port = pd->port_port; port = pd->port_port;
dd = pd->port_dd;
if (pd->port_hdrqfull) { if (pd->port_hdrqfull) {
ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors " ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors "
...@@ -2176,6 +2203,35 @@ static int ipath_get_slave_info(struct ipath_portdata *pd, ...@@ -2176,6 +2203,35 @@ static int ipath_get_slave_info(struct ipath_portdata *pd,
return ret; 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, static ssize_t ipath_write(struct file *fp, const char __user *data,
size_t count, loff_t *off) size_t count, loff_t *off)
{ {
...@@ -2250,6 +2306,16 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, ...@@ -2250,6 +2306,16 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
dest = &cmd.cmd.armlaunch_ctrl; dest = &cmd.cmd.armlaunch_ctrl;
src = &ucmd->cmd.armlaunch_ctrl; src = &ucmd->cmd.armlaunch_ctrl;
break; 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: default:
ret = -EINVAL; ret = -EINVAL;
goto bail; goto bail;
...@@ -2331,6 +2397,17 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, ...@@ -2331,6 +2397,17 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
else else
ipath_disable_armlaunch(pd->port_dd); ipath_disable_armlaunch(pd->port_dd);
break; 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) if (ret >= 0)
...@@ -2340,6 +2417,20 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, ...@@ -2340,6 +2417,20 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
return ret; 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 struct class *ipath_class;
static int init_cdev(int minor, char *name, const struct file_operations *fops, 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) ...@@ -980,6 +980,10 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
dd->ipath_stats_timer_active = 1; 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 */ /* Set up HoL state */
init_timer(&dd->ipath_hol_timer); init_timer(&dd->ipath_hol_timer);
dd->ipath_hol_timer.function = ipath_hol_event; dd->ipath_hol_timer.function = ipath_hol_event;
......
This diff is collapsed.
...@@ -871,7 +871,8 @@ struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t); ...@@ -871,7 +871,8 @@ struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t);
extern int ipath_diag_inuse; extern int ipath_diag_inuse;
irqreturn_t ipath_intr(int irq, void *devid); irqreturn_t ipath_intr(int irq, void *devid);
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);
#if __IPATH_INFO || __IPATH_DBG #if __IPATH_INFO || __IPATH_DBG
extern const char *ipath_ibcstatus_str[]; extern const char *ipath_ibcstatus_str[];
#endif #endif
...@@ -1026,6 +1027,7 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val); ...@@ -1026,6 +1027,7 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
/* send dma routines */ /* send dma routines */
int setup_sdma(struct ipath_devdata *); int setup_sdma(struct ipath_devdata *);
void teardown_sdma(struct ipath_devdata *); void teardown_sdma(struct ipath_devdata *);
void ipath_restart_sdma(struct ipath_devdata *);
void ipath_sdma_intr(struct ipath_devdata *); void ipath_sdma_intr(struct ipath_devdata *);
int ipath_sdma_verbs_send(struct ipath_devdata *, struct ipath_sge_state *, int ipath_sdma_verbs_send(struct ipath_devdata *, struct ipath_sge_state *,
u32, struct ipath_verbs_txreq *); u32, struct ipath_verbs_txreq *);
......
...@@ -340,6 +340,7 @@ static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type) ...@@ -340,6 +340,7 @@ static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type)
qp->s_flags &= IPATH_S_SIGNAL_REQ_WR; qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
qp->s_hdrwords = 0; qp->s_hdrwords = 0;
qp->s_wqe = NULL; qp->s_wqe = NULL;
qp->s_pkt_delay = 0;
qp->s_psn = 0; qp->s_psn = 0;
qp->r_psn = 0; qp->r_psn = 0;
qp->r_msn = 0; qp->r_msn = 0;
...@@ -563,8 +564,10 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -563,8 +564,10 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (attr_mask & IB_QP_ACCESS_FLAGS) if (attr_mask & IB_QP_ACCESS_FLAGS)
qp->qp_access_flags = attr->qp_access_flags; qp->qp_access_flags = attr->qp_access_flags;
if (attr_mask & IB_QP_AV) if (attr_mask & IB_QP_AV) {
qp->remote_ah_attr = attr->ah_attr; qp->remote_ah_attr = attr->ah_attr;
qp->s_dmult = ipath_ib_rate_to_mult(attr->ah_attr.static_rate);
}
if (attr_mask & IB_QP_PATH_MTU) if (attr_mask & IB_QP_PATH_MTU)
qp->path_mtu = attr->path_mtu; qp->path_mtu = attr->path_mtu;
...@@ -850,6 +853,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, ...@@ -850,6 +853,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
goto bail_qp; goto bail_qp;
} }
qp->ip = NULL; qp->ip = NULL;
qp->s_tx = NULL;
ipath_reset_qp(qp, init_attr->qp_type); ipath_reset_qp(qp, init_attr->qp_type);
break; break;
...@@ -955,12 +959,20 @@ int ipath_destroy_qp(struct ib_qp *ibqp) ...@@ -955,12 +959,20 @@ int ipath_destroy_qp(struct ib_qp *ibqp)
/* Stop the sending tasklet. */ /* Stop the sending tasklet. */
tasklet_kill(&qp->s_task); tasklet_kill(&qp->s_task);
if (qp->s_tx) {
atomic_dec(&qp->refcount);
if (qp->s_tx->txreq.flags & IPATH_SDMA_TXREQ_F_FREEBUF)
kfree(qp->s_tx->txreq.map_addr);
}
/* Make sure the QP isn't on the timeout list. */ /* Make sure the QP isn't on the timeout list. */
spin_lock_irqsave(&dev->pending_lock, flags); spin_lock_irqsave(&dev->pending_lock, flags);
if (!list_empty(&qp->timerwait)) if (!list_empty(&qp->timerwait))
list_del_init(&qp->timerwait); list_del_init(&qp->timerwait);
if (!list_empty(&qp->piowait)) if (!list_empty(&qp->piowait))
list_del_init(&qp->piowait); list_del_init(&qp->piowait);
if (qp->s_tx)
list_add(&qp->s_tx->txreq.list, &dev->txreq_free);
spin_unlock_irqrestore(&dev->pending_lock, flags); spin_unlock_irqrestore(&dev->pending_lock, flags);
/* /*
......
...@@ -483,14 +483,16 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) ...@@ -483,14 +483,16 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp)
static void want_buffer(struct ipath_devdata *dd) static void want_buffer(struct ipath_devdata *dd)
{ {
unsigned long flags; if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA)) {
unsigned long flags;
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL; spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); dd->ipath_sendctrl);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
}
} }
/** /**
......
...@@ -230,7 +230,6 @@ static void dump_sdma_state(struct ipath_devdata *dd) ...@@ -230,7 +230,6 @@ static void dump_sdma_state(struct ipath_devdata *dd)
static void sdma_abort_task(unsigned long opaque) static void sdma_abort_task(unsigned long opaque)
{ {
struct ipath_devdata *dd = (struct ipath_devdata *) opaque; struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
int kick = 0;
u64 status; u64 status;
unsigned long flags; unsigned long flags;
...@@ -308,30 +307,26 @@ static void sdma_abort_task(unsigned long opaque) ...@@ -308,30 +307,26 @@ static void sdma_abort_task(unsigned long opaque)
/* done with sdma state for a bit */ /* done with sdma state for a bit */
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
/* restart sdma engine */ /*
* Don't restart sdma here. Wait until link is up to ACTIVE.
* VL15 MADs used to bring the link up use PIO, and multiple
* link transitions otherwise cause the sdma engine to be
* stopped and started multiple times.
* The disable is done here, including the shadow, so the
* state is kept consistent.
* See ipath_restart_sdma() for the actual starting of sdma.
*/
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE; dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl); dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
dd->ipath_sendctrl |= INFINIPATH_S_SDMAENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
kick = 1;
ipath_dbg("sdma restarted from abort\n");
/* now clear status bits */
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
__clear_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
__clear_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
__clear_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
/* make sure I see next message */ /* make sure I see next message */
dd->ipath_sdma_abort_jiffies = 0; dd->ipath_sdma_abort_jiffies = 0;
goto unlock; goto done;
} }
resched: resched:
...@@ -353,10 +348,8 @@ static void sdma_abort_task(unsigned long opaque) ...@@ -353,10 +348,8 @@ static void sdma_abort_task(unsigned long opaque)
unlock: unlock:
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
done:
/* kick upper layers */ return;
if (kick)
ipath_ib_piobufavail(dd->verbs_dev);
} }
/* /*
...@@ -481,10 +474,14 @@ int setup_sdma(struct ipath_devdata *dd) ...@@ -481,10 +474,14 @@ int setup_sdma(struct ipath_devdata *dd)
tasklet_init(&dd->ipath_sdma_abort_task, sdma_abort_task, tasklet_init(&dd->ipath_sdma_abort_task, sdma_abort_task,
(unsigned long) dd); (unsigned long) dd);
/* Turn on SDMA */ /*
* No use to turn on SDMA here, as link is probably not ACTIVE
* Just mark it RUNNING and enable the interrupt, and let the
* ipath_restart_sdma() on link transition to ACTIVE actually
* enable it.
*/
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl |= INFINIPATH_S_SDMAENABLE | dd->ipath_sendctrl |= INFINIPATH_S_SDMAINTENABLE;
INFINIPATH_S_SDMAINTENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
__set_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status); __set_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status);
...@@ -572,6 +569,56 @@ void teardown_sdma(struct ipath_devdata *dd) ...@@ -572,6 +569,56 @@ void teardown_sdma(struct ipath_devdata *dd)
sdma_descq, sdma_descq_phys); sdma_descq, sdma_descq_phys);
} }
/*
* [Re]start SDMA, if we use it, and it's not already OK.
* This is called on transition to link ACTIVE, either the first or
* subsequent times.
*/
void ipath_restart_sdma(struct ipath_devdata *dd)
{
unsigned long flags;
int needed = 1;
if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA))
goto bail;
/*
* First, make sure we should, which is to say,
* check that we are "RUNNING" (not in teardown)
* and not "SHUTDOWN"
*/
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
if (!test_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status)
|| test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
needed = 0;
else {
__clear_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
__clear_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
__clear_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
}
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (!needed) {
ipath_dbg("invalid attempt to restart SDMA, status 0x%016llx\n",
dd->ipath_sdma_status);
goto bail;
}
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
/*
* First clear, just to be safe. Enable is only done
* in chip on 0->1 transition
*/
dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
dd->ipath_sendctrl |= INFINIPATH_S_SDMAENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
bail:
return;
}
static inline void make_sdma_desc(struct ipath_devdata *dd, static inline void make_sdma_desc(struct ipath_devdata *dd,
u64 *sdmadesc, u64 addr, u64 dwlen, u64 dwoffset) u64 *sdmadesc, u64 addr, u64 dwlen, u64 dwoffset)
{ {
......
...@@ -292,8 +292,8 @@ void ipath_get_faststats(unsigned long opaque) ...@@ -292,8 +292,8 @@ void ipath_get_faststats(unsigned long opaque)
&& time_after(jiffies, dd->ipath_unmasktime)) { && time_after(jiffies, dd->ipath_unmasktime)) {
char ebuf[256]; char ebuf[256];
int iserr; int iserr;
iserr = ipath_decode_err(ebuf, sizeof ebuf, iserr = ipath_decode_err(dd, ebuf, sizeof ebuf,
dd->ipath_maskederrs); dd->ipath_maskederrs);
if (dd->ipath_maskederrs & if (dd->ipath_maskederrs &
~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL | ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
INFINIPATH_E_PKTERRS)) INFINIPATH_E_PKTERRS))
......
...@@ -303,6 +303,7 @@ int ipath_make_ud_req(struct ipath_qp *qp) ...@@ -303,6 +303,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
qp->s_hdrwords = 7; qp->s_hdrwords = 7;
qp->s_cur_size = wqe->length; qp->s_cur_size = wqe->length;
qp->s_cur_sge = &qp->s_sge; qp->s_cur_sge = &qp->s_sge;
qp->s_dmult = ah_attr->static_rate;
qp->s_wqe = wqe; qp->s_wqe = wqe;
qp->s_sge.sge = wqe->sg_list[0]; qp->s_sge.sge = wqe->sg_list[0];
qp->s_sge.sg_list = wqe->sg_list + 1; qp->s_sge.sg_list = wqe->sg_list + 1;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment