ipath_intr.c
来自「linux 内核源代码」· C语言 代码 · 共 1,209 行 · 第 1/3 页
C
1,209 行
/* * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */#include <linux/pci.h>#include "ipath_kernel.h"#include "ipath_verbs.h"#include "ipath_common.h"/* * clear (write) a pio buffer, to clear a parity error. This routine * should only be called when in freeze mode, and the buffer should be * canceled afterwards. */static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum){ u32 __iomem *pbuf; u32 dwcnt; /* dword count to write */ if (pnum < dd->ipath_piobcnt2k) { pbuf = (u32 __iomem *) (dd->ipath_pio2kbase + pnum * dd->ipath_palign); dwcnt = dd->ipath_piosize2k >> 2; } else { pbuf = (u32 __iomem *) (dd->ipath_pio4kbase + (pnum - dd->ipath_piobcnt2k) * dd->ipath_4kalign); dwcnt = dd->ipath_piosize4k >> 2; } dev_info(&dd->pcidev->dev, "Rewrite PIO buffer %u, to recover from parity error\n", pnum); *pbuf = dwcnt+1; /* no flush required, since already in freeze */ while(--dwcnt) *pbuf++ = 0;}/* * Called when we might have an error that is specific to a particular * PIO buffer, and may need to cancel that buffer, so it can be re-used. * If rewrite is true, and bits are set in the sendbufferror registers, * we'll write to the buffer, for error recovery on parity errors. */static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite){ u32 piobcnt; unsigned long sbuf[4]; /* * it's possible that sendbuffererror could have bits set; might * have already done this as a result of hardware error handling */ piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k; /* read these before writing errorclear */ sbuf[0] = ipath_read_kreg64( dd, dd->ipath_kregs->kr_sendbuffererror); sbuf[1] = ipath_read_kreg64( dd, dd->ipath_kregs->kr_sendbuffererror + 1); if (piobcnt > 128) { sbuf[2] = ipath_read_kreg64( dd, dd->ipath_kregs->kr_sendbuffererror + 2); sbuf[3] = ipath_read_kreg64( dd, dd->ipath_kregs->kr_sendbuffererror + 3); } if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) { int i; if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG) && dd->ipath_lastcancel > jiffies) { __IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG, "SendbufErrs %lx %lx", sbuf[0], sbuf[1]); if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128) printk(" %lx %lx ", sbuf[2], sbuf[3]); printk("\n"); } for (i = 0; i < piobcnt; i++) if (test_bit(i, sbuf)) { if (rewrite) ipath_clrpiobuf(dd, i); ipath_disarm_piobufs(dd, i, 1); } /* ignore armlaunch errs for a bit */ dd->ipath_lastcancel = jiffies+3; }}/* These are all rcv-related errors which we want to count for stats */#define E_SUM_PKTERRS \ (INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \ INFINIPATH_E_RBADVERSION | INFINIPATH_E_RHDR | \ INFINIPATH_E_RLONGPKTLEN | INFINIPATH_E_RSHORTPKTLEN | \ INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RMINPKTLEN | \ INFINIPATH_E_RFORMATERR | INFINIPATH_E_RUNSUPVL | \ INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_REBP)/* These are all send-related errors which we want to count for stats */#define E_SUM_ERRS \ (INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | \ INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \ INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SUNSUPVL | \ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \ INFINIPATH_E_INVALIDADDR)/* * this is similar to E_SUM_ERRS, but can't ignore armlaunch, don't ignore * errors not related to freeze and cancelling buffers. Can't ignore * armlaunch because could get more while still cleaning up, and need * to cancel those as they happen. */#define E_SPKT_ERRS_IGNORE \ (INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \ INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SMINPKTLEN | \ INFINIPATH_E_SPKTLEN)/* * these are errors that can occur when the link changes state while * a packet is being sent or received. This doesn't cover things * like EBP or VCRC that can be the result of a sending having the * link change state, so we receive a "known bad" packet. */#define E_SUM_LINK_PKTERRS \ (INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \ INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RMINPKTLEN | \ INFINIPATH_E_RUNEXPCHAR)static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs){ u64 ignore_this_time = 0; ipath_disarm_senderrbufs(dd, 0); if ((errs & E_SUM_LINK_PKTERRS) && !(dd->ipath_flags & IPATH_LINKACTIVE)) { /* * This can happen when SMA is trying to bring the link * up, but the IB link changes state at the "wrong" time. * The IB logic then complains that the packet isn't * valid. We don't want to confuse people, so we just * don't print them, except at debug */ ipath_dbg("Ignoring packet errors %llx, because link not " "ACTIVE\n", (unsigned long long) errs); ignore_this_time = errs & E_SUM_LINK_PKTERRS; } return ignore_this_time;}/* generic hw error messages... */#define INFINIPATH_HWE_TXEMEMPARITYERR_MSG(a) \ { \ .mask = ( INFINIPATH_HWE_TXEMEMPARITYERR_##a << \ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT ), \ .msg = "TXE " #a " Memory Parity" \ }#define INFINIPATH_HWE_RXEMEMPARITYERR_MSG(a) \ { \ .mask = ( INFINIPATH_HWE_RXEMEMPARITYERR_##a << \ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT ), \ .msg = "RXE " #a " Memory Parity" \ }static const struct ipath_hwerror_msgs ipath_generic_hwerror_msgs[] = { INFINIPATH_HWE_MSG(IBCBUSFRSPCPARITYERR, "IPATH2IB Parity"), INFINIPATH_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2IPATH Parity"), INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOBUF), INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOPBC), INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOLAUNCHFIFO), INFINIPATH_HWE_RXEMEMPARITYERR_MSG(RCVBUF), INFINIPATH_HWE_RXEMEMPARITYERR_MSG(LOOKUPQ), INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EAGERTID), INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EXPTID), INFINIPATH_HWE_RXEMEMPARITYERR_MSG(FLAGBUF), INFINIPATH_HWE_RXEMEMPARITYERR_MSG(DATAINFO), INFINIPATH_HWE_RXEMEMPARITYERR_MSG(HDRINFO),};/** * ipath_format_hwmsg - format a single hwerror message * @msg message buffer * @msgl length of message buffer * @hwmsg message to add to message buffer */static void ipath_format_hwmsg(char *msg, size_t msgl, const char *hwmsg){ strlcat(msg, "[", msgl); strlcat(msg, hwmsg, msgl); strlcat(msg, "]", msgl);}/** * ipath_format_hwerrors - format hardware error messages for display * @hwerrs hardware errors bit vector * @hwerrmsgs hardware error descriptions * @nhwerrmsgs number of hwerrmsgs * @msg message buffer * @msgl message buffer length */void ipath_format_hwerrors(u64 hwerrs, const struct ipath_hwerror_msgs *hwerrmsgs, size_t nhwerrmsgs, char *msg, size_t msgl){ int i; const int glen = sizeof(ipath_generic_hwerror_msgs) / sizeof(ipath_generic_hwerror_msgs[0]); for (i=0; i<glen; i++) { if (hwerrs & ipath_generic_hwerror_msgs[i].mask) { ipath_format_hwmsg(msg, msgl, ipath_generic_hwerror_msgs[i].msg); } } for (i=0; i<nhwerrmsgs; i++) { if (hwerrs & hwerrmsgs[i].mask) { ipath_format_hwmsg(msg, msgl, hwerrmsgs[i].msg); } }}/* return the strings for the most common link states */static char *ib_linkstate(u32 linkstate){ char *ret; switch (linkstate) { case IPATH_IBSTATE_INIT: ret = "Init"; break; case IPATH_IBSTATE_ARM: ret = "Arm"; break; case IPATH_IBSTATE_ACTIVE: ret = "Active"; break; default: ret = "Down"; } return ret;}void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev){ struct ib_event event; event.device = &dd->verbs_dev->ibdev; event.element.port_num = 1; event.event = ev; ib_dispatch_event(&event);}static void handle_e_ibstatuschanged(struct ipath_devdata *dd, ipath_err_t errs, int noprint){ u64 val; u32 ltstate, lstate; /* * even if diags are enabled, we want to notice LINKINIT, etc. * We just don't want to change the LED state, or * dd->ipath_kregs->kr_ibcctrl */ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus); lstate = val & IPATH_IBSTATE_MASK; /* * this is confusing enough when it happens that I want to always put it * on the console and in the logs. If it was a requested state change, * we'll have already cleared the flags, so we won't print this warning */ if ((lstate != IPATH_IBSTATE_ARM && lstate != IPATH_IBSTATE_ACTIVE) && (dd->ipath_flags & (IPATH_LINKARMED | IPATH_LINKACTIVE))) { dev_info(&dd->pcidev->dev, "Link state changed from %s to %s\n", (dd->ipath_flags & IPATH_LINKARMED) ? "ARM" : "ACTIVE", ib_linkstate(lstate)); /* * Flush all queued sends when link went to DOWN or INIT, * to be sure that they don't block SMA and other MAD packets */ ipath_cancel_sends(dd, 1); } else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM || lstate == IPATH_IBSTATE_ACTIVE) { /* * only print at SMA if there is a change, debug if not * (sometimes we want to know that, usually not). */ if (lstate == ((unsigned) dd->ipath_lastibcstat & IPATH_IBSTATE_MASK)) { ipath_dbg("Status change intr but no change (%s)\n", ib_linkstate(lstate)); } else ipath_cdbg(VERBOSE, "Unit %u link state %s, last " "was %s\n", dd->ipath_unit, ib_linkstate(lstate), ib_linkstate((unsigned) dd->ipath_lastibcstat & IPATH_IBSTATE_MASK)); } else { lstate = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM || lstate == IPATH_IBSTATE_ACTIVE) ipath_cdbg(VERBOSE, "Unit %u link state down" " (state 0x%x), from %s\n", dd->ipath_unit, (u32)val & IPATH_IBSTATE_MASK, ib_linkstate(lstate)); else ipath_cdbg(VERBOSE, "Unit %u link state changed " "to 0x%x from down (%x)\n", dd->ipath_unit, (u32) val, lstate); } ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & INFINIPATH_IBCS_LINKTRAININGSTATE_MASK; lstate = (val >> INFINIPATH_IBCS_LINKSTATE_SHIFT) & INFINIPATH_IBCS_LINKSTATE_MASK; if (ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE || ltstate == INFINIPATH_IBCS_LT_STATE_POLLQUIET) { u32 last_ltstate; /* * Ignore cycling back and forth from Polling.Active * to Polling.Quiet while waiting for the other end of * the link to come up. We will cycle back and forth * between them if no cable is plugged in, * the other device is powered off or disabled, etc. */ last_ltstate = (dd->ipath_lastibcstat >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & INFINIPATH_IBCS_LINKTRAININGSTATE_MASK; if (last_ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE || last_ltstate == INFINIPATH_IBCS_LT_STATE_POLLQUIET) { if (dd->ipath_ibpollcnt > 40) { dd->ipath_flags |= IPATH_NOCABLE; *dd->ipath_statusp |= IPATH_STATUS_IB_NOCABLE; } else dd->ipath_ibpollcnt++; goto skip_ibchange; } } dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */ ipath_stats.sps_iblink++; if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) { if (dd->ipath_flags & IPATH_LINKACTIVE) signal_ib_event(dd, IB_EVENT_PORT_ERR); dd->ipath_flags |= IPATH_LINKDOWN; dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT | IPATH_LINKACTIVE | IPATH_LINKARMED); *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; dd->ipath_lli_counter = 0; if (!noprint) { if (((dd->ipath_lastibcstat >> INFINIPATH_IBCS_LINKSTATE_SHIFT) & INFINIPATH_IBCS_LINKSTATE_MASK) == INFINIPATH_IBCS_L_STATE_ACTIVE) /* if from up to down be more vocal */ ipath_cdbg(VERBOSE, "Unit %u link now down (%s)\n", dd->ipath_unit, ipath_ibcstatus_str[ltstate]);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?