linux/drivers/infiniband/hw/qib/qib_intr.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
   3 * All rights reserved.
   4 * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
   5 *
   6 * This software is available to you under a choice of one of two
   7 * licenses.  You may choose to be licensed under the terms of the GNU
   8 * General Public License (GPL) Version 2, available from the file
   9 * COPYING in the main directory of this source tree, or the
  10 * OpenIB.org BSD license below:
  11 *
  12 *     Redistribution and use in source and binary forms, with or
  13 *     without modification, are permitted provided that the following
  14 *     conditions are met:
  15 *
  16 *      - Redistributions of source code must retain the above
  17 *        copyright notice, this list of conditions and the following
  18 *        disclaimer.
  19 *
  20 *      - Redistributions in binary form must reproduce the above
  21 *        copyright notice, this list of conditions and the following
  22 *        disclaimer in the documentation and/or other materials
  23 *        provided with the distribution.
  24 *
  25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  32 * SOFTWARE.
  33 */
  34
  35#include <linux/pci.h>
  36#include <linux/delay.h>
  37
  38#include "qib.h"
  39#include "qib_common.h"
  40
  41/**
  42 * qib_format_hwmsg - format a single hwerror message
  43 * @msg message buffer
  44 * @msgl length of message buffer
  45 * @hwmsg message to add to message buffer
  46 */
  47static void qib_format_hwmsg(char *msg, size_t msgl, const char *hwmsg)
  48{
  49        strlcat(msg, "[", msgl);
  50        strlcat(msg, hwmsg, msgl);
  51        strlcat(msg, "]", msgl);
  52}
  53
  54/**
  55 * qib_format_hwerrors - format hardware error messages for display
  56 * @hwerrs hardware errors bit vector
  57 * @hwerrmsgs hardware error descriptions
  58 * @nhwerrmsgs number of hwerrmsgs
  59 * @msg message buffer
  60 * @msgl message buffer length
  61 */
  62void qib_format_hwerrors(u64 hwerrs, const struct qib_hwerror_msgs *hwerrmsgs,
  63                         size_t nhwerrmsgs, char *msg, size_t msgl)
  64{
  65        int i;
  66
  67        for (i = 0; i < nhwerrmsgs; i++)
  68                if (hwerrs & hwerrmsgs[i].mask)
  69                        qib_format_hwmsg(msg, msgl, hwerrmsgs[i].msg);
  70}
  71
  72static void signal_ib_event(struct qib_pportdata *ppd, enum ib_event_type ev)
  73{
  74        struct ib_event event;
  75        struct qib_devdata *dd = ppd->dd;
  76
  77        event.device = &dd->verbs_dev.rdi.ibdev;
  78        event.element.port_num = ppd->port;
  79        event.event = ev;
  80        ib_dispatch_event(&event);
  81}
  82
  83void qib_handle_e_ibstatuschanged(struct qib_pportdata *ppd, u64 ibcs)
  84{
  85        struct qib_devdata *dd = ppd->dd;
  86        unsigned long flags;
  87        u32 lstate;
  88        u8 ltstate;
  89        enum ib_event_type ev = 0;
  90
  91        lstate = dd->f_iblink_state(ibcs); /* linkstate */
  92        ltstate = dd->f_ibphys_portstate(ibcs);
  93
  94        /*
  95         * If linkstate transitions into INIT from any of the various down
  96         * states, or if it transitions from any of the up (INIT or better)
  97         * states into any of the down states (except link recovery), then
  98         * call the chip-specific code to take appropriate actions.
  99         *
 100         * ppd->lflags could be 0 if this is the first time the interrupt
 101         * handlers has been called but the link is already up.
 102         */
 103        if (lstate >= IB_PORT_INIT &&
 104            (!ppd->lflags || (ppd->lflags & QIBL_LINKDOWN)) &&
 105            ltstate == IB_PHYSPORTSTATE_LINKUP) {
 106                /* transitioned to UP */
 107                if (dd->f_ib_updown(ppd, 1, ibcs))
 108                        goto skip_ibchange; /* chip-code handled */
 109        } else if (ppd->lflags & (QIBL_LINKINIT | QIBL_LINKARMED |
 110                   QIBL_LINKACTIVE | QIBL_IB_FORCE_NOTIFY)) {
 111                if (ltstate != IB_PHYSPORTSTATE_LINKUP &&
 112                    ltstate <= IB_PHYSPORTSTATE_CFG_TRAIN &&
 113                    dd->f_ib_updown(ppd, 0, ibcs))
 114                        goto skip_ibchange; /* chip-code handled */
 115                qib_set_uevent_bits(ppd, _QIB_EVENT_LINKDOWN_BIT);
 116        }
 117
 118        if (lstate != IB_PORT_DOWN) {
 119                /* lstate is INIT, ARMED, or ACTIVE */
 120                if (lstate != IB_PORT_ACTIVE) {
 121                        *ppd->statusp &= ~QIB_STATUS_IB_READY;
 122                        if (ppd->lflags & QIBL_LINKACTIVE)
 123                                ev = IB_EVENT_PORT_ERR;
 124                        spin_lock_irqsave(&ppd->lflags_lock, flags);
 125                        if (lstate == IB_PORT_ARMED) {
 126                                ppd->lflags |= QIBL_LINKARMED | QIBL_LINKV;
 127                                ppd->lflags &= ~(QIBL_LINKINIT |
 128                                        QIBL_LINKDOWN | QIBL_LINKACTIVE);
 129                        } else {
 130                                ppd->lflags |= QIBL_LINKINIT | QIBL_LINKV;
 131                                ppd->lflags &= ~(QIBL_LINKARMED |
 132                                        QIBL_LINKDOWN | QIBL_LINKACTIVE);
 133                        }
 134                        spin_unlock_irqrestore(&ppd->lflags_lock, flags);
 135                        /* start a 75msec timer to clear symbol errors */
 136                        mod_timer(&ppd->symerr_clear_timer,
 137                                  msecs_to_jiffies(75));
 138                } else if (ltstate == IB_PHYSPORTSTATE_LINKUP &&
 139                           !(ppd->lflags & QIBL_LINKACTIVE)) {
 140                        /* active, but not active defered */
 141                        qib_hol_up(ppd); /* useful only for 6120 now */
 142                        *ppd->statusp |=
 143                                QIB_STATUS_IB_READY | QIB_STATUS_IB_CONF;
 144                        qib_clear_symerror_on_linkup((unsigned long)ppd);
 145                        spin_lock_irqsave(&ppd->lflags_lock, flags);
 146                        ppd->lflags |= QIBL_LINKACTIVE | QIBL_LINKV;
 147                        ppd->lflags &= ~(QIBL_LINKINIT |
 148                                QIBL_LINKDOWN | QIBL_LINKARMED);
 149                        spin_unlock_irqrestore(&ppd->lflags_lock, flags);
 150                        if (dd->flags & QIB_HAS_SEND_DMA)
 151                                qib_sdma_process_event(ppd,
 152                                        qib_sdma_event_e30_go_running);
 153                        ev = IB_EVENT_PORT_ACTIVE;
 154                        dd->f_setextled(ppd, 1);
 155                }
 156        } else { /* down */
 157                if (ppd->lflags & QIBL_LINKACTIVE)
 158                        ev = IB_EVENT_PORT_ERR;
 159                spin_lock_irqsave(&ppd->lflags_lock, flags);
 160                ppd->lflags |= QIBL_LINKDOWN | QIBL_LINKV;
 161                ppd->lflags &= ~(QIBL_LINKINIT |
 162                                 QIBL_LINKACTIVE | QIBL_LINKARMED);
 163                spin_unlock_irqrestore(&ppd->lflags_lock, flags);
 164                *ppd->statusp &= ~QIB_STATUS_IB_READY;
 165        }
 166
 167skip_ibchange:
 168        ppd->lastibcstat = ibcs;
 169        if (ev)
 170                signal_ib_event(ppd, ev);
 171}
 172
 173void qib_clear_symerror_on_linkup(unsigned long opaque)
 174{
 175        struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
 176
 177        if (ppd->lflags & QIBL_LINKACTIVE)
 178                return;
 179
 180        ppd->ibport_data.z_symbol_error_counter =
 181                ppd->dd->f_portcntr(ppd, QIBPORTCNTR_IBSYMBOLERR);
 182}
 183
 184/*
 185 * Handle receive interrupts for user ctxts; this means a user
 186 * process was waiting for a packet to arrive, and didn't want
 187 * to poll.
 188 */
 189void qib_handle_urcv(struct qib_devdata *dd, u64 ctxtr)
 190{
 191        struct qib_ctxtdata *rcd;
 192        unsigned long flags;
 193        int i;
 194
 195        spin_lock_irqsave(&dd->uctxt_lock, flags);
 196        for (i = dd->first_user_ctxt; dd->rcd && i < dd->cfgctxts; i++) {
 197                if (!(ctxtr & (1ULL << i)))
 198                        continue;
 199                rcd = dd->rcd[i];
 200                if (!rcd || !rcd->cnt)
 201                        continue;
 202
 203                if (test_and_clear_bit(QIB_CTXT_WAITING_RCV, &rcd->flag)) {
 204                        wake_up_interruptible(&rcd->wait);
 205                        dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_INTRAVAIL_DIS,
 206                                      rcd->ctxt);
 207                } else if (test_and_clear_bit(QIB_CTXT_WAITING_URG,
 208                                              &rcd->flag)) {
 209                        rcd->urgent++;
 210                        wake_up_interruptible(&rcd->wait);
 211                }
 212        }
 213        spin_unlock_irqrestore(&dd->uctxt_lock, flags);
 214}
 215
 216void qib_bad_intrstatus(struct qib_devdata *dd)
 217{
 218        static int allbits;
 219
 220        /* separate routine, for better optimization of qib_intr() */
 221
 222        /*
 223         * We print the message and disable interrupts, in hope of
 224         * having a better chance of debugging the problem.
 225         */
 226        qib_dev_err(dd,
 227                "Read of chip interrupt status failed disabling interrupts\n");
 228        if (allbits++) {
 229                /* disable interrupt delivery, something is very wrong */
 230                if (allbits == 2)
 231                        dd->f_set_intr_state(dd, 0);
 232                if (allbits == 3) {
 233                        qib_dev_err(dd,
 234                                "2nd bad interrupt status, unregistering interrupts\n");
 235                        dd->flags |= QIB_BADINTR;
 236                        dd->flags &= ~QIB_INITTED;
 237                        dd->f_free_irq(dd);
 238                }
 239        }
 240}
 241