CINXE.COM
LKML: Roland Dreier: [PATCH 08/13] [RFC] ipath core last bit
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>LKML: Roland Dreier: [PATCH 08/13] [RFC] ipath core last bit</title><link href="/css/message.css" rel="stylesheet" type="text/css" /><link href="/css/wrap.css" rel="alternate stylesheet" type="text/css" title="wrap" /><link href="/css/nowrap.css" rel="stylesheet" type="text/css" title="nowrap" /><link href="/favicon.ico" rel="shortcut icon" /><script src="/js/simple-calendar.js" type="text/javascript"></script><script src="/js/styleswitcher.js" type="text/javascript"></script><link rel="alternate" type="application/rss+xml" title="lkml.org : last 100 messages" href="/rss.php" /><link rel="alternate" type="application/rss+xml" title="lkml.org : last messages by Roland Dreier" href="/groupie.php?aid=3215" /><!--Matomo--><script> var _paq = window._paq = window._paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDoNotTrack", true]); _paq.push(["disableCookies"]); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="//m.lkml.org/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script><!--End Matomo Code--></head><body onload="es.jasper.simpleCalendar.init();" itemscope="itemscope" itemtype="http://schema.org/BlogPosting"><table border="0" cellpadding="0" cellspacing="0"><tr><td width="180" align="center"><a href="/"><img style="border:0;width:135px;height:32px" src="/images/toprowlk.gif" alt="lkml.org" /></a></td><td width="32">聽</td><td class="nb"><div><a class="nb" href="/lkml"> [lkml]</a> 聽 <a class="nb" href="/lkml/2005"> [2005]</a> 聽 <a class="nb" href="/lkml/2005/12"> [Dec]</a> 聽 <a class="nb" href="/lkml/2005/12/16"> [16]</a> 聽 <a class="nb" href="/lkml/last100"> [last100]</a> 聽 <a href="/rss.php"><img src="/images/rss-or.gif" border="0" alt="RSS Feed" /></a></div><div>Views: <a href="#" class="nowrap" onclick="setActiveStyleSheet('wrap');return false;">[wrap]</a><a href="#" class="wrap" onclick="setActiveStyleSheet('nowrap');return false;">[no wrap]</a> 聽 <a class="nb" href="/lkml/mheaders/2005/12/16/305" onclick="this.href='/lkml/headers'+'/2005/12/16/305';">[headers]</a>聽 <a href="/lkml/bounce/2005/12/16/305">[forward]</a>聽 </div></td><td width="32">聽</td></tr><tr><td valign="top"><div class="es-jasper-simpleCalendar" baseurl="/lkml/"></div><div class="threadlist">Messages in this thread</div><ul class="threadlist"><li class="root"><a href="/lkml/2005/12/16/290">First message in thread</a></li><li><a href="/lkml/2005/12/16/297">Roland Dreier</a><ul><li><a href="/lkml/2005/12/16/296">Roland Dreier</a><ul><li class="origin"><a href="/lkml/2005/12/16/299">Roland Dreier</a><ul><li><a href="/lkml/2005/12/16/299">Roland Dreier</a><ul><li><a href="/lkml/2005/12/16/295">Roland Dreier</a></li><li><a href="/lkml/2005/12/18/89">"Paul E. McKenney"</a></li></ul></li><li><a href="/lkml/2005/12/17/75">Andrew Morton</a><ul><li><a href="/lkml/2005/12/20/295">Robert Walsh</a></li></ul></li></ul></li></ul></li><li><a href="/lkml/2005/12/17/74">Andrew Morton</a><ul><li><a href="/lkml/2005/12/17/87">Robert Walsh</a></li><li><a href="/lkml/2005/12/17/90">Robert Walsh</a><ul><li><a href="/lkml/2005/12/17/124">Andrew Morton</a><ul><li><a href="/lkml/2005/12/17/125">Robert Walsh</a></li></ul></li></ul></li></ul></li></ul></li></ul><div class="threadlist">Patch in this message</div><ul class="threadlist"><li><a href="/lkml/diff/2005/12/16/305/1">Get diff 1</a></li></ul></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerl.gif" width="32" height="32" alt="/" /></td><td class="c" rowspan="2" valign="top" style="padding-top: 1em"><table><tr><td><table><tr><td class="lp">Subject</td><td class="rp" itemprop="name">[PATCH 08/13] [RFC] ipath core last bit</td></tr><tr><td class="lp">Date</td><td class="rp" itemprop="datePublished">Fri, 16 Dec 2005 15:48:55 -0800</td></tr><tr><td class="lp">From</td><td class="rp" itemprop="author">Roland Dreier <></td></tr></table></td><td></td></tr></table><pre itemprop="articleBody">Last piece of ipath LLD<br /><br />---<br /><br /> drivers/infiniband/hw/ipath/ipath_layer.c | 1155 +++++++++++++++++++++++++++++<br /> 1 files changed, 1155 insertions(+), 0 deletions(-)<br /> create mode 100644 drivers/infiniband/hw/ipath/ipath_layer.c<br /><br />978ded82c9b5a4bca4e55f36d20ef4a585c50f38<br />diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c<br />new file mode 100644<br />index 0000000..6a60851<br />--- /dev/null<br />+++ b/drivers/infiniband/hw/ipath/ipath_layer.c<br />@@ -0,0 +1,1155 @@<br />+/*<br />+ * Copyright (c) 2003, 2004, 2005. PathScale, Inc. All rights reserved.<br />+ *<br />+ * This software is available to you under a choice of one of two<br />+ * licenses. You may choose to be licensed under the terms of the GNU<br />+ * General Public License (GPL) Version 2, available from the file<br />+ * COPYING in the main directory of this source tree, or the<br />+ * OpenIB.org BSD license below:<br />+ *<br />+ * Redistribution and use in source and binary forms, with or<br />+ * without modification, are permitted provided that the following<br />+ * conditions are met:<br />+ *<br />+ * - Redistributions of source code must retain the above<br />+ * copyright notice, this list of conditions and the following<br />+ * disclaimer.<br />+ *<br />+ * - Redistributions in binary form must reproduce the above<br />+ * copyright notice, this list of conditions and the following<br />+ * disclaimer in the documentation and/or other materials<br />+ * provided with the distribution.<br />+ *<br />+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,<br />+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF<br />+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND<br />+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS<br />+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN<br />+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN<br />+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE<br />+ * SOFTWARE.<br />+ *<br />+ * Patent licenses, if any, provided herein do not apply to<br />+ * combinations of this program with other software, or any other<br />+ * product whatsoever.<br />+ *<br />+ * $Id: ipath_layer.c 4365 2005-12-10 00:04:16Z rjwalsh $<br />+ */<br />+<br />+/*<br />+ * These are the routines used by layered drivers, currently just the<br />+ * layered ethernet driver and verbs layer.<br />+ */<br />+<br />+#include <linux/pci.h><br />+<br />+#include "ipath_kernel.h"<br />+#include "ips_common.h"<br />+#include "ipath_layer.h"<br />+<br />+/* unit number is already validated in ipath_ioctl() */<br />+int ipath_kset_linkstate(uint32_t arg)<br />+{<br />+ ipath_type unit = 0xffff & (arg >> 16);<br />+ uint32_t lstate;<br />+ ipath_devdata *dd;<br />+<br />+ if (unit >= infinipath_max ||<br />+ !(devdata[unit].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", unit);<br />+ return -ENODEV;<br />+ }<br />+<br />+ dd = &devdata[unit];<br />+ arg &= 0xffff;<br />+ if (arg != IPATH_IB_LINKDOWN && arg != IPATH_IB_LINKARM &&<br />+ arg != IPATH_IB_LINKACTIVE) {<br />+ _IPATH_DBG("Unknown linkstate 0x%x requested\n", arg);<br />+ return -EINVAL;<br />+ }<br />+ if (arg == IPATH_IB_LINKDOWN) {<br />+ ipath_down_link(unit); /* really moving it to idle */<br />+ lstate = IPATH_LINKDOWN | IPATH_LINK_SLEEPING;<br />+ } else if (arg == IPATH_IB_LINKARM) {<br />+ if (!(dd->ipath_flags &<br />+ (IPATH_LINKINIT | IPATH_LINKARMED | IPATH_LINKDOWN |<br />+ IPATH_LINK_SLEEPING | IPATH_LINKACTIVE)))<br />+ _IPATH_DBG<br />+ ("don't know current state (flags 0x%x), try anyway\n",<br />+ dd->ipath_flags);<br />+ ipath_set_ib_lstate(unit, INFINIPATH_IBCC_LINKCMD_ARMED);<br />+ lstate = IPATH_LINKARMED;<br />+ } else {<br />+ int tryarmed = 0;<br />+ /*<br />+ * because we sometimes go to ARMED, but then back to 0x11<br />+ * (initialized) before the SMA asks us to move to ACTIVE,<br />+ * we will try to advance state to ARMED here, if necessary<br />+ */<br />+ if (!(dd->ipath_flags &<br />+ (IPATH_LINKINIT | IPATH_LINKARMED | IPATH_LINKDOWN |<br />+ IPATH_LINK_SLEEPING | IPATH_LINKACTIVE))) {<br />+ /* this one is just paranoia */<br />+ _IPATH_DBG<br />+ ("don't know current state (flags 0x%x), try anyway\n",<br />+ dd->ipath_flags);<br />+ tryarmed = 1;<br />+<br />+ }<br />+ if (!(dd->ipath_flags & (IPATH_LINKARMED | IPATH_LINKACTIVE)))<br />+ tryarmed = 1;<br />+ if (tryarmed) {<br />+ ipath_set_ib_lstate(unit,<br />+ INFINIPATH_IBCC_LINKCMD_ARMED);<br />+ /*<br />+ * give it up to 2 seconds to get to ARMED or<br />+ * ACTIVE; continue afterwards even if we fail<br />+ */<br />+ if (ipath_wait_linkstate<br />+ (unit, IPATH_LINKARMED | IPATH_LINKACTIVE, 2000))<br />+ _IPATH_VDBG<br />+ ("try for active, even though didn't get to ARMED\n");<br />+ }<br />+<br />+ ipath_set_ib_lstate(unit, INFINIPATH_IBCC_LINKCMD_ACTIVE);<br />+ lstate = IPATH_LINKACTIVE;<br />+ }<br />+ return ipath_wait_linkstate(unit, lstate, 5000);<br />+}<br />+<br />+/*<br />+ * we can handle "any" incoming size, the issue here is whether we<br />+ * need to restrict our outgoing size. For now, we don't do any<br />+ * sanity checking on this, and we don't deal with what happens to<br />+ * programs that are already running when the size changes.<br />+ * unit number is already validated in ipath_ioctl()<br />+ * NOTE: changing the MTU will usually cause the IBC to go back to<br />+ * link initialize (0x11) state...<br />+ */<br />+int ipath_kset_mtu(uint32_t arg)<br />+{<br />+ unsigned unit = (arg >> 16) & 0xffff;<br />+ uint32_t piosize;<br />+ int changed = 0;<br />+<br />+ if (unit >= infinipath_max ||<br />+ !(devdata[unit].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", unit);<br />+ return -ENODEV;<br />+ }<br />+<br />+ arg &= 0xffff;<br />+ /*<br />+ * mtu is IB data payload max. It's the largest power of 2 less<br />+ * than piosize (or even larger, since it only really controls the<br />+ * largest we can receive; we can send the max of the mtu and piosize).<br />+ * We check that it's one of the valid IB sizes.<br />+ */<br />+ if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 &&<br />+ arg != 4096) {<br />+ _IPATH_DBG("Trying to set invalid mtu %u, failing\n", arg);<br />+ return -EINVAL;<br />+ }<br />+ if (devdata[unit].ipath_ibmtu == arg) {<br />+ return 0; /* same as current */<br />+ }<br />+<br />+ piosize = devdata[unit].ipath_ibmaxlen;<br />+ devdata[unit].ipath_ibmtu = arg;<br />+<br />+ /*<br />+ * the 128 is the max IB header size allowed for in our pio send buffers<br />+ * If we are reducing the MTU below that, this doesn't completely make<br />+ * sense, but it's OK.<br />+ */<br />+ if (arg >= (piosize - 128)) {<br />+ /* hasn't been changed */<br />+ if (piosize == devdata[unit].ipath_init_ibmaxlen)<br />+ _IPATH_VDBG<br />+ ("mtu 0x%x >= ibmaxlen hardware max, nothing to do\n",<br />+ arg);<br />+ else {<br />+ _IPATH_VDBG<br />+ ("mtu 0x%x restores ibmaxlen to full amount 0x%x\n",<br />+ arg, piosize);<br />+ devdata[unit].ipath_ibmaxlen = piosize;<br />+ changed = 1;<br />+ }<br />+ } else if ((arg + 128) == devdata[unit].ipath_ibmaxlen)<br />+ _IPATH_VDBG("ibmaxlen %x same as current, no change\n", arg);<br />+ else {<br />+ piosize = arg + 128;<br />+ _IPATH_VDBG("ibmaxlen was 0x%x, setting to 0x%x (mtu 0x%x)\n",<br />+ devdata[unit].ipath_ibmaxlen, piosize, arg);<br />+ devdata[unit].ipath_ibmaxlen = piosize;<br />+ changed = 1;<br />+ }<br />+<br />+ if (changed) {<br />+ /*<br />+ * set the IBC maxpktlength to the size of our pio<br />+ * buffers in words<br />+ */<br />+ uint64_t ibc = devdata[unit].ipath_ibcctrl;<br />+ ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK <<<br />+ INFINIPATH_IBCC_MAXPKTLEN_SHIFT);<br />+<br />+ piosize = piosize - 2 * sizeof(uint32_t); /* ignore pbc */<br />+ devdata[unit].ipath_ibmaxlen = piosize;<br />+ piosize /= sizeof(uint32_t); /* in words */<br />+ /*<br />+ * for ICRC, which we only send in diag test pkt mode, and we<br />+ * don't need to worry about that for mtu<br />+ */<br />+ piosize += 1;<br />+<br />+ ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT;<br />+ devdata[unit].ipath_ibcctrl = ibc;<br />+ ipath_kput_kreg(unit, kr_ibcctrl, devdata[unit].ipath_ibcctrl);<br />+ }<br />+ return 0;<br />+}<br />+<br />+void ipath_set_sps_lid(const ipath_type unit, uint32_t arg)<br />+{<br />+ if (unit >= infinipath_max ||<br />+ !(devdata[unit].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", unit);<br />+ return;<br />+ }<br />+<br />+ ipath_stats.sps_lid[unit] = devdata[unit].ipath_lid = arg;<br />+ if (devdata[unit].ipath_layer.l_intr)<br />+ devdata[unit].ipath_layer.l_intr(unit, IPATH_LAYER_INT_LID);<br />+}<br />+<br />+/* XXX - need to inform anyone who cares this just happened. */<br />+int ipath_layer_set_guid(const ipath_type device, uint64_t guid)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return -ENODEV;<br />+ }<br />+ devdata[device].ipath_guid = guid;<br />+ return 0;<br />+}<br />+<br />+uint64_t ipath_layer_get_guid(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+ return devdata[device].ipath_guid;<br />+}<br />+<br />+uint32_t ipath_layer_get_nguid(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+ return devdata[device].ipath_nguid;<br />+}<br />+<br />+int ipath_layer_query_device(const ipath_type device, uint32_t * vendor,<br />+ uint32_t * boardrev, uint32_t * majrev,<br />+ uint32_t * minrev)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return -ENODEV;<br />+ }<br />+<br />+ *vendor = devdata[device].ipath_vendorid;<br />+ *boardrev = devdata[device].ipath_boardrev;<br />+ *majrev = devdata[device].ipath_majrev;<br />+ *minrev = devdata[device].ipath_minrev;<br />+<br />+ return 0;<br />+}<br />+<br />+uint32_t ipath_layer_get_flags(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+<br />+ return devdata[device].ipath_flags;<br />+}<br />+<br />+struct device *ipath_layer_get_pcidev(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return NULL;<br />+ }<br />+<br />+ return &(devdata[device].pcidev->dev);<br />+}<br />+<br />+uint16_t ipath_layer_get_deviceid(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+<br />+ return devdata[device].ipath_deviceid;<br />+}<br />+<br />+uint64_t ipath_layer_get_lastibcstat(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+<br />+ return devdata[device].ipath_lastibcstat;<br />+}<br />+<br />+uint32_t ipath_layer_get_ibmtu(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+<br />+ return devdata[device].ipath_ibmtu;<br />+}<br />+<br />+int ipath_layer_register(const ipath_type device,<br />+ int (*l_intr) (const ipath_type, uint32_t),<br />+ int (*l_rcv) (const ipath_type, void *,<br />+ struct sk_buff *), uint16_t l_rcv_opcode,<br />+ int (*l_rcv_lid) (const ipath_type, void *),<br />+ uint16_t l_rcv_lid_opcode)<br />+{<br />+ int ret = 0;<br />+<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 1;<br />+ }<br />+ if (!(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_VDBG("%s not yet initialized, failing\n",<br />+ ipath_get_unit_name(device));<br />+ return 1;<br />+ }<br />+<br />+ _IPATH_VDBG("intr %p rx %p, rx_lid %p\n", l_intr, l_rcv, l_rcv_lid);<br />+ if (devdata[device].ipath_layer.l_intr<br />+ || devdata[device].ipath_layer.l_rcv) {<br />+ _IPATH_DBG<br />+ ("Layered device already registered on unit %u, failing\n",<br />+ device);<br />+ return 1;<br />+ }<br />+<br />+ if(!(*devdata[device].ipath_statusp & IPATH_STATUS_SMA))<br />+ *devdata[device].ipath_statusp |= IPATH_STATUS_OIB_SMA;<br />+ devdata[device].ipath_layer.l_intr = l_intr;<br />+ devdata[device].ipath_layer.l_rcv = l_rcv;<br />+ devdata[device].ipath_layer.l_rcv_lid = l_rcv_lid;<br />+ devdata[device].ipath_layer.l_rcv_opcode = l_rcv_opcode;<br />+ devdata[device].ipath_layer.l_rcv_lid_opcode = l_rcv_lid_opcode;<br />+<br />+ return ret;<br />+}<br />+<br />+static void ipath_verbs_timer(unsigned long t)<br />+{<br />+ /*<br />+ * If port 0 receive packet interrupts are not availabile,<br />+ * check the receive queue.<br />+ */<br />+ if (!(devdata[t].ipath_flags & IPATH_GPIO_INTR))<br />+ ipath_kreceive(t);<br />+<br />+ /* Handle verbs layer timeouts. */<br />+ if (devdata[t].verbs_layer.l_timer_cb)<br />+ devdata[t].verbs_layer.l_timer_cb(t);<br />+<br />+ mod_timer(&devdata[t].verbs_layer.l_timer, jiffies + 1);<br />+}<br />+<br />+/* Verbs layer registration. */<br />+int ipath_verbs_register(const ipath_type device,<br />+ int (*l_piobufavail) (const ipath_type device),<br />+ void (*l_rcv) (const ipath_type device, void *rhdr,<br />+ void *data, u32 tlen),<br />+ void (*l_timer_cb) (const ipath_type device))<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+ if (!(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_VDBG("%s not yet initialized, failing\n",<br />+ ipath_get_unit_name(device));<br />+ return 0;<br />+ }<br />+<br />+ _IPATH_VDBG("piobufavail %p rx %p\n", l_piobufavail, l_rcv);<br />+ if (devdata[device].verbs_layer.l_piobufavail ||<br />+ devdata[device].verbs_layer.l_rcv) {<br />+ _IPATH_DBG("Verbs layer already registered on unit %u, "<br />+ "failing\n", device);<br />+ return 0;<br />+ }<br />+<br />+ devdata[device].verbs_layer.l_piobufavail = l_piobufavail;<br />+ devdata[device].verbs_layer.l_rcv = l_rcv;<br />+ devdata[device].verbs_layer.l_timer_cb = l_timer_cb;<br />+ devdata[device].verbs_layer.l_flags = 0;<br />+<br />+ return 1;<br />+}<br />+<br />+void ipath_verbs_unregister(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return;<br />+ }<br />+ if (!(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ _IPATH_VDBG("%s not yet initialized, failing\n",<br />+ ipath_get_unit_name(device));<br />+ return;<br />+ }<br />+<br />+ *devdata[device].ipath_statusp &= ~IPATH_STATUS_OIB_SMA;<br />+ devdata[device].verbs_layer.l_piobufavail = NULL;<br />+ devdata[device].verbs_layer.l_rcv = NULL;<br />+ devdata[device].verbs_layer.l_timer_cb = NULL;<br />+ devdata[device].verbs_layer.l_flags = 0;<br />+}<br />+<br />+int ipath_layer_open(const ipath_type device, uint32_t * pktmax)<br />+{<br />+ int ret = 0;<br />+ uint32_t intval = 0;<br />+<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 1;<br />+ }<br />+ if (!devdata[device].ipath_layer.l_intr<br />+ || !devdata[device].ipath_layer.l_rcv) {<br />+ _IPATH_DBG("layer not registered, failing\n");<br />+ return 1;<br />+ }<br />+<br />+ if ((ret =<br />+ ipath_setrcvhdrsize(device, NUM_OF_EKSTRA_WORDS_IN_HEADER_QUEUE)))<br />+ return ret;<br />+<br />+ *pktmax = devdata[device].ipath_ibmaxlen;<br />+<br />+ if (*devdata[device].ipath_statusp & IPATH_STATUS_IB_READY)<br />+ intval |= IPATH_LAYER_INT_IF_UP;<br />+ if (ipath_stats.sps_lid[device])<br />+ intval |= IPATH_LAYER_INT_LID;<br />+ if (ipath_stats.sps_mlid[device])<br />+ intval |= IPATH_LAYER_INT_BCAST;<br />+ /*<br />+ * do this on open, in case low level is already up and<br />+ * just layered driver was reloaded, etc.<br />+ */<br />+ if (intval)<br />+ devdata[device].ipath_layer.l_intr(device, intval);<br />+<br />+ return ret;<br />+}<br />+<br />+int16_t ipath_layer_get_lid(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+<br />+ _IPATH_VDBG("returning mylid 0x%x for layered dev %d\n",<br />+ devdata[device].ipath_lid, device);<br />+ return devdata[device].ipath_lid;<br />+}<br />+<br />+/*<br />+ * get the MAC address. This is the EUID-64 OUI octets (top 3), then<br />+ * skip the next 2 (which should both be zero or 0xff).<br />+ * The returned MAC is in network order<br />+ * mac points to at least 6 bytes of buffer<br />+ * returns 0 on error (to be consistent with get_lid and get_bcast<br />+ * return 1 on success<br />+ * We assume that by the time the LID is set, that the GUID is as valid<br />+ * as it's ever going to be, rather than adding yet another status bit.<br />+ */<br />+<br />+int ipath_layer_get_mac(const ipath_type device, uint8_t * mac)<br />+{<br />+ uint8_t *guid;<br />+<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u, failing\n", device);<br />+ return 0;<br />+ }<br />+ guid = (uint8_t *) & devdata[device].ipath_guid;<br />+<br />+ mac[0] = guid[0];<br />+ mac[1] = guid[1];<br />+ mac[2] = guid[2];<br />+ mac[3] = guid[5];<br />+ mac[4] = guid[6];<br />+ mac[5] = guid[7];<br />+ if((guid[3] || guid[4]) && !(guid[3] == 0xff && guid[4] == 0xff))<br />+ _IPATH_DBG("Warning, guid bytes 3 and 4 not 0 or 0xffff: %x %x\n",<br />+ guid[3], guid[4]);<br />+ _IPATH_VDBG("Returning %x:%x:%x:%x:%x:%x\n",<br />+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);<br />+ return 1;<br />+}<br />+<br />+int16_t ipath_layer_get_bcast(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u, failing\n", device);<br />+ return 0;<br />+ }<br />+<br />+ _IPATH_VDBG("returning broadcast LID 0x%x for unit %u\n",<br />+ devdata[device].ipath_mlid, device);<br />+ return devdata[device].ipath_mlid;<br />+}<br />+<br />+int ipath_layer_get_num_of_dev(void)<br />+{<br />+ return infinipath_max;<br />+}<br />+<br />+int ipath_layer_get_cr_errpkey(const ipath_type device)<br />+{<br />+ return ipath_kget_creg32(device, cr_errpkey);<br />+}<br />+<br />+void ipath_layer_close(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return;<br />+ }<br />+ if (!devdata[device].ipath_layer.l_intr<br />+ || !devdata[device].ipath_layer.l_rcv) {<br />+ /* normal if not all chips are present */<br />+ _IPATH_VDBG("layer close without open\n");<br />+ } else {<br />+ devdata[device].ipath_layer.l_intr = NULL;<br />+ devdata[device].ipath_layer.l_rcv = NULL;<br />+ devdata[device].ipath_layer.l_rcv_lid = NULL;<br />+ devdata[device].ipath_layer.l_rcv_opcode = 0;<br />+ devdata[device].ipath_layer.l_rcv_lid_opcode = 0;<br />+ }<br />+}<br />+<br />+static inline void copy_aligned(uint32_t *piobuf, struct ipath_sge_state *ss,<br />+ uint32_t length)<br />+{<br />+ struct ipath_sge *sge = &ss->sge;<br />+<br />+ while (length) {<br />+ u32 len = sge->length;<br />+ u32 w;<br />+<br />+ BUG_ON(len == 0);<br />+ if (len > length)<br />+ len = length;<br />+ /* Need to round up for the last dword in the packet. */<br />+ w = (len + 3) >> 2;<br />+ ipath_dwordcpy(piobuf, sge->vaddr, w);<br />+ piobuf += w;<br />+ sge->vaddr += len;<br />+ sge->length -= len;<br />+ sge->sge_length -= len;<br />+ if (sge->sge_length == 0) {<br />+ if (--ss->num_sge)<br />+ *sge = *ss->sg_list++;<br />+ } else if (sge->length == 0 && sge->mr != NULL) {<br />+ if (++sge->n >= IPATH_SEGSZ) {<br />+ if (++sge->m >= sge->mr->mapsz)<br />+ break;<br />+ sge->n = 0;<br />+ }<br />+ sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;<br />+ sge->length = sge->mr->map[sge->m]->segs[sge->n].length;<br />+ }<br />+ length -= len;<br />+ }<br />+}<br />+<br />+static inline void copy_unaligned(uint32_t *piobuf, struct ipath_sge_state *ss,<br />+ uint32_t length)<br />+{<br />+ struct ipath_sge *sge = &ss->sge;<br />+ union {<br />+ u8 wbuf[4];<br />+ u32 w;<br />+ } u;<br />+ int extra = 0;<br />+<br />+ while (length) {<br />+ u32 len = sge->length;<br />+<br />+ BUG_ON(len == 0);<br />+ if (len > length)<br />+ len = length;<br />+ length -= len;<br />+ while (len) {<br />+ u.wbuf[extra++] = *(u8 *) sge->vaddr;<br />+ sge->vaddr++;<br />+ sge->length--;<br />+ sge->sge_length--;<br />+ if (extra >= 4) {<br />+ *piobuf++ = u.w;<br />+ extra = 0;<br />+ }<br />+ len--;<br />+ }<br />+ if (sge->sge_length == 0) {<br />+ if (--ss->num_sge)<br />+ *sge = *ss->sg_list++;<br />+ } else if (sge->length == 0) {<br />+ if (++sge->n >= IPATH_SEGSZ) {<br />+ if (++sge->m >= sge->mr->mapsz)<br />+ break;<br />+ sge->n = 0;<br />+ }<br />+ sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;<br />+ sge->length = sge->mr->map[sge->m]->segs[sge->n].length;<br />+ }<br />+ }<br />+ if (extra) {<br />+ while (extra < 4)<br />+ u.wbuf[extra++] = 0;<br />+ *piobuf = u.w;<br />+ }<br />+}<br />+<br />+/*<br />+ * This is like ipath_send_smapkt() in that we need to be able to send<br />+ * packets after the chip is initialized (MADs) but also like<br />+ * ipath_layer_send() since its used by the verbs layer.<br />+ */<br />+int ipath_verbs_send(const ipath_type device, uint32_t hdrwords,<br />+ uint32_t *hdr, uint32_t len, struct ipath_sge_state *ss)<br />+{<br />+ ipath_devdata *dd = &devdata[device];<br />+ int whichpb;<br />+ uint32_t *piobuf, plen;<br />+ uint64_t pboff;<br />+<br />+ if (device >= infinipath_max ||<br />+ !(dd->ipath_flags & IPATH_PRESENT) || !dd->ipath_kregbase) {<br />+ _IPATH_DBG("illegal unit %u\n", device);<br />+ return -ENODEV;<br />+ }<br />+ if (!(dd->ipath_flags & IPATH_INITTED)) {<br />+ /* no hardware, freeze, etc. */<br />+ _IPATH_DBG("unit %u not usable\n", device);<br />+ return -ENODEV;<br />+ }<br />+ /* +1 is for the qword padding of pbc */<br />+ plen = hdrwords + ((len + 3) >> 2) + 1;<br />+ if ((plen << 2) > dd->ipath_ibmaxlen) {<br />+ _IPATH_DBG("packet len 0x%x too long, failing\n", plen);<br />+ return -EINVAL;<br />+ }<br />+<br />+ /* Get a PIO buffer to use. */<br />+ if ((whichpb = ipath_getpiobuf(device)) < 0)<br />+ return whichpb;<br />+<br />+ pboff = dd->ipath_piobufbase;<br />+ piobuf = (uint32_t *) (((char *)(dd->ipath_kregbase)) + pboff<br />+ + whichpb * dd->ipath_palign);<br />+ _IPATH_EPDBG("0x%x+1w pio%d\n", plen - 1, whichpb);<br />+<br />+ /* Write len to control qword, no flags. */<br />+ *((uint64_t *) piobuf) = (uint64_t) plen;<br />+ piobuf += 2;<br />+ ipath_dwordcpy(piobuf, hdr, hdrwords);<br />+ if (len == 0)<br />+ return 0;<br />+ piobuf += hdrwords;<br />+ /*<br />+ * If we really wanted to check everything, we would have to<br />+ * check that each segment starts on a dword boundary and is<br />+ * a dword multiple in length.<br />+ * Since there can be lots of segments, we only check for a simple<br />+ * common case where the amount to copy is contained in one segment.<br />+ */<br />+ if (ss->sge.length == len)<br />+ copy_aligned(piobuf, ss, len);<br />+ else<br />+ copy_unaligned(piobuf, ss, len);<br />+ return 0;<br />+}<br />+<br />+void ipath_layer_snapshot_counters(const ipath_type device, u64 * swords,<br />+ u64 * rwords, u64 * spkts, u64 * rpkts)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_PRESENT)) {<br />+ _IPATH_DBG("illegal unit %u\n", device);<br />+ return;<br />+ }<br />+ if (!(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ /* no hardware, freeze, etc. */<br />+ _IPATH_DBG("unit %u not usable\n", device);<br />+ return;<br />+ }<br />+ *swords = ipath_snap_cntr(device, cr_wordsendcnt);<br />+ *rwords = ipath_snap_cntr(device, cr_wordrcvcnt);<br />+ *spkts = ipath_snap_cntr(device, cr_pktsendcnt);<br />+ *rpkts = ipath_snap_cntr(device, cr_pktrcvcnt);<br />+}<br />+<br />+/*<br />+ * Return the counters needed by recv_pma_get_portcounters().<br />+ */<br />+void ipath_layer_get_counters(const ipath_type device,<br />+ struct ipath_layer_counters *cntrs)<br />+{<br />+ if (device >= infinipath_max ||<br />+ !(devdata[device].ipath_flags & IPATH_PRESENT)) {<br />+ _IPATH_DBG("illegal unit %u\n", device);<br />+ return;<br />+ }<br />+ if (!(devdata[device].ipath_flags & IPATH_INITTED)) {<br />+ /* no hardware, freeze, etc. */<br />+ _IPATH_DBG("unit %u not usable\n", device);<br />+ return;<br />+ }<br />+ cntrs->symbol_error_counter =<br />+ ipath_snap_cntr(device, cr_ibsymbolerrcnt);<br />+ cntrs->link_error_recovery_counter =<br />+ ipath_snap_cntr(device, cr_iblinkerrrecovcnt);<br />+ cntrs->link_downed_counter = ipath_snap_cntr(device, cr_iblinkdowncnt);<br />+ cntrs->port_rcv_errors = ipath_snap_cntr(device, cr_err_rlencnt) +<br />+ ipath_snap_cntr(device, cr_invalidrlencnt) +<br />+ ipath_snap_cntr(device, cr_erricrccnt) +<br />+ ipath_snap_cntr(device, cr_errvcrccnt) +<br />+ ipath_snap_cntr(device, cr_badformatcnt);<br />+ cntrs->port_rcv_remphys_errors = ipath_snap_cntr(device, cr_rcvebpcnt);<br />+ cntrs->port_xmit_discards = ipath_snap_cntr(device, cr_unsupvlcnt);<br />+ cntrs->port_xmit_data = ipath_snap_cntr(device, cr_wordsendcnt);<br />+ cntrs->port_rcv_data = ipath_snap_cntr(device, cr_wordrcvcnt);<br />+ cntrs->port_xmit_packets = ipath_snap_cntr(device, cr_pktsendcnt);<br />+ cntrs->port_rcv_packets = ipath_snap_cntr(device, cr_pktrcvcnt);<br />+}<br />+<br />+void ipath_layer_want_buffer(const ipath_type device)<br />+{<br />+ atomic_set_mask(INFINIPATH_S_PIOINTBUFAVAIL,<br />+ &devdata[device].ipath_sendctrl);<br />+ ipath_kput_kreg(device, kr_sendctrl, devdata[device].ipath_sendctrl);<br />+}<br />+<br />+int ipath_layer_send(const ipath_type device, void *hdr, void *data,<br />+ uint32_t datawords)<br />+{<br />+ int ret = 0, whichpb;<br />+ uint32_t *piobuf, plen;<br />+ uint16_t vlsllnh;<br />+ uint64_t pboff;<br />+<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u, failing\n", device);<br />+ return -EINVAL;<br />+ }<br />+ if (!(devdata[device].ipath_flags & IPATH_RCVHDRSZ_SET)) {<br />+ _IPATH_DBG("send while not open\n");<br />+ ret = -EINVAL;<br />+ } else<br />+ if ((devdata[device].ipath_flags & (IPATH_LINKUNK | IPATH_LINKDOWN))<br />+ || devdata[device].ipath_lid == 0) {<br />+ /* lid check is for when sma hasn't yet configured */<br />+ ret = -ENETDOWN;<br />+ _IPATH_VDBG("send while not ready, mylid=%u, flags=0x%x\n",<br />+ devdata[device].ipath_lid,<br />+ devdata[device].ipath_flags);<br />+ }<br />+ /* +1 is for the qword padding of pbc */<br />+ plen = (sizeof(ips_message_header_typ) >> 2) + datawords + 1;<br />+ if (plen > (devdata[device].ipath_ibmaxlen >> 2)) {<br />+ _IPATH_DBG("packet len 0x%x too long, failing\n", plen);<br />+ ret = -EINVAL;<br />+ }<br />+ vlsllnh = *((uint16_t *) hdr);<br />+ if (vlsllnh != htons(IPS_LRH_BTH)) {<br />+ _IPATH_DBG("Warning: lrh[0] wrong (%x, not %x); not sending\n",<br />+ vlsllnh, htons(IPS_LRH_BTH));<br />+ ret = -EINVAL;<br />+ }<br />+ if (ret)<br />+ goto done;<br />+<br />+ /* Get a PIO buffer to use. */<br />+ if ((whichpb = ipath_getpiobuf(device)) < 0) {<br />+ ret = whichpb;<br />+ goto done;<br />+ }<br />+<br />+ pboff = devdata[device].ipath_piobufbase;<br />+ piobuf =<br />+ (uint32_t *) (((char *)(devdata[device].ipath_kregbase)) + pboff +<br />+ whichpb * devdata[device].ipath_palign);<br />+ _IPATH_EPDBG("0x%x+1w pio%d\n", plen - 1, whichpb);<br />+<br />+ /* len to control qword, no flags */<br />+ *((uint64_t *) piobuf) = (uint64_t) plen;<br />+ piobuf += 2;<br />+ ipath_dwordcpy(piobuf, hdr, (sizeof(ips_message_header_typ) >> 2));<br />+ piobuf += (sizeof(ips_message_header_typ) >> 2);<br />+ ipath_dwordcpy(piobuf, data, datawords);<br />+<br />+ ipath_stats.sps_ether_spkts++; /* another ether packet sent */<br />+<br />+done:<br />+ return ret;<br />+}<br />+<br />+void ipath_layer_set_piointbufavail_int(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return;<br />+ }<br />+<br />+ atomic_set_mask(INFINIPATH_S_PIOINTBUFAVAIL,<br />+ &devdata[device].ipath_sendctrl);<br />+<br />+ ipath_kput_kreg(device, kr_sendctrl, devdata[device].ipath_sendctrl);<br />+}<br />+<br />+void ipath_layer_enable_timer(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return;<br />+ }<br />+<br />+ /*<br />+ * HT-400 has a design flaw where the chip and kernel idea<br />+ * of the tail register don't always agree, and therefore we won't<br />+ * get an interrupt on the next packet received.<br />+ * If the board supports per packet receive interrupts, use it.<br />+ * Otherwise, the timer function periodically checks for packets<br />+ * to cover this case.<br />+ * Either way, the timer is needed for verbs layer related<br />+ * processing.<br />+ */<br />+ if (devdata[device].ipath_flags & IPATH_GPIO_INTR) {<br />+ ipath_kput_kreg(device, kr_debugportselect, 0x2074076542310UL);<br />+ /* Enable GPIO bit 2 interrupt */<br />+ ipath_kput_kreg(device, kr_gpio_mask, (uint64_t)(1 << 2));<br />+ }<br />+<br />+ init_timer(&devdata[device].verbs_layer.l_timer);<br />+ devdata[device].verbs_layer.l_timer.function = ipath_verbs_timer;<br />+ devdata[device].verbs_layer.l_timer.data = (unsigned long)device;<br />+ devdata[device].verbs_layer.l_timer.expires = jiffies + 1;<br />+ add_timer(&devdata[device].verbs_layer.l_timer);<br />+}<br />+<br />+void ipath_layer_disable_timer(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return;<br />+ }<br />+<br />+ /* Disable GPIO bit 2 interrupt */<br />+ if (devdata[device].ipath_flags & IPATH_GPIO_INTR)<br />+ ipath_kput_kreg(device, kr_gpio_mask, 0);<br />+<br />+ del_timer_sync(&devdata[device].verbs_layer.l_timer);<br />+}<br />+<br />+/*<br />+ * Get the verbs layer flags.<br />+ */<br />+unsigned ipath_verbs_get_flags(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+<br />+ return devdata[device].verbs_layer.l_flags;<br />+}<br />+<br />+/*<br />+ * Set the verbs layer flags.<br />+ */<br />+void ipath_verbs_set_flags(const ipath_type device, unsigned flags)<br />+{<br />+ ipath_type s;<br />+<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return;<br />+ }<br />+<br />+ devdata[device].verbs_layer.l_flags = flags;<br />+<br />+ for (s = 0; s < infinipath_max; s++) {<br />+ if (!(devdata[s].ipath_flags & IPATH_INITTED))<br />+ continue;<br />+ if ((flags & IPATH_VERBS_KERNEL_SMA) &&<br />+ !(*devdata[s].ipath_statusp & IPATH_STATUS_SMA)) {<br />+ *devdata[s].ipath_statusp |= IPATH_STATUS_OIB_SMA;<br />+ } else {<br />+ *devdata[s].ipath_statusp &= ~IPATH_STATUS_OIB_SMA;<br />+ }<br />+ }<br />+}<br />+<br />+/*<br />+ * Return the size of the PKEY table for port 0.<br />+ */<br />+unsigned ipath_layer_get_npkeys(const ipath_type device)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+<br />+ return ARRAY_SIZE(devdata[device].ipath_pd[0]->port_pkeys);<br />+}<br />+<br />+/*<br />+ * Return the indexed PKEY from the port 0 PKEY table.<br />+ */<br />+unsigned ipath_layer_get_pkey(const ipath_type device, unsigned index)<br />+{<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return 0;<br />+ }<br />+ if (index >= ARRAY_SIZE(devdata[device].ipath_pd[0]->port_pkeys))<br />+ return 0;<br />+<br />+ return devdata[device].ipath_pd[0]->port_pkeys[index];<br />+}<br />+<br />+/*<br />+ * Return the PKEY table for port 0.<br />+ */<br />+void ipath_layer_get_pkeys(const ipath_type device, uint16_t *pkeys)<br />+{<br />+ struct _ipath_portdata *pd;<br />+<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return;<br />+ }<br />+<br />+ pd = devdata[device].ipath_pd[0];<br />+ memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));<br />+}<br />+<br />+/*<br />+ * Decrecment the reference count for the given PKEY.<br />+ * Return true if this was the last reference and the hardware table entry<br />+ * needs to be changed.<br />+ */<br />+static inline int rm_pkey(ipath_devdata *dd, uint16_t key)<br />+{<br />+ int i;<br />+<br />+ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {<br />+ if (dd->ipath_pkeys[i] != key)<br />+ continue;<br />+ if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {<br />+ dd->ipath_pkeys[i] = 0;<br />+ return 1;<br />+ }<br />+ break;<br />+ }<br />+ return 0;<br />+}<br />+<br />+/*<br />+ * Add the given PKEY to the hardware table.<br />+ * Return an error code if unable to add the entry, zero if no change,<br />+ * or 1 if the hardware PKEY register needs to be updated.<br />+ */<br />+static inline int add_pkey(ipath_devdata *dd, uint16_t key)<br />+{<br />+ int i;<br />+ uint16_t lkey = key & 0x7FFF;<br />+ int any = 0;<br />+<br />+ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {<br />+ if (!dd->ipath_pkeys[i]) {<br />+ any++;<br />+ continue;<br />+ }<br />+ /* If it matches exactly, try to increment the ref count */<br />+ if (dd->ipath_pkeys[i] == key) {<br />+ if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1)<br />+ return 0;<br />+ /* Lost the race. Look for an empty slot below. */<br />+ atomic_dec(&dd->ipath_pkeyrefs[i]);<br />+ any++;<br />+ }<br />+ /*<br />+ * It makes no sense to have both the limited and unlimited<br />+ * PKEY set at the same time since the unlimited one will<br />+ * disable the limited one.<br />+ */<br />+ if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey)<br />+ return -EEXIST;<br />+ }<br />+ if (!any)<br />+ return -EBUSY;<br />+ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {<br />+ if (!dd->ipath_pkeys[i] &&<br />+ atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {<br />+ /* for ipathstats, etc. */<br />+ ipath_stats.sps_pkeys[i] = lkey;<br />+ dd->ipath_pkeys[i] = key;<br />+ return 1;<br />+ }<br />+ }<br />+ return -EBUSY;<br />+}<br />+<br />+/*<br />+ * Set the PKEY table for port 0.<br />+ */<br />+int ipath_layer_set_pkeys(const ipath_type device, uint16_t *pkeys)<br />+{<br />+ ipath_portdata *pd;<br />+ ipath_devdata *dd;<br />+ int i;<br />+ int changed = 0;<br />+<br />+ if (device >= infinipath_max) {<br />+ _IPATH_DBG("Invalid unit %u\n", device);<br />+ return -EINVAL;<br />+ }<br />+<br />+ dd = &devdata[device];<br />+ pd = dd->ipath_pd[0];<br />+<br />+ for (i = 0; i > ARRAY_SIZE(pd->port_pkeys); i++) {<br />+ uint16_t key = pkeys[i];<br />+ uint16_t okey = pd->port_pkeys[i];<br />+<br />+ if (key == okey)<br />+ continue;<br />+ /*<br />+ * The value of this PKEY table entry is changing.<br />+ * Remove the old entry in the hardware's array of PKEYs.<br />+ */<br />+ if (okey & 0x7FFF)<br />+ changed |= rm_pkey(dd, okey);<br />+ if (key & 0x7FFF) {<br />+ int ret = add_pkey(dd, key);<br />+<br />+ if (ret < 0)<br />+ key = 0;<br />+ else<br />+ changed |= ret;<br />+ }<br />+ pd->port_pkeys[i] = key;<br />+ }<br />+ if (changed) {<br />+ uint64_t pkey;<br />+<br />+ pkey = (uint64_t) dd->ipath_pkeys[0] |<br />+ ((uint64_t) dd->ipath_pkeys[1] << 16) |<br />+ ((uint64_t) dd->ipath_pkeys[2] << 32) |<br />+ ((uint64_t) dd->ipath_pkeys[3] << 48);<br />+ _IPATH_VDBG("p0 new pkey reg %llx\n", pkey);<br />+ ipath_kput_kreg(pd->port_unit, kr_partitionkey, pkey);<br />+ }<br />+ return 0;<br />+}<br />+<br />+/*<br />+ * Registers that vary with the chip implementation constants (port)<br />+ * use this routine.<br />+ */<br />+uint64_t ipath_kget_kreg64_port(const ipath_type stype, ipath_kreg regno,<br />+ unsigned port)<br />+{<br />+ ipath_kreg tmp =<br />+ (port < devdata[stype].ipath_portcnt && regno == kr_rcvhdraddr) ?<br />+ regno + port :<br />+ ((port < devdata[stype].ipath_portcnt<br />+ && regno == kr_rcvhdrtailaddr) ? regno + port : __kr_invalid);<br />+ return ipath_kget_kreg64(stype, tmp);<br />+}<br />+<br />+/*<br />+ * Registers that vary with the chip implementation constants (port)<br />+ * use this routine.<br />+ */<br />+void ipath_kput_kreg_port(const ipath_type stype, ipath_kreg regno,<br />+ unsigned port, uint64_t value)<br />+{<br />+ ipath_kreg tmp =<br />+ (port < devdata[stype].ipath_portcnt && regno == kr_rcvhdraddr) ?<br />+ regno + port :<br />+ ((port < devdata[stype].ipath_portcnt<br />+ && regno == kr_rcvhdrtailaddr) ? regno + port : __kr_invalid);<br />+ ipath_kput_kreg(stype, tmp, value);<br />+}<br />+<br />+EXPORT_SYMBOL(ipath_kset_linkstate);<br />+EXPORT_SYMBOL(ipath_kset_mtu);<br />+EXPORT_SYMBOL(ipath_layer_close);<br />+EXPORT_SYMBOL(ipath_layer_get_bcast);<br />+EXPORT_SYMBOL(ipath_layer_get_cr_errpkey);<br />+EXPORT_SYMBOL(ipath_layer_get_deviceid);<br />+EXPORT_SYMBOL(ipath_layer_get_flags);<br />+EXPORT_SYMBOL(ipath_layer_get_guid);<br />+EXPORT_SYMBOL(ipath_layer_get_ibmtu);<br />+EXPORT_SYMBOL(ipath_layer_get_lastibcstat);<br />+EXPORT_SYMBOL(ipath_layer_get_lid);<br />+EXPORT_SYMBOL(ipath_layer_get_mac);<br />+EXPORT_SYMBOL(ipath_layer_get_nguid);<br />+EXPORT_SYMBOL(ipath_layer_get_num_of_dev);<br />+EXPORT_SYMBOL(ipath_layer_get_pcidev);<br />+EXPORT_SYMBOL(ipath_layer_open);<br />+EXPORT_SYMBOL(ipath_layer_query_device);<br />+EXPORT_SYMBOL(ipath_layer_register);<br />+EXPORT_SYMBOL(ipath_layer_send);<br />+EXPORT_SYMBOL(ipath_layer_set_guid);<br />+EXPORT_SYMBOL(ipath_layer_set_piointbufavail_int);<br />+EXPORT_SYMBOL(ipath_layer_snapshot_counters);<br />+EXPORT_SYMBOL(ipath_layer_get_counters);<br />+EXPORT_SYMBOL(ipath_layer_want_buffer);<br />+EXPORT_SYMBOL(ipath_verbs_register);<br />+EXPORT_SYMBOL(ipath_verbs_send);<br />+EXPORT_SYMBOL(ipath_verbs_unregister);<br />+EXPORT_SYMBOL(ipath_set_sps_lid);<br />+EXPORT_SYMBOL(ipath_layer_enable_timer);<br />+EXPORT_SYMBOL(ipath_layer_disable_timer);<br />+EXPORT_SYMBOL(ipath_verbs_get_flags);<br />+EXPORT_SYMBOL(ipath_verbs_set_flags);<br />+EXPORT_SYMBOL(ipath_layer_get_npkeys);<br />+EXPORT_SYMBOL(ipath_layer_get_pkey);<br />+EXPORT_SYMBOL(ipath_layer_get_pkeys);<br />+EXPORT_SYMBOL(ipath_layer_set_pkeys);<br />-- <br />0.99.9n<br />-<br />To unsubscribe from this list: send the line "unsubscribe linux-kernel" in<br />the body of a message to majordomo@vger.kernel.org<br />More majordomo info at <a href="http://vger.kernel.org/majordomo-info.html">http://vger.kernel.org/majordomo-info.html</a><br />Please read the FAQ at <a href="http://www.tux.org/lkml/">http://www.tux.org/lkml/</a><br /></pre></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerr.gif" width="32" height="32" alt="\" /></td></tr><tr><td align="right" valign="bottom"> 聽 </td></tr><tr><td align="right" valign="bottom">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerl.gif" width="32" height="32" alt="\" /></td><td class="c">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerr.gif" width="32" height="32" alt="/" /></td></tr><tr><td align="right" valign="top" colspan="2"> 聽 </td><td class="lm">Last update: 2005-12-17 01:04 聽聽 [from the cache]<br />漏2003-2020 <a href="http://blog.jasper.es/"><span itemprop="editor">Jasper Spaans</span></a>|hosted at <a href="https://www.digitalocean.com/?refcode=9a8e99d24cf9">Digital Ocean</a> and my Meterkast|<a href="http://blog.jasper.es/categories.html#lkml-ref">Read the blog</a></td><td>聽</td></tr></table><script language="javascript" src="/js/styleswitcher.js" type="text/javascript"></script></body></html>