diff options
Diffstat (limited to 'drivers/infiniband/hw')
99 files changed, 23256 insertions, 2362 deletions
diff --git a/drivers/infiniband/hw/amso1100/Kbuild b/drivers/infiniband/hw/amso1100/Kbuild new file mode 100644 index 000000000000..06964c4af849 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/Kbuild | |||
@@ -0,0 +1,8 @@ | |||
1 | ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG | ||
2 | EXTRA_CFLAGS += -DDEBUG | ||
3 | endif | ||
4 | |||
5 | obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o | ||
6 | |||
7 | iw_c2-y := c2.o c2_provider.o c2_rnic.o c2_alloc.o c2_mq.o c2_ae.o c2_vq.o \ | ||
8 | c2_intr.o c2_cq.o c2_qp.o c2_cm.o c2_mm.o c2_pd.o | ||
diff --git a/drivers/infiniband/hw/amso1100/Kconfig b/drivers/infiniband/hw/amso1100/Kconfig new file mode 100644 index 000000000000..809cb14ac6de --- /dev/null +++ b/drivers/infiniband/hw/amso1100/Kconfig | |||
@@ -0,0 +1,15 @@ | |||
1 | config INFINIBAND_AMSO1100 | ||
2 | tristate "Ammasso 1100 HCA support" | ||
3 | depends on PCI && INET && INFINIBAND | ||
4 | ---help--- | ||
5 | This is a low-level driver for the Ammasso 1100 host | ||
6 | channel adapter (HCA). | ||
7 | |||
8 | config INFINIBAND_AMSO1100_DEBUG | ||
9 | bool "Verbose debugging output" | ||
10 | depends on INFINIBAND_AMSO1100 | ||
11 | default n | ||
12 | ---help--- | ||
13 | This option causes the amso1100 driver to produce a bunch of | ||
14 | debug messages. Select this if you are developing the driver | ||
15 | or trying to diagnose a problem. | ||
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c new file mode 100644 index 000000000000..9e9120f36019 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2.c | |||
@@ -0,0 +1,1255 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/moduleparam.h> | ||
35 | #include <linux/pci.h> | ||
36 | #include <linux/netdevice.h> | ||
37 | #include <linux/etherdevice.h> | ||
38 | #include <linux/inetdevice.h> | ||
39 | #include <linux/delay.h> | ||
40 | #include <linux/ethtool.h> | ||
41 | #include <linux/mii.h> | ||
42 | #include <linux/if_vlan.h> | ||
43 | #include <linux/crc32.h> | ||
44 | #include <linux/in.h> | ||
45 | #include <linux/ip.h> | ||
46 | #include <linux/tcp.h> | ||
47 | #include <linux/init.h> | ||
48 | #include <linux/dma-mapping.h> | ||
49 | |||
50 | #include <asm/io.h> | ||
51 | #include <asm/irq.h> | ||
52 | #include <asm/byteorder.h> | ||
53 | |||
54 | #include <rdma/ib_smi.h> | ||
55 | #include "c2.h" | ||
56 | #include "c2_provider.h" | ||
57 | |||
58 | MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>"); | ||
59 | MODULE_DESCRIPTION("Ammasso AMSO1100 Low-level iWARP Driver"); | ||
60 | MODULE_LICENSE("Dual BSD/GPL"); | ||
61 | MODULE_VERSION(DRV_VERSION); | ||
62 | |||
63 | static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | ||
64 | | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; | ||
65 | |||
66 | static int debug = -1; /* defaults above */ | ||
67 | module_param(debug, int, 0); | ||
68 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); | ||
69 | |||
70 | static int c2_up(struct net_device *netdev); | ||
71 | static int c2_down(struct net_device *netdev); | ||
72 | static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev); | ||
73 | static void c2_tx_interrupt(struct net_device *netdev); | ||
74 | static void c2_rx_interrupt(struct net_device *netdev); | ||
75 | static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
76 | static void c2_tx_timeout(struct net_device *netdev); | ||
77 | static int c2_change_mtu(struct net_device *netdev, int new_mtu); | ||
78 | static void c2_reset(struct c2_port *c2_port); | ||
79 | static struct net_device_stats *c2_get_stats(struct net_device *netdev); | ||
80 | |||
81 | static struct pci_device_id c2_pci_table[] = { | ||
82 | { PCI_DEVICE(0x18b8, 0xb001) }, | ||
83 | { 0 } | ||
84 | }; | ||
85 | |||
86 | MODULE_DEVICE_TABLE(pci, c2_pci_table); | ||
87 | |||
88 | static void c2_print_macaddr(struct net_device *netdev) | ||
89 | { | ||
90 | pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, " | ||
91 | "IRQ %u\n", netdev->name, | ||
92 | netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], | ||
93 | netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5], | ||
94 | netdev->irq); | ||
95 | } | ||
96 | |||
97 | static void c2_set_rxbufsize(struct c2_port *c2_port) | ||
98 | { | ||
99 | struct net_device *netdev = c2_port->netdev; | ||
100 | |||
101 | if (netdev->mtu > RX_BUF_SIZE) | ||
102 | c2_port->rx_buf_size = | ||
103 | netdev->mtu + ETH_HLEN + sizeof(struct c2_rxp_hdr) + | ||
104 | NET_IP_ALIGN; | ||
105 | else | ||
106 | c2_port->rx_buf_size = sizeof(struct c2_rxp_hdr) + RX_BUF_SIZE; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * Allocate TX ring elements and chain them together. | ||
111 | * One-to-one association of adapter descriptors with ring elements. | ||
112 | */ | ||
113 | static int c2_tx_ring_alloc(struct c2_ring *tx_ring, void *vaddr, | ||
114 | dma_addr_t base, void __iomem * mmio_txp_ring) | ||
115 | { | ||
116 | struct c2_tx_desc *tx_desc; | ||
117 | struct c2_txp_desc __iomem *txp_desc; | ||
118 | struct c2_element *elem; | ||
119 | int i; | ||
120 | |||
121 | tx_ring->start = kmalloc(sizeof(*elem) * tx_ring->count, GFP_KERNEL); | ||
122 | if (!tx_ring->start) | ||
123 | return -ENOMEM; | ||
124 | |||
125 | elem = tx_ring->start; | ||
126 | tx_desc = vaddr; | ||
127 | txp_desc = mmio_txp_ring; | ||
128 | for (i = 0; i < tx_ring->count; i++, elem++, tx_desc++, txp_desc++) { | ||
129 | tx_desc->len = 0; | ||
130 | tx_desc->status = 0; | ||
131 | |||
132 | /* Set TXP_HTXD_UNINIT */ | ||
133 | __raw_writeq(cpu_to_be64(0x1122334455667788ULL), | ||
134 | (void __iomem *) txp_desc + C2_TXP_ADDR); | ||
135 | __raw_writew(0, (void __iomem *) txp_desc + C2_TXP_LEN); | ||
136 | __raw_writew(cpu_to_be16(TXP_HTXD_UNINIT), | ||
137 | (void __iomem *) txp_desc + C2_TXP_FLAGS); | ||
138 | |||
139 | elem->skb = NULL; | ||
140 | elem->ht_desc = tx_desc; | ||
141 | elem->hw_desc = txp_desc; | ||
142 | |||
143 | if (i == tx_ring->count - 1) { | ||
144 | elem->next = tx_ring->start; | ||
145 | tx_desc->next_offset = base; | ||
146 | } else { | ||
147 | elem->next = elem + 1; | ||
148 | tx_desc->next_offset = | ||
149 | base + (i + 1) * sizeof(*tx_desc); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | tx_ring->to_use = tx_ring->to_clean = tx_ring->start; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Allocate RX ring elements and chain them together. | ||
160 | * One-to-one association of adapter descriptors with ring elements. | ||
161 | */ | ||
162 | static int c2_rx_ring_alloc(struct c2_ring *rx_ring, void *vaddr, | ||
163 | dma_addr_t base, void __iomem * mmio_rxp_ring) | ||
164 | { | ||
165 | struct c2_rx_desc *rx_desc; | ||
166 | struct c2_rxp_desc __iomem *rxp_desc; | ||
167 | struct c2_element *elem; | ||
168 | int i; | ||
169 | |||
170 | rx_ring->start = kmalloc(sizeof(*elem) * rx_ring->count, GFP_KERNEL); | ||
171 | if (!rx_ring->start) | ||
172 | return -ENOMEM; | ||
173 | |||
174 | elem = rx_ring->start; | ||
175 | rx_desc = vaddr; | ||
176 | rxp_desc = mmio_rxp_ring; | ||
177 | for (i = 0; i < rx_ring->count; i++, elem++, rx_desc++, rxp_desc++) { | ||
178 | rx_desc->len = 0; | ||
179 | rx_desc->status = 0; | ||
180 | |||
181 | /* Set RXP_HRXD_UNINIT */ | ||
182 | __raw_writew(cpu_to_be16(RXP_HRXD_OK), | ||
183 | (void __iomem *) rxp_desc + C2_RXP_STATUS); | ||
184 | __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_COUNT); | ||
185 | __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_LEN); | ||
186 | __raw_writeq(cpu_to_be64(0x99aabbccddeeffULL), | ||
187 | (void __iomem *) rxp_desc + C2_RXP_ADDR); | ||
188 | __raw_writew(cpu_to_be16(RXP_HRXD_UNINIT), | ||
189 | (void __iomem *) rxp_desc + C2_RXP_FLAGS); | ||
190 | |||
191 | elem->skb = NULL; | ||
192 | elem->ht_desc = rx_desc; | ||
193 | elem->hw_desc = rxp_desc; | ||
194 | |||
195 | if (i == rx_ring->count - 1) { | ||
196 | elem->next = rx_ring->start; | ||
197 | rx_desc->next_offset = base; | ||
198 | } else { | ||
199 | elem->next = elem + 1; | ||
200 | rx_desc->next_offset = | ||
201 | base + (i + 1) * sizeof(*rx_desc); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | rx_ring->to_use = rx_ring->to_clean = rx_ring->start; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* Setup buffer for receiving */ | ||
211 | static inline int c2_rx_alloc(struct c2_port *c2_port, struct c2_element *elem) | ||
212 | { | ||
213 | struct c2_dev *c2dev = c2_port->c2dev; | ||
214 | struct c2_rx_desc *rx_desc = elem->ht_desc; | ||
215 | struct sk_buff *skb; | ||
216 | dma_addr_t mapaddr; | ||
217 | u32 maplen; | ||
218 | struct c2_rxp_hdr *rxp_hdr; | ||
219 | |||
220 | skb = dev_alloc_skb(c2_port->rx_buf_size); | ||
221 | if (unlikely(!skb)) { | ||
222 | pr_debug("%s: out of memory for receive\n", | ||
223 | c2_port->netdev->name); | ||
224 | return -ENOMEM; | ||
225 | } | ||
226 | |||
227 | /* Zero out the rxp hdr in the sk_buff */ | ||
228 | memset(skb->data, 0, sizeof(*rxp_hdr)); | ||
229 | |||
230 | skb->dev = c2_port->netdev; | ||
231 | |||
232 | maplen = c2_port->rx_buf_size; | ||
233 | mapaddr = | ||
234 | pci_map_single(c2dev->pcidev, skb->data, maplen, | ||
235 | PCI_DMA_FROMDEVICE); | ||
236 | |||
237 | /* Set the sk_buff RXP_header to RXP_HRXD_READY */ | ||
238 | rxp_hdr = (struct c2_rxp_hdr *) skb->data; | ||
239 | rxp_hdr->flags = RXP_HRXD_READY; | ||
240 | |||
241 | __raw_writew(0, elem->hw_desc + C2_RXP_STATUS); | ||
242 | __raw_writew(cpu_to_be16((u16) maplen - sizeof(*rxp_hdr)), | ||
243 | elem->hw_desc + C2_RXP_LEN); | ||
244 | __raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_RXP_ADDR); | ||
245 | __raw_writew(cpu_to_be16(RXP_HRXD_READY), elem->hw_desc + C2_RXP_FLAGS); | ||
246 | |||
247 | elem->skb = skb; | ||
248 | elem->mapaddr = mapaddr; | ||
249 | elem->maplen = maplen; | ||
250 | rx_desc->len = maplen; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * Allocate buffers for the Rx ring | ||
257 | * For receive: rx_ring.to_clean is next received frame | ||
258 | */ | ||
259 | static int c2_rx_fill(struct c2_port *c2_port) | ||
260 | { | ||
261 | struct c2_ring *rx_ring = &c2_port->rx_ring; | ||
262 | struct c2_element *elem; | ||
263 | int ret = 0; | ||
264 | |||
265 | elem = rx_ring->start; | ||
266 | do { | ||
267 | if (c2_rx_alloc(c2_port, elem)) { | ||
268 | ret = 1; | ||
269 | break; | ||
270 | } | ||
271 | } while ((elem = elem->next) != rx_ring->start); | ||
272 | |||
273 | rx_ring->to_clean = rx_ring->start; | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | /* Free all buffers in RX ring, assumes receiver stopped */ | ||
278 | static void c2_rx_clean(struct c2_port *c2_port) | ||
279 | { | ||
280 | struct c2_dev *c2dev = c2_port->c2dev; | ||
281 | struct c2_ring *rx_ring = &c2_port->rx_ring; | ||
282 | struct c2_element *elem; | ||
283 | struct c2_rx_desc *rx_desc; | ||
284 | |||
285 | elem = rx_ring->start; | ||
286 | do { | ||
287 | rx_desc = elem->ht_desc; | ||
288 | rx_desc->len = 0; | ||
289 | |||
290 | __raw_writew(0, elem->hw_desc + C2_RXP_STATUS); | ||
291 | __raw_writew(0, elem->hw_desc + C2_RXP_COUNT); | ||
292 | __raw_writew(0, elem->hw_desc + C2_RXP_LEN); | ||
293 | __raw_writeq(cpu_to_be64(0x99aabbccddeeffULL), | ||
294 | elem->hw_desc + C2_RXP_ADDR); | ||
295 | __raw_writew(cpu_to_be16(RXP_HRXD_UNINIT), | ||
296 | elem->hw_desc + C2_RXP_FLAGS); | ||
297 | |||
298 | if (elem->skb) { | ||
299 | pci_unmap_single(c2dev->pcidev, elem->mapaddr, | ||
300 | elem->maplen, PCI_DMA_FROMDEVICE); | ||
301 | dev_kfree_skb(elem->skb); | ||
302 | elem->skb = NULL; | ||
303 | } | ||
304 | } while ((elem = elem->next) != rx_ring->start); | ||
305 | } | ||
306 | |||
307 | static inline int c2_tx_free(struct c2_dev *c2dev, struct c2_element *elem) | ||
308 | { | ||
309 | struct c2_tx_desc *tx_desc = elem->ht_desc; | ||
310 | |||
311 | tx_desc->len = 0; | ||
312 | |||
313 | pci_unmap_single(c2dev->pcidev, elem->mapaddr, elem->maplen, | ||
314 | PCI_DMA_TODEVICE); | ||
315 | |||
316 | if (elem->skb) { | ||
317 | dev_kfree_skb_any(elem->skb); | ||
318 | elem->skb = NULL; | ||
319 | } | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | /* Free all buffers in TX ring, assumes transmitter stopped */ | ||
325 | static void c2_tx_clean(struct c2_port *c2_port) | ||
326 | { | ||
327 | struct c2_ring *tx_ring = &c2_port->tx_ring; | ||
328 | struct c2_element *elem; | ||
329 | struct c2_txp_desc txp_htxd; | ||
330 | int retry; | ||
331 | unsigned long flags; | ||
332 | |||
333 | spin_lock_irqsave(&c2_port->tx_lock, flags); | ||
334 | |||
335 | elem = tx_ring->start; | ||
336 | |||
337 | do { | ||
338 | retry = 0; | ||
339 | do { | ||
340 | txp_htxd.flags = | ||
341 | readw(elem->hw_desc + C2_TXP_FLAGS); | ||
342 | |||
343 | if (txp_htxd.flags == TXP_HTXD_READY) { | ||
344 | retry = 1; | ||
345 | __raw_writew(0, | ||
346 | elem->hw_desc + C2_TXP_LEN); | ||
347 | __raw_writeq(0, | ||
348 | elem->hw_desc + C2_TXP_ADDR); | ||
349 | __raw_writew(cpu_to_be16(TXP_HTXD_DONE), | ||
350 | elem->hw_desc + C2_TXP_FLAGS); | ||
351 | c2_port->netstats.tx_dropped++; | ||
352 | break; | ||
353 | } else { | ||
354 | __raw_writew(0, | ||
355 | elem->hw_desc + C2_TXP_LEN); | ||
356 | __raw_writeq(cpu_to_be64(0x1122334455667788ULL), | ||
357 | elem->hw_desc + C2_TXP_ADDR); | ||
358 | __raw_writew(cpu_to_be16(TXP_HTXD_UNINIT), | ||
359 | elem->hw_desc + C2_TXP_FLAGS); | ||
360 | } | ||
361 | |||
362 | c2_tx_free(c2_port->c2dev, elem); | ||
363 | |||
364 | } while ((elem = elem->next) != tx_ring->start); | ||
365 | } while (retry); | ||
366 | |||
367 | c2_port->tx_avail = c2_port->tx_ring.count - 1; | ||
368 | c2_port->c2dev->cur_tx = tx_ring->to_use - tx_ring->start; | ||
369 | |||
370 | if (c2_port->tx_avail > MAX_SKB_FRAGS + 1) | ||
371 | netif_wake_queue(c2_port->netdev); | ||
372 | |||
373 | spin_unlock_irqrestore(&c2_port->tx_lock, flags); | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * Process transmit descriptors marked 'DONE' by the firmware, | ||
378 | * freeing up their unneeded sk_buffs. | ||
379 | */ | ||
380 | static void c2_tx_interrupt(struct net_device *netdev) | ||
381 | { | ||
382 | struct c2_port *c2_port = netdev_priv(netdev); | ||
383 | struct c2_dev *c2dev = c2_port->c2dev; | ||
384 | struct c2_ring *tx_ring = &c2_port->tx_ring; | ||
385 | struct c2_element *elem; | ||
386 | struct c2_txp_desc txp_htxd; | ||
387 | |||
388 | spin_lock(&c2_port->tx_lock); | ||
389 | |||
390 | for (elem = tx_ring->to_clean; elem != tx_ring->to_use; | ||
391 | elem = elem->next) { | ||
392 | txp_htxd.flags = | ||
393 | be16_to_cpu(readw(elem->hw_desc + C2_TXP_FLAGS)); | ||
394 | |||
395 | if (txp_htxd.flags != TXP_HTXD_DONE) | ||
396 | break; | ||
397 | |||
398 | if (netif_msg_tx_done(c2_port)) { | ||
399 | /* PCI reads are expensive in fast path */ | ||
400 | txp_htxd.len = | ||
401 | be16_to_cpu(readw(elem->hw_desc + C2_TXP_LEN)); | ||
402 | pr_debug("%s: tx done slot %3Zu status 0x%x len " | ||
403 | "%5u bytes\n", | ||
404 | netdev->name, elem - tx_ring->start, | ||
405 | txp_htxd.flags, txp_htxd.len); | ||
406 | } | ||
407 | |||
408 | c2_tx_free(c2dev, elem); | ||
409 | ++(c2_port->tx_avail); | ||
410 | } | ||
411 | |||
412 | tx_ring->to_clean = elem; | ||
413 | |||
414 | if (netif_queue_stopped(netdev) | ||
415 | && c2_port->tx_avail > MAX_SKB_FRAGS + 1) | ||
416 | netif_wake_queue(netdev); | ||
417 | |||
418 | spin_unlock(&c2_port->tx_lock); | ||
419 | } | ||
420 | |||
421 | static void c2_rx_error(struct c2_port *c2_port, struct c2_element *elem) | ||
422 | { | ||
423 | struct c2_rx_desc *rx_desc = elem->ht_desc; | ||
424 | struct c2_rxp_hdr *rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data; | ||
425 | |||
426 | if (rxp_hdr->status != RXP_HRXD_OK || | ||
427 | rxp_hdr->len > (rx_desc->len - sizeof(*rxp_hdr))) { | ||
428 | pr_debug("BAD RXP_HRXD\n"); | ||
429 | pr_debug(" rx_desc : %p\n", rx_desc); | ||
430 | pr_debug(" index : %Zu\n", | ||
431 | elem - c2_port->rx_ring.start); | ||
432 | pr_debug(" len : %u\n", rx_desc->len); | ||
433 | pr_debug(" rxp_hdr : %p [PA %p]\n", rxp_hdr, | ||
434 | (void *) __pa((unsigned long) rxp_hdr)); | ||
435 | pr_debug(" flags : 0x%x\n", rxp_hdr->flags); | ||
436 | pr_debug(" status: 0x%x\n", rxp_hdr->status); | ||
437 | pr_debug(" len : %u\n", rxp_hdr->len); | ||
438 | pr_debug(" rsvd : 0x%x\n", rxp_hdr->rsvd); | ||
439 | } | ||
440 | |||
441 | /* Setup the skb for reuse since we're dropping this pkt */ | ||
442 | elem->skb->tail = elem->skb->data = elem->skb->head; | ||
443 | |||
444 | /* Zero out the rxp hdr in the sk_buff */ | ||
445 | memset(elem->skb->data, 0, sizeof(*rxp_hdr)); | ||
446 | |||
447 | /* Write the descriptor to the adapter's rx ring */ | ||
448 | __raw_writew(0, elem->hw_desc + C2_RXP_STATUS); | ||
449 | __raw_writew(0, elem->hw_desc + C2_RXP_COUNT); | ||
450 | __raw_writew(cpu_to_be16((u16) elem->maplen - sizeof(*rxp_hdr)), | ||
451 | elem->hw_desc + C2_RXP_LEN); | ||
452 | __raw_writeq(cpu_to_be64(elem->mapaddr), elem->hw_desc + C2_RXP_ADDR); | ||
453 | __raw_writew(cpu_to_be16(RXP_HRXD_READY), elem->hw_desc + C2_RXP_FLAGS); | ||
454 | |||
455 | pr_debug("packet dropped\n"); | ||
456 | c2_port->netstats.rx_dropped++; | ||
457 | } | ||
458 | |||
459 | static void c2_rx_interrupt(struct net_device *netdev) | ||
460 | { | ||
461 | struct c2_port *c2_port = netdev_priv(netdev); | ||
462 | struct c2_dev *c2dev = c2_port->c2dev; | ||
463 | struct c2_ring *rx_ring = &c2_port->rx_ring; | ||
464 | struct c2_element *elem; | ||
465 | struct c2_rx_desc *rx_desc; | ||
466 | struct c2_rxp_hdr *rxp_hdr; | ||
467 | struct sk_buff *skb; | ||
468 | dma_addr_t mapaddr; | ||
469 | u32 maplen, buflen; | ||
470 | unsigned long flags; | ||
471 | |||
472 | spin_lock_irqsave(&c2dev->lock, flags); | ||
473 | |||
474 | /* Begin where we left off */ | ||
475 | rx_ring->to_clean = rx_ring->start + c2dev->cur_rx; | ||
476 | |||
477 | for (elem = rx_ring->to_clean; elem->next != rx_ring->to_clean; | ||
478 | elem = elem->next) { | ||
479 | rx_desc = elem->ht_desc; | ||
480 | mapaddr = elem->mapaddr; | ||
481 | maplen = elem->maplen; | ||
482 | skb = elem->skb; | ||
483 | rxp_hdr = (struct c2_rxp_hdr *) skb->data; | ||
484 | |||
485 | if (rxp_hdr->flags != RXP_HRXD_DONE) | ||
486 | break; | ||
487 | buflen = rxp_hdr->len; | ||
488 | |||
489 | /* Sanity check the RXP header */ | ||
490 | if (rxp_hdr->status != RXP_HRXD_OK || | ||
491 | buflen > (rx_desc->len - sizeof(*rxp_hdr))) { | ||
492 | c2_rx_error(c2_port, elem); | ||
493 | continue; | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * Allocate and map a new skb for replenishing the host | ||
498 | * RX desc | ||
499 | */ | ||
500 | if (c2_rx_alloc(c2_port, elem)) { | ||
501 | c2_rx_error(c2_port, elem); | ||
502 | continue; | ||
503 | } | ||
504 | |||
505 | /* Unmap the old skb */ | ||
506 | pci_unmap_single(c2dev->pcidev, mapaddr, maplen, | ||
507 | PCI_DMA_FROMDEVICE); | ||
508 | |||
509 | prefetch(skb->data); | ||
510 | |||
511 | /* | ||
512 | * Skip past the leading 8 bytes comprising of the | ||
513 | * "struct c2_rxp_hdr", prepended by the adapter | ||
514 | * to the usual Ethernet header ("struct ethhdr"), | ||
515 | * to the start of the raw Ethernet packet. | ||
516 | * | ||
517 | * Fix up the various fields in the sk_buff before | ||
518 | * passing it up to netif_rx(). The transfer size | ||
519 | * (in bytes) specified by the adapter len field of | ||
520 | * the "struct rxp_hdr_t" does NOT include the | ||
521 | * "sizeof(struct c2_rxp_hdr)". | ||
522 | */ | ||
523 | skb->data += sizeof(*rxp_hdr); | ||
524 | skb->tail = skb->data + buflen; | ||
525 | skb->len = buflen; | ||
526 | skb->dev = netdev; | ||
527 | skb->protocol = eth_type_trans(skb, netdev); | ||
528 | |||
529 | netif_rx(skb); | ||
530 | |||
531 | netdev->last_rx = jiffies; | ||
532 | c2_port->netstats.rx_packets++; | ||
533 | c2_port->netstats.rx_bytes += buflen; | ||
534 | } | ||
535 | |||
536 | /* Save where we left off */ | ||
537 | rx_ring->to_clean = elem; | ||
538 | c2dev->cur_rx = elem - rx_ring->start; | ||
539 | C2_SET_CUR_RX(c2dev, c2dev->cur_rx); | ||
540 | |||
541 | spin_unlock_irqrestore(&c2dev->lock, flags); | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * Handle netisr0 TX & RX interrupts. | ||
546 | */ | ||
547 | static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
548 | { | ||
549 | unsigned int netisr0, dmaisr; | ||
550 | int handled = 0; | ||
551 | struct c2_dev *c2dev = (struct c2_dev *) dev_id; | ||
552 | |||
553 | /* Process CCILNET interrupts */ | ||
554 | netisr0 = readl(c2dev->regs + C2_NISR0); | ||
555 | if (netisr0) { | ||
556 | |||
557 | /* | ||
558 | * There is an issue with the firmware that always | ||
559 | * provides the status of RX for both TX & RX | ||
560 | * interrupts. So process both queues here. | ||
561 | */ | ||
562 | c2_rx_interrupt(c2dev->netdev); | ||
563 | c2_tx_interrupt(c2dev->netdev); | ||
564 | |||
565 | /* Clear the interrupt */ | ||
566 | writel(netisr0, c2dev->regs + C2_NISR0); | ||
567 | handled++; | ||
568 | } | ||
569 | |||
570 | /* Process RNIC interrupts */ | ||
571 | dmaisr = readl(c2dev->regs + C2_DISR); | ||
572 | if (dmaisr) { | ||
573 | writel(dmaisr, c2dev->regs + C2_DISR); | ||
574 | c2_rnic_interrupt(c2dev); | ||
575 | handled++; | ||
576 | } | ||
577 | |||
578 | if (handled) { | ||
579 | return IRQ_HANDLED; | ||
580 | } else { | ||
581 | return IRQ_NONE; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | static int c2_up(struct net_device *netdev) | ||
586 | { | ||
587 | struct c2_port *c2_port = netdev_priv(netdev); | ||
588 | struct c2_dev *c2dev = c2_port->c2dev; | ||
589 | struct c2_element *elem; | ||
590 | struct c2_rxp_hdr *rxp_hdr; | ||
591 | struct in_device *in_dev; | ||
592 | size_t rx_size, tx_size; | ||
593 | int ret, i; | ||
594 | unsigned int netimr0; | ||
595 | |||
596 | if (netif_msg_ifup(c2_port)) | ||
597 | pr_debug("%s: enabling interface\n", netdev->name); | ||
598 | |||
599 | /* Set the Rx buffer size based on MTU */ | ||
600 | c2_set_rxbufsize(c2_port); | ||
601 | |||
602 | /* Allocate DMA'able memory for Tx/Rx host descriptor rings */ | ||
603 | rx_size = c2_port->rx_ring.count * sizeof(struct c2_rx_desc); | ||
604 | tx_size = c2_port->tx_ring.count * sizeof(struct c2_tx_desc); | ||
605 | |||
606 | c2_port->mem_size = tx_size + rx_size; | ||
607 | c2_port->mem = pci_alloc_consistent(c2dev->pcidev, c2_port->mem_size, | ||
608 | &c2_port->dma); | ||
609 | if (c2_port->mem == NULL) { | ||
610 | pr_debug("Unable to allocate memory for " | ||
611 | "host descriptor rings\n"); | ||
612 | return -ENOMEM; | ||
613 | } | ||
614 | |||
615 | memset(c2_port->mem, 0, c2_port->mem_size); | ||
616 | |||
617 | /* Create the Rx host descriptor ring */ | ||
618 | if ((ret = | ||
619 | c2_rx_ring_alloc(&c2_port->rx_ring, c2_port->mem, c2_port->dma, | ||
620 | c2dev->mmio_rxp_ring))) { | ||
621 | pr_debug("Unable to create RX ring\n"); | ||
622 | goto bail0; | ||
623 | } | ||
624 | |||
625 | /* Allocate Rx buffers for the host descriptor ring */ | ||
626 | if (c2_rx_fill(c2_port)) { | ||
627 | pr_debug("Unable to fill RX ring\n"); | ||
628 | goto bail1; | ||
629 | } | ||
630 | |||
631 | /* Create the Tx host descriptor ring */ | ||
632 | if ((ret = c2_tx_ring_alloc(&c2_port->tx_ring, c2_port->mem + rx_size, | ||
633 | c2_port->dma + rx_size, | ||
634 | c2dev->mmio_txp_ring))) { | ||
635 | pr_debug("Unable to create TX ring\n"); | ||
636 | goto bail1; | ||
637 | } | ||
638 | |||
639 | /* Set the TX pointer to where we left off */ | ||
640 | c2_port->tx_avail = c2_port->tx_ring.count - 1; | ||
641 | c2_port->tx_ring.to_use = c2_port->tx_ring.to_clean = | ||
642 | c2_port->tx_ring.start + c2dev->cur_tx; | ||
643 | |||
644 | /* missing: Initialize MAC */ | ||
645 | |||
646 | BUG_ON(c2_port->tx_ring.to_use != c2_port->tx_ring.to_clean); | ||
647 | |||
648 | /* Reset the adapter, ensures the driver is in sync with the RXP */ | ||
649 | c2_reset(c2_port); | ||
650 | |||
651 | /* Reset the READY bit in the sk_buff RXP headers & adapter HRXDQ */ | ||
652 | for (i = 0, elem = c2_port->rx_ring.start; i < c2_port->rx_ring.count; | ||
653 | i++, elem++) { | ||
654 | rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data; | ||
655 | rxp_hdr->flags = 0; | ||
656 | __raw_writew(cpu_to_be16(RXP_HRXD_READY), | ||
657 | elem->hw_desc + C2_RXP_FLAGS); | ||
658 | } | ||
659 | |||
660 | /* Enable network packets */ | ||
661 | netif_start_queue(netdev); | ||
662 | |||
663 | /* Enable IRQ */ | ||
664 | writel(0, c2dev->regs + C2_IDIS); | ||
665 | netimr0 = readl(c2dev->regs + C2_NIMR0); | ||
666 | netimr0 &= ~(C2_PCI_HTX_INT | C2_PCI_HRX_INT); | ||
667 | writel(netimr0, c2dev->regs + C2_NIMR0); | ||
668 | |||
669 | /* Tell the stack to ignore arp requests for ipaddrs bound to | ||
670 | * other interfaces. This is needed to prevent the host stack | ||
671 | * from responding to arp requests to the ipaddr bound on the | ||
672 | * rdma interface. | ||
673 | */ | ||
674 | in_dev = in_dev_get(netdev); | ||
675 | in_dev->cnf.arp_ignore = 1; | ||
676 | in_dev_put(in_dev); | ||
677 | |||
678 | return 0; | ||
679 | |||
680 | bail1: | ||
681 | c2_rx_clean(c2_port); | ||
682 | kfree(c2_port->rx_ring.start); | ||
683 | |||
684 | bail0: | ||
685 | pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem, | ||
686 | c2_port->dma); | ||
687 | |||
688 | return ret; | ||
689 | } | ||
690 | |||
691 | static int c2_down(struct net_device *netdev) | ||
692 | { | ||
693 | struct c2_port *c2_port = netdev_priv(netdev); | ||
694 | struct c2_dev *c2dev = c2_port->c2dev; | ||
695 | |||
696 | if (netif_msg_ifdown(c2_port)) | ||
697 | pr_debug("%s: disabling interface\n", | ||
698 | netdev->name); | ||
699 | |||
700 | /* Wait for all the queued packets to get sent */ | ||
701 | c2_tx_interrupt(netdev); | ||
702 | |||
703 | /* Disable network packets */ | ||
704 | netif_stop_queue(netdev); | ||
705 | |||
706 | /* Disable IRQs by clearing the interrupt mask */ | ||
707 | writel(1, c2dev->regs + C2_IDIS); | ||
708 | writel(0, c2dev->regs + C2_NIMR0); | ||
709 | |||
710 | /* missing: Stop transmitter */ | ||
711 | |||
712 | /* missing: Stop receiver */ | ||
713 | |||
714 | /* Reset the adapter, ensures the driver is in sync with the RXP */ | ||
715 | c2_reset(c2_port); | ||
716 | |||
717 | /* missing: Turn off LEDs here */ | ||
718 | |||
719 | /* Free all buffers in the host descriptor rings */ | ||
720 | c2_tx_clean(c2_port); | ||
721 | c2_rx_clean(c2_port); | ||
722 | |||
723 | /* Free the host descriptor rings */ | ||
724 | kfree(c2_port->rx_ring.start); | ||
725 | kfree(c2_port->tx_ring.start); | ||
726 | pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem, | ||
727 | c2_port->dma); | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static void c2_reset(struct c2_port *c2_port) | ||
733 | { | ||
734 | struct c2_dev *c2dev = c2_port->c2dev; | ||
735 | unsigned int cur_rx = c2dev->cur_rx; | ||
736 | |||
737 | /* Tell the hardware to quiesce */ | ||
738 | C2_SET_CUR_RX(c2dev, cur_rx | C2_PCI_HRX_QUI); | ||
739 | |||
740 | /* | ||
741 | * The hardware will reset the C2_PCI_HRX_QUI bit once | ||
742 | * the RXP is quiesced. Wait 2 seconds for this. | ||
743 | */ | ||
744 | ssleep(2); | ||
745 | |||
746 | cur_rx = C2_GET_CUR_RX(c2dev); | ||
747 | |||
748 | if (cur_rx & C2_PCI_HRX_QUI) | ||
749 | pr_debug("c2_reset: failed to quiesce the hardware!\n"); | ||
750 | |||
751 | cur_rx &= ~C2_PCI_HRX_QUI; | ||
752 | |||
753 | c2dev->cur_rx = cur_rx; | ||
754 | |||
755 | pr_debug("Current RX: %u\n", c2dev->cur_rx); | ||
756 | } | ||
757 | |||
758 | static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | ||
759 | { | ||
760 | struct c2_port *c2_port = netdev_priv(netdev); | ||
761 | struct c2_dev *c2dev = c2_port->c2dev; | ||
762 | struct c2_ring *tx_ring = &c2_port->tx_ring; | ||
763 | struct c2_element *elem; | ||
764 | dma_addr_t mapaddr; | ||
765 | u32 maplen; | ||
766 | unsigned long flags; | ||
767 | unsigned int i; | ||
768 | |||
769 | spin_lock_irqsave(&c2_port->tx_lock, flags); | ||
770 | |||
771 | if (unlikely(c2_port->tx_avail < (skb_shinfo(skb)->nr_frags + 1))) { | ||
772 | netif_stop_queue(netdev); | ||
773 | spin_unlock_irqrestore(&c2_port->tx_lock, flags); | ||
774 | |||
775 | pr_debug("%s: Tx ring full when queue awake!\n", | ||
776 | netdev->name); | ||
777 | return NETDEV_TX_BUSY; | ||
778 | } | ||
779 | |||
780 | maplen = skb_headlen(skb); | ||
781 | mapaddr = | ||
782 | pci_map_single(c2dev->pcidev, skb->data, maplen, PCI_DMA_TODEVICE); | ||
783 | |||
784 | elem = tx_ring->to_use; | ||
785 | elem->skb = skb; | ||
786 | elem->mapaddr = mapaddr; | ||
787 | elem->maplen = maplen; | ||
788 | |||
789 | /* Tell HW to xmit */ | ||
790 | __raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_TXP_ADDR); | ||
791 | __raw_writew(cpu_to_be16(maplen), elem->hw_desc + C2_TXP_LEN); | ||
792 | __raw_writew(cpu_to_be16(TXP_HTXD_READY), elem->hw_desc + C2_TXP_FLAGS); | ||
793 | |||
794 | c2_port->netstats.tx_packets++; | ||
795 | c2_port->netstats.tx_bytes += maplen; | ||
796 | |||
797 | /* Loop thru additional data fragments and queue them */ | ||
798 | if (skb_shinfo(skb)->nr_frags) { | ||
799 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||
800 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||
801 | maplen = frag->size; | ||
802 | mapaddr = | ||
803 | pci_map_page(c2dev->pcidev, frag->page, | ||
804 | frag->page_offset, maplen, | ||
805 | PCI_DMA_TODEVICE); | ||
806 | |||
807 | elem = elem->next; | ||
808 | elem->skb = NULL; | ||
809 | elem->mapaddr = mapaddr; | ||
810 | elem->maplen = maplen; | ||
811 | |||
812 | /* Tell HW to xmit */ | ||
813 | __raw_writeq(cpu_to_be64(mapaddr), | ||
814 | elem->hw_desc + C2_TXP_ADDR); | ||
815 | __raw_writew(cpu_to_be16(maplen), | ||
816 | elem->hw_desc + C2_TXP_LEN); | ||
817 | __raw_writew(cpu_to_be16(TXP_HTXD_READY), | ||
818 | elem->hw_desc + C2_TXP_FLAGS); | ||
819 | |||
820 | c2_port->netstats.tx_packets++; | ||
821 | c2_port->netstats.tx_bytes += maplen; | ||
822 | } | ||
823 | } | ||
824 | |||
825 | tx_ring->to_use = elem->next; | ||
826 | c2_port->tx_avail -= (skb_shinfo(skb)->nr_frags + 1); | ||
827 | |||
828 | if (c2_port->tx_avail <= MAX_SKB_FRAGS + 1) { | ||
829 | netif_stop_queue(netdev); | ||
830 | if (netif_msg_tx_queued(c2_port)) | ||
831 | pr_debug("%s: transmit queue full\n", | ||
832 | netdev->name); | ||
833 | } | ||
834 | |||
835 | spin_unlock_irqrestore(&c2_port->tx_lock, flags); | ||
836 | |||
837 | netdev->trans_start = jiffies; | ||
838 | |||
839 | return NETDEV_TX_OK; | ||
840 | } | ||
841 | |||
842 | static struct net_device_stats *c2_get_stats(struct net_device *netdev) | ||
843 | { | ||
844 | struct c2_port *c2_port = netdev_priv(netdev); | ||
845 | |||
846 | return &c2_port->netstats; | ||
847 | } | ||
848 | |||
849 | static void c2_tx_timeout(struct net_device *netdev) | ||
850 | { | ||
851 | struct c2_port *c2_port = netdev_priv(netdev); | ||
852 | |||
853 | if (netif_msg_timer(c2_port)) | ||
854 | pr_debug("%s: tx timeout\n", netdev->name); | ||
855 | |||
856 | c2_tx_clean(c2_port); | ||
857 | } | ||
858 | |||
859 | static int c2_change_mtu(struct net_device *netdev, int new_mtu) | ||
860 | { | ||
861 | int ret = 0; | ||
862 | |||
863 | if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) | ||
864 | return -EINVAL; | ||
865 | |||
866 | netdev->mtu = new_mtu; | ||
867 | |||
868 | if (netif_running(netdev)) { | ||
869 | c2_down(netdev); | ||
870 | |||
871 | c2_up(netdev); | ||
872 | } | ||
873 | |||
874 | return ret; | ||
875 | } | ||
876 | |||
877 | /* Initialize network device */ | ||
878 | static struct net_device *c2_devinit(struct c2_dev *c2dev, | ||
879 | void __iomem * mmio_addr) | ||
880 | { | ||
881 | struct c2_port *c2_port = NULL; | ||
882 | struct net_device *netdev = alloc_etherdev(sizeof(*c2_port)); | ||
883 | |||
884 | if (!netdev) { | ||
885 | pr_debug("c2_port etherdev alloc failed"); | ||
886 | return NULL; | ||
887 | } | ||
888 | |||
889 | SET_MODULE_OWNER(netdev); | ||
890 | SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev); | ||
891 | |||
892 | netdev->open = c2_up; | ||
893 | netdev->stop = c2_down; | ||
894 | netdev->hard_start_xmit = c2_xmit_frame; | ||
895 | netdev->get_stats = c2_get_stats; | ||
896 | netdev->tx_timeout = c2_tx_timeout; | ||
897 | netdev->change_mtu = c2_change_mtu; | ||
898 | netdev->watchdog_timeo = C2_TX_TIMEOUT; | ||
899 | netdev->irq = c2dev->pcidev->irq; | ||
900 | |||
901 | c2_port = netdev_priv(netdev); | ||
902 | c2_port->netdev = netdev; | ||
903 | c2_port->c2dev = c2dev; | ||
904 | c2_port->msg_enable = netif_msg_init(debug, default_msg); | ||
905 | c2_port->tx_ring.count = C2_NUM_TX_DESC; | ||
906 | c2_port->rx_ring.count = C2_NUM_RX_DESC; | ||
907 | |||
908 | spin_lock_init(&c2_port->tx_lock); | ||
909 | |||
910 | /* Copy our 48-bit ethernet hardware address */ | ||
911 | memcpy_fromio(netdev->dev_addr, mmio_addr + C2_REGS_ENADDR, 6); | ||
912 | |||
913 | /* Validate the MAC address */ | ||
914 | if (!is_valid_ether_addr(netdev->dev_addr)) { | ||
915 | pr_debug("Invalid MAC Address\n"); | ||
916 | c2_print_macaddr(netdev); | ||
917 | free_netdev(netdev); | ||
918 | return NULL; | ||
919 | } | ||
920 | |||
921 | c2dev->netdev = netdev; | ||
922 | |||
923 | return netdev; | ||
924 | } | ||
925 | |||
926 | static int __devinit c2_probe(struct pci_dev *pcidev, | ||
927 | const struct pci_device_id *ent) | ||
928 | { | ||
929 | int ret = 0, i; | ||
930 | unsigned long reg0_start, reg0_flags, reg0_len; | ||
931 | unsigned long reg2_start, reg2_flags, reg2_len; | ||
932 | unsigned long reg4_start, reg4_flags, reg4_len; | ||
933 | unsigned kva_map_size; | ||
934 | struct net_device *netdev = NULL; | ||
935 | struct c2_dev *c2dev = NULL; | ||
936 | void __iomem *mmio_regs = NULL; | ||
937 | |||
938 | printk(KERN_INFO PFX "AMSO1100 Gigabit Ethernet driver v%s loaded\n", | ||
939 | DRV_VERSION); | ||
940 | |||
941 | /* Enable PCI device */ | ||
942 | ret = pci_enable_device(pcidev); | ||
943 | if (ret) { | ||
944 | printk(KERN_ERR PFX "%s: Unable to enable PCI device\n", | ||
945 | pci_name(pcidev)); | ||
946 | goto bail0; | ||
947 | } | ||
948 | |||
949 | reg0_start = pci_resource_start(pcidev, BAR_0); | ||
950 | reg0_len = pci_resource_len(pcidev, BAR_0); | ||
951 | reg0_flags = pci_resource_flags(pcidev, BAR_0); | ||
952 | |||
953 | reg2_start = pci_resource_start(pcidev, BAR_2); | ||
954 | reg2_len = pci_resource_len(pcidev, BAR_2); | ||
955 | reg2_flags = pci_resource_flags(pcidev, BAR_2); | ||
956 | |||
957 | reg4_start = pci_resource_start(pcidev, BAR_4); | ||
958 | reg4_len = pci_resource_len(pcidev, BAR_4); | ||
959 | reg4_flags = pci_resource_flags(pcidev, BAR_4); | ||
960 | |||
961 | pr_debug("BAR0 size = 0x%lX bytes\n", reg0_len); | ||
962 | pr_debug("BAR2 size = 0x%lX bytes\n", reg2_len); | ||
963 | pr_debug("BAR4 size = 0x%lX bytes\n", reg4_len); | ||
964 | |||
965 | /* Make sure PCI base addr are MMIO */ | ||
966 | if (!(reg0_flags & IORESOURCE_MEM) || | ||
967 | !(reg2_flags & IORESOURCE_MEM) || !(reg4_flags & IORESOURCE_MEM)) { | ||
968 | printk(KERN_ERR PFX "PCI regions not an MMIO resource\n"); | ||
969 | ret = -ENODEV; | ||
970 | goto bail1; | ||
971 | } | ||
972 | |||
973 | /* Check for weird/broken PCI region reporting */ | ||
974 | if ((reg0_len < C2_REG0_SIZE) || | ||
975 | (reg2_len < C2_REG2_SIZE) || (reg4_len < C2_REG4_SIZE)) { | ||
976 | printk(KERN_ERR PFX "Invalid PCI region sizes\n"); | ||
977 | ret = -ENODEV; | ||
978 | goto bail1; | ||
979 | } | ||
980 | |||
981 | /* Reserve PCI I/O and memory resources */ | ||
982 | ret = pci_request_regions(pcidev, DRV_NAME); | ||
983 | if (ret) { | ||
984 | printk(KERN_ERR PFX "%s: Unable to request regions\n", | ||
985 | pci_name(pcidev)); | ||
986 | goto bail1; | ||
987 | } | ||
988 | |||
989 | if ((sizeof(dma_addr_t) > 4)) { | ||
990 | ret = pci_set_dma_mask(pcidev, DMA_64BIT_MASK); | ||
991 | if (ret < 0) { | ||
992 | printk(KERN_ERR PFX "64b DMA configuration failed\n"); | ||
993 | goto bail2; | ||
994 | } | ||
995 | } else { | ||
996 | ret = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); | ||
997 | if (ret < 0) { | ||
998 | printk(KERN_ERR PFX "32b DMA configuration failed\n"); | ||
999 | goto bail2; | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | /* Enables bus-mastering on the device */ | ||
1004 | pci_set_master(pcidev); | ||
1005 | |||
1006 | /* Remap the adapter PCI registers in BAR4 */ | ||
1007 | mmio_regs = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET, | ||
1008 | sizeof(struct c2_adapter_pci_regs)); | ||
1009 | if (mmio_regs == 0UL) { | ||
1010 | printk(KERN_ERR PFX | ||
1011 | "Unable to remap adapter PCI registers in BAR4\n"); | ||
1012 | ret = -EIO; | ||
1013 | goto bail2; | ||
1014 | } | ||
1015 | |||
1016 | /* Validate PCI regs magic */ | ||
1017 | for (i = 0; i < sizeof(c2_magic); i++) { | ||
1018 | if (c2_magic[i] != readb(mmio_regs + C2_REGS_MAGIC + i)) { | ||
1019 | printk(KERN_ERR PFX "Downlevel Firmware boot loader " | ||
1020 | "[%d/%Zd: got 0x%x, exp 0x%x]. Use the cc_flash " | ||
1021 | "utility to update your boot loader\n", | ||
1022 | i + 1, sizeof(c2_magic), | ||
1023 | readb(mmio_regs + C2_REGS_MAGIC + i), | ||
1024 | c2_magic[i]); | ||
1025 | printk(KERN_ERR PFX "Adapter not claimed\n"); | ||
1026 | iounmap(mmio_regs); | ||
1027 | ret = -EIO; | ||
1028 | goto bail2; | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | /* Validate the adapter version */ | ||
1033 | if (be32_to_cpu(readl(mmio_regs + C2_REGS_VERS)) != C2_VERSION) { | ||
1034 | printk(KERN_ERR PFX "Version mismatch " | ||
1035 | "[fw=%u, c2=%u], Adapter not claimed\n", | ||
1036 | be32_to_cpu(readl(mmio_regs + C2_REGS_VERS)), | ||
1037 | C2_VERSION); | ||
1038 | ret = -EINVAL; | ||
1039 | iounmap(mmio_regs); | ||
1040 | goto bail2; | ||
1041 | } | ||
1042 | |||
1043 | /* Validate the adapter IVN */ | ||
1044 | if (be32_to_cpu(readl(mmio_regs + C2_REGS_IVN)) != C2_IVN) { | ||
1045 | printk(KERN_ERR PFX "Downlevel FIrmware level. You should be using " | ||
1046 | "the OpenIB device support kit. " | ||
1047 | "[fw=0x%x, c2=0x%x], Adapter not claimed\n", | ||
1048 | be32_to_cpu(readl(mmio_regs + C2_REGS_IVN)), | ||
1049 | C2_IVN); | ||
1050 | ret = -EINVAL; | ||
1051 | iounmap(mmio_regs); | ||
1052 | goto bail2; | ||
1053 | } | ||
1054 | |||
1055 | /* Allocate hardware structure */ | ||
1056 | c2dev = (struct c2_dev *) ib_alloc_device(sizeof(*c2dev)); | ||
1057 | if (!c2dev) { | ||
1058 | printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n", | ||
1059 | pci_name(pcidev)); | ||
1060 | ret = -ENOMEM; | ||
1061 | iounmap(mmio_regs); | ||
1062 | goto bail2; | ||
1063 | } | ||
1064 | |||
1065 | memset(c2dev, 0, sizeof(*c2dev)); | ||
1066 | spin_lock_init(&c2dev->lock); | ||
1067 | c2dev->pcidev = pcidev; | ||
1068 | c2dev->cur_tx = 0; | ||
1069 | |||
1070 | /* Get the last RX index */ | ||
1071 | c2dev->cur_rx = | ||
1072 | (be32_to_cpu(readl(mmio_regs + C2_REGS_HRX_CUR)) - | ||
1073 | 0xffffc000) / sizeof(struct c2_rxp_desc); | ||
1074 | |||
1075 | /* Request an interrupt line for the driver */ | ||
1076 | ret = request_irq(pcidev->irq, c2_interrupt, SA_SHIRQ, DRV_NAME, c2dev); | ||
1077 | if (ret) { | ||
1078 | printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n", | ||
1079 | pci_name(pcidev), pcidev->irq); | ||
1080 | iounmap(mmio_regs); | ||
1081 | goto bail3; | ||
1082 | } | ||
1083 | |||
1084 | /* Set driver specific data */ | ||
1085 | pci_set_drvdata(pcidev, c2dev); | ||
1086 | |||
1087 | /* Initialize network device */ | ||
1088 | if ((netdev = c2_devinit(c2dev, mmio_regs)) == NULL) { | ||
1089 | iounmap(mmio_regs); | ||
1090 | goto bail4; | ||
1091 | } | ||
1092 | |||
1093 | /* Save off the actual size prior to unmapping mmio_regs */ | ||
1094 | kva_map_size = be32_to_cpu(readl(mmio_regs + C2_REGS_PCI_WINSIZE)); | ||
1095 | |||
1096 | /* Unmap the adapter PCI registers in BAR4 */ | ||
1097 | iounmap(mmio_regs); | ||
1098 | |||
1099 | /* Register network device */ | ||
1100 | ret = register_netdev(netdev); | ||
1101 | if (ret) { | ||
1102 | printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", | ||
1103 | ret); | ||
1104 | goto bail5; | ||
1105 | } | ||
1106 | |||
1107 | /* Disable network packets */ | ||
1108 | netif_stop_queue(netdev); | ||
1109 | |||
1110 | /* Remap the adapter HRXDQ PA space to kernel VA space */ | ||
1111 | c2dev->mmio_rxp_ring = ioremap_nocache(reg4_start + C2_RXP_HRXDQ_OFFSET, | ||
1112 | C2_RXP_HRXDQ_SIZE); | ||
1113 | if (c2dev->mmio_rxp_ring == 0UL) { | ||
1114 | printk(KERN_ERR PFX "Unable to remap MMIO HRXDQ region\n"); | ||
1115 | ret = -EIO; | ||
1116 | goto bail6; | ||
1117 | } | ||
1118 | |||
1119 | /* Remap the adapter HTXDQ PA space to kernel VA space */ | ||
1120 | c2dev->mmio_txp_ring = ioremap_nocache(reg4_start + C2_TXP_HTXDQ_OFFSET, | ||
1121 | C2_TXP_HTXDQ_SIZE); | ||
1122 | if (c2dev->mmio_txp_ring == 0UL) { | ||
1123 | printk(KERN_ERR PFX "Unable to remap MMIO HTXDQ region\n"); | ||
1124 | ret = -EIO; | ||
1125 | goto bail7; | ||
1126 | } | ||
1127 | |||
1128 | /* Save off the current RX index in the last 4 bytes of the TXP Ring */ | ||
1129 | C2_SET_CUR_RX(c2dev, c2dev->cur_rx); | ||
1130 | |||
1131 | /* Remap the PCI registers in adapter BAR0 to kernel VA space */ | ||
1132 | c2dev->regs = ioremap_nocache(reg0_start, reg0_len); | ||
1133 | if (c2dev->regs == 0UL) { | ||
1134 | printk(KERN_ERR PFX "Unable to remap BAR0\n"); | ||
1135 | ret = -EIO; | ||
1136 | goto bail8; | ||
1137 | } | ||
1138 | |||
1139 | /* Remap the PCI registers in adapter BAR4 to kernel VA space */ | ||
1140 | c2dev->pa = reg4_start + C2_PCI_REGS_OFFSET; | ||
1141 | c2dev->kva = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET, | ||
1142 | kva_map_size); | ||
1143 | if (c2dev->kva == 0UL) { | ||
1144 | printk(KERN_ERR PFX "Unable to remap BAR4\n"); | ||
1145 | ret = -EIO; | ||
1146 | goto bail9; | ||
1147 | } | ||
1148 | |||
1149 | /* Print out the MAC address */ | ||
1150 | c2_print_macaddr(netdev); | ||
1151 | |||
1152 | ret = c2_rnic_init(c2dev); | ||
1153 | if (ret) { | ||
1154 | printk(KERN_ERR PFX "c2_rnic_init failed: %d\n", ret); | ||
1155 | goto bail10; | ||
1156 | } | ||
1157 | |||
1158 | c2_register_device(c2dev); | ||
1159 | |||
1160 | return 0; | ||
1161 | |||
1162 | bail10: | ||
1163 | iounmap(c2dev->kva); | ||
1164 | |||
1165 | bail9: | ||
1166 | iounmap(c2dev->regs); | ||
1167 | |||
1168 | bail8: | ||
1169 | iounmap(c2dev->mmio_txp_ring); | ||
1170 | |||
1171 | bail7: | ||
1172 | iounmap(c2dev->mmio_rxp_ring); | ||
1173 | |||
1174 | bail6: | ||
1175 | unregister_netdev(netdev); | ||
1176 | |||
1177 | bail5: | ||
1178 | free_netdev(netdev); | ||
1179 | |||
1180 | bail4: | ||
1181 | free_irq(pcidev->irq, c2dev); | ||
1182 | |||
1183 | bail3: | ||
1184 | ib_dealloc_device(&c2dev->ibdev); | ||
1185 | |||
1186 | bail2: | ||
1187 | pci_release_regions(pcidev); | ||
1188 | |||
1189 | bail1: | ||
1190 | pci_disable_device(pcidev); | ||
1191 | |||
1192 | bail0: | ||
1193 | return ret; | ||
1194 | } | ||
1195 | |||
1196 | static void __devexit c2_remove(struct pci_dev *pcidev) | ||
1197 | { | ||
1198 | struct c2_dev *c2dev = pci_get_drvdata(pcidev); | ||
1199 | struct net_device *netdev = c2dev->netdev; | ||
1200 | |||
1201 | /* Unregister with OpenIB */ | ||
1202 | c2_unregister_device(c2dev); | ||
1203 | |||
1204 | /* Clean up the RNIC resources */ | ||
1205 | c2_rnic_term(c2dev); | ||
1206 | |||
1207 | /* Remove network device from the kernel */ | ||
1208 | unregister_netdev(netdev); | ||
1209 | |||
1210 | /* Free network device */ | ||
1211 | free_netdev(netdev); | ||
1212 | |||
1213 | /* Free the interrupt line */ | ||
1214 | free_irq(pcidev->irq, c2dev); | ||
1215 | |||
1216 | /* missing: Turn LEDs off here */ | ||
1217 | |||
1218 | /* Unmap adapter PA space */ | ||
1219 | iounmap(c2dev->kva); | ||
1220 | iounmap(c2dev->regs); | ||
1221 | iounmap(c2dev->mmio_txp_ring); | ||
1222 | iounmap(c2dev->mmio_rxp_ring); | ||
1223 | |||
1224 | /* Free the hardware structure */ | ||
1225 | ib_dealloc_device(&c2dev->ibdev); | ||
1226 | |||
1227 | /* Release reserved PCI I/O and memory resources */ | ||
1228 | pci_release_regions(pcidev); | ||
1229 | |||
1230 | /* Disable PCI device */ | ||
1231 | pci_disable_device(pcidev); | ||
1232 | |||
1233 | /* Clear driver specific data */ | ||
1234 | pci_set_drvdata(pcidev, NULL); | ||
1235 | } | ||
1236 | |||
1237 | static struct pci_driver c2_pci_driver = { | ||
1238 | .name = DRV_NAME, | ||
1239 | .id_table = c2_pci_table, | ||
1240 | .probe = c2_probe, | ||
1241 | .remove = __devexit_p(c2_remove), | ||
1242 | }; | ||
1243 | |||
1244 | static int __init c2_init_module(void) | ||
1245 | { | ||
1246 | return pci_module_init(&c2_pci_driver); | ||
1247 | } | ||
1248 | |||
1249 | static void __exit c2_exit_module(void) | ||
1250 | { | ||
1251 | pci_unregister_driver(&c2_pci_driver); | ||
1252 | } | ||
1253 | |||
1254 | module_init(c2_init_module); | ||
1255 | module_exit(c2_exit_module); | ||
diff --git a/drivers/infiniband/hw/amso1100/c2.h b/drivers/infiniband/hw/amso1100/c2.h new file mode 100644 index 000000000000..1b17dcdd0505 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2.h | |||
@@ -0,0 +1,551 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #ifndef __C2_H | ||
35 | #define __C2_H | ||
36 | |||
37 | #include <linux/netdevice.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/pci.h> | ||
41 | #include <linux/dma-mapping.h> | ||
42 | #include <linux/idr.h> | ||
43 | #include <asm/semaphore.h> | ||
44 | |||
45 | #include "c2_provider.h" | ||
46 | #include "c2_mq.h" | ||
47 | #include "c2_status.h" | ||
48 | |||
49 | #define DRV_NAME "c2" | ||
50 | #define DRV_VERSION "1.1" | ||
51 | #define PFX DRV_NAME ": " | ||
52 | |||
53 | #define BAR_0 0 | ||
54 | #define BAR_2 2 | ||
55 | #define BAR_4 4 | ||
56 | |||
57 | #define RX_BUF_SIZE (1536 + 8) | ||
58 | #define ETH_JUMBO_MTU 9000 | ||
59 | #define C2_MAGIC "CEPHEUS" | ||
60 | #define C2_VERSION 4 | ||
61 | #define C2_IVN (18 & 0x7fffffff) | ||
62 | |||
63 | #define C2_REG0_SIZE (16 * 1024) | ||
64 | #define C2_REG2_SIZE (2 * 1024 * 1024) | ||
65 | #define C2_REG4_SIZE (256 * 1024 * 1024) | ||
66 | #define C2_NUM_TX_DESC 341 | ||
67 | #define C2_NUM_RX_DESC 256 | ||
68 | #define C2_PCI_REGS_OFFSET (0x10000) | ||
69 | #define C2_RXP_HRXDQ_OFFSET (((C2_REG4_SIZE)/2)) | ||
70 | #define C2_RXP_HRXDQ_SIZE (4096) | ||
71 | #define C2_TXP_HTXDQ_OFFSET (((C2_REG4_SIZE)/2) + C2_RXP_HRXDQ_SIZE) | ||
72 | #define C2_TXP_HTXDQ_SIZE (4096) | ||
73 | #define C2_TX_TIMEOUT (6*HZ) | ||
74 | |||
75 | /* CEPHEUS */ | ||
76 | static const u8 c2_magic[] = { | ||
77 | 0x43, 0x45, 0x50, 0x48, 0x45, 0x55, 0x53 | ||
78 | }; | ||
79 | |||
80 | enum adapter_pci_regs { | ||
81 | C2_REGS_MAGIC = 0x0000, | ||
82 | C2_REGS_VERS = 0x0008, | ||
83 | C2_REGS_IVN = 0x000C, | ||
84 | C2_REGS_PCI_WINSIZE = 0x0010, | ||
85 | C2_REGS_Q0_QSIZE = 0x0014, | ||
86 | C2_REGS_Q0_MSGSIZE = 0x0018, | ||
87 | C2_REGS_Q0_POOLSTART = 0x001C, | ||
88 | C2_REGS_Q0_SHARED = 0x0020, | ||
89 | C2_REGS_Q1_QSIZE = 0x0024, | ||
90 | C2_REGS_Q1_MSGSIZE = 0x0028, | ||
91 | C2_REGS_Q1_SHARED = 0x0030, | ||
92 | C2_REGS_Q2_QSIZE = 0x0034, | ||
93 | C2_REGS_Q2_MSGSIZE = 0x0038, | ||
94 | C2_REGS_Q2_SHARED = 0x0040, | ||
95 | C2_REGS_ENADDR = 0x004C, | ||
96 | C2_REGS_RDMA_ENADDR = 0x0054, | ||
97 | C2_REGS_HRX_CUR = 0x006C, | ||
98 | }; | ||
99 | |||
100 | struct c2_adapter_pci_regs { | ||
101 | char reg_magic[8]; | ||
102 | u32 version; | ||
103 | u32 ivn; | ||
104 | u32 pci_window_size; | ||
105 | u32 q0_q_size; | ||
106 | u32 q0_msg_size; | ||
107 | u32 q0_pool_start; | ||
108 | u32 q0_shared; | ||
109 | u32 q1_q_size; | ||
110 | u32 q1_msg_size; | ||
111 | u32 q1_pool_start; | ||
112 | u32 q1_shared; | ||
113 | u32 q2_q_size; | ||
114 | u32 q2_msg_size; | ||
115 | u32 q2_pool_start; | ||
116 | u32 q2_shared; | ||
117 | u32 log_start; | ||
118 | u32 log_size; | ||
119 | u8 host_enaddr[8]; | ||
120 | u8 rdma_enaddr[8]; | ||
121 | u32 crash_entry; | ||
122 | u32 crash_ready[2]; | ||
123 | u32 fw_txd_cur; | ||
124 | u32 fw_hrxd_cur; | ||
125 | u32 fw_rxd_cur; | ||
126 | }; | ||
127 | |||
128 | enum pci_regs { | ||
129 | C2_HISR = 0x0000, | ||
130 | C2_DISR = 0x0004, | ||
131 | C2_HIMR = 0x0008, | ||
132 | C2_DIMR = 0x000C, | ||
133 | C2_NISR0 = 0x0010, | ||
134 | C2_NISR1 = 0x0014, | ||
135 | C2_NIMR0 = 0x0018, | ||
136 | C2_NIMR1 = 0x001C, | ||
137 | C2_IDIS = 0x0020, | ||
138 | }; | ||
139 | |||
140 | enum { | ||
141 | C2_PCI_HRX_INT = 1 << 8, | ||
142 | C2_PCI_HTX_INT = 1 << 17, | ||
143 | C2_PCI_HRX_QUI = 1 << 31, | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * Cepheus registers in BAR0. | ||
148 | */ | ||
149 | struct c2_pci_regs { | ||
150 | u32 hostisr; | ||
151 | u32 dmaisr; | ||
152 | u32 hostimr; | ||
153 | u32 dmaimr; | ||
154 | u32 netisr0; | ||
155 | u32 netisr1; | ||
156 | u32 netimr0; | ||
157 | u32 netimr1; | ||
158 | u32 int_disable; | ||
159 | }; | ||
160 | |||
161 | /* TXP flags */ | ||
162 | enum c2_txp_flags { | ||
163 | TXP_HTXD_DONE = 0, | ||
164 | TXP_HTXD_READY = 1 << 0, | ||
165 | TXP_HTXD_UNINIT = 1 << 1, | ||
166 | }; | ||
167 | |||
168 | /* RXP flags */ | ||
169 | enum c2_rxp_flags { | ||
170 | RXP_HRXD_UNINIT = 0, | ||
171 | RXP_HRXD_READY = 1 << 0, | ||
172 | RXP_HRXD_DONE = 1 << 1, | ||
173 | }; | ||
174 | |||
175 | /* RXP status */ | ||
176 | enum c2_rxp_status { | ||
177 | RXP_HRXD_ZERO = 0, | ||
178 | RXP_HRXD_OK = 1 << 0, | ||
179 | RXP_HRXD_BUF_OV = 1 << 1, | ||
180 | }; | ||
181 | |||
182 | /* TXP descriptor fields */ | ||
183 | enum txp_desc { | ||
184 | C2_TXP_FLAGS = 0x0000, | ||
185 | C2_TXP_LEN = 0x0002, | ||
186 | C2_TXP_ADDR = 0x0004, | ||
187 | }; | ||
188 | |||
189 | /* RXP descriptor fields */ | ||
190 | enum rxp_desc { | ||
191 | C2_RXP_FLAGS = 0x0000, | ||
192 | C2_RXP_STATUS = 0x0002, | ||
193 | C2_RXP_COUNT = 0x0004, | ||
194 | C2_RXP_LEN = 0x0006, | ||
195 | C2_RXP_ADDR = 0x0008, | ||
196 | }; | ||
197 | |||
198 | struct c2_txp_desc { | ||
199 | u16 flags; | ||
200 | u16 len; | ||
201 | u64 addr; | ||
202 | } __attribute__ ((packed)); | ||
203 | |||
204 | struct c2_rxp_desc { | ||
205 | u16 flags; | ||
206 | u16 status; | ||
207 | u16 count; | ||
208 | u16 len; | ||
209 | u64 addr; | ||
210 | } __attribute__ ((packed)); | ||
211 | |||
212 | struct c2_rxp_hdr { | ||
213 | u16 flags; | ||
214 | u16 status; | ||
215 | u16 len; | ||
216 | u16 rsvd; | ||
217 | } __attribute__ ((packed)); | ||
218 | |||
219 | struct c2_tx_desc { | ||
220 | u32 len; | ||
221 | u32 status; | ||
222 | dma_addr_t next_offset; | ||
223 | }; | ||
224 | |||
225 | struct c2_rx_desc { | ||
226 | u32 len; | ||
227 | u32 status; | ||
228 | dma_addr_t next_offset; | ||
229 | }; | ||
230 | |||
231 | struct c2_alloc { | ||
232 | u32 last; | ||
233 | u32 max; | ||
234 | spinlock_t lock; | ||
235 | unsigned long *table; | ||
236 | }; | ||
237 | |||
238 | struct c2_array { | ||
239 | struct { | ||
240 | void **page; | ||
241 | int used; | ||
242 | } *page_list; | ||
243 | }; | ||
244 | |||
245 | /* | ||
246 | * The MQ shared pointer pool is organized as a linked list of | ||
247 | * chunks. Each chunk contains a linked list of free shared pointers | ||
248 | * that can be allocated to a given user mode client. | ||
249 | * | ||
250 | */ | ||
251 | struct sp_chunk { | ||
252 | struct sp_chunk *next; | ||
253 | dma_addr_t dma_addr; | ||
254 | DECLARE_PCI_UNMAP_ADDR(mapping); | ||
255 | u16 head; | ||
256 | u16 shared_ptr[0]; | ||
257 | }; | ||
258 | |||
259 | struct c2_pd_table { | ||
260 | u32 last; | ||
261 | u32 max; | ||
262 | spinlock_t lock; | ||
263 | unsigned long *table; | ||
264 | }; | ||
265 | |||
266 | struct c2_qp_table { | ||
267 | struct idr idr; | ||
268 | spinlock_t lock; | ||
269 | int last; | ||
270 | }; | ||
271 | |||
272 | struct c2_element { | ||
273 | struct c2_element *next; | ||
274 | void *ht_desc; /* host descriptor */ | ||
275 | void __iomem *hw_desc; /* hardware descriptor */ | ||
276 | struct sk_buff *skb; | ||
277 | dma_addr_t mapaddr; | ||
278 | u32 maplen; | ||
279 | }; | ||
280 | |||
281 | struct c2_ring { | ||
282 | struct c2_element *to_clean; | ||
283 | struct c2_element *to_use; | ||
284 | struct c2_element *start; | ||
285 | unsigned long count; | ||
286 | }; | ||
287 | |||
288 | struct c2_dev { | ||
289 | struct ib_device ibdev; | ||
290 | void __iomem *regs; | ||
291 | void __iomem *mmio_txp_ring; /* remapped adapter memory for hw rings */ | ||
292 | void __iomem *mmio_rxp_ring; | ||
293 | spinlock_t lock; | ||
294 | struct pci_dev *pcidev; | ||
295 | struct net_device *netdev; | ||
296 | struct net_device *pseudo_netdev; | ||
297 | unsigned int cur_tx; | ||
298 | unsigned int cur_rx; | ||
299 | u32 adapter_handle; | ||
300 | int device_cap_flags; | ||
301 | void __iomem *kva; /* KVA device memory */ | ||
302 | unsigned long pa; /* PA device memory */ | ||
303 | void **qptr_array; | ||
304 | |||
305 | kmem_cache_t *host_msg_cache; | ||
306 | |||
307 | struct list_head cca_link; /* adapter list */ | ||
308 | struct list_head eh_wakeup_list; /* event wakeup list */ | ||
309 | wait_queue_head_t req_vq_wo; | ||
310 | |||
311 | /* Cached RNIC properties */ | ||
312 | struct ib_device_attr props; | ||
313 | |||
314 | struct c2_pd_table pd_table; | ||
315 | struct c2_qp_table qp_table; | ||
316 | int ports; /* num of GigE ports */ | ||
317 | int devnum; | ||
318 | spinlock_t vqlock; /* sync vbs req MQ */ | ||
319 | |||
320 | /* Verbs Queues */ | ||
321 | struct c2_mq req_vq; /* Verbs Request MQ */ | ||
322 | struct c2_mq rep_vq; /* Verbs Reply MQ */ | ||
323 | struct c2_mq aeq; /* Async Events MQ */ | ||
324 | |||
325 | /* Kernel client MQs */ | ||
326 | struct sp_chunk *kern_mqsp_pool; | ||
327 | |||
328 | /* Device updates these values when posting messages to a host | ||
329 | * target queue */ | ||
330 | u16 req_vq_shared; | ||
331 | u16 rep_vq_shared; | ||
332 | u16 aeq_shared; | ||
333 | u16 irq_claimed; | ||
334 | |||
335 | /* | ||
336 | * Shared host target pages for user-accessible MQs. | ||
337 | */ | ||
338 | int hthead; /* index of first free entry */ | ||
339 | void *htpages; /* kernel vaddr */ | ||
340 | int htlen; /* length of htpages memory */ | ||
341 | void *htuva; /* user mapped vaddr */ | ||
342 | spinlock_t htlock; /* serialize allocation */ | ||
343 | |||
344 | u64 adapter_hint_uva; /* access to the activity FIFO */ | ||
345 | |||
346 | // spinlock_t aeq_lock; | ||
347 | // spinlock_t rnic_lock; | ||
348 | |||
349 | u16 *hint_count; | ||
350 | dma_addr_t hint_count_dma; | ||
351 | u16 hints_read; | ||
352 | |||
353 | int init; /* TRUE if it's ready */ | ||
354 | char ae_cache_name[16]; | ||
355 | char vq_cache_name[16]; | ||
356 | }; | ||
357 | |||
358 | struct c2_port { | ||
359 | u32 msg_enable; | ||
360 | struct c2_dev *c2dev; | ||
361 | struct net_device *netdev; | ||
362 | |||
363 | spinlock_t tx_lock; | ||
364 | u32 tx_avail; | ||
365 | struct c2_ring tx_ring; | ||
366 | struct c2_ring rx_ring; | ||
367 | |||
368 | void *mem; /* PCI memory for host rings */ | ||
369 | dma_addr_t dma; | ||
370 | unsigned long mem_size; | ||
371 | |||
372 | u32 rx_buf_size; | ||
373 | |||
374 | struct net_device_stats netstats; | ||
375 | }; | ||
376 | |||
377 | /* | ||
378 | * Activity FIFO registers in BAR0. | ||
379 | */ | ||
380 | #define PCI_BAR0_HOST_HINT 0x100 | ||
381 | #define PCI_BAR0_ADAPTER_HINT 0x2000 | ||
382 | |||
383 | /* | ||
384 | * Ammasso PCI vendor id and Cepheus PCI device id. | ||
385 | */ | ||
386 | #define CQ_ARMED 0x01 | ||
387 | #define CQ_WAIT_FOR_DMA 0x80 | ||
388 | |||
389 | /* | ||
390 | * The format of a hint is as follows: | ||
391 | * Lower 16 bits are the count of hints for the queue. | ||
392 | * Next 15 bits are the qp_index | ||
393 | * Upper most bit depends on who reads it: | ||
394 | * If read by producer, then it means Full (1) or Not-Full (0) | ||
395 | * If read by consumer, then it means Empty (1) or Not-Empty (0) | ||
396 | */ | ||
397 | #define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count) | ||
398 | #define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16) | ||
399 | #define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF) | ||
400 | |||
401 | |||
402 | /* | ||
403 | * The following defines the offset in SDRAM for the c2_adapter_pci_regs_t | ||
404 | * struct. | ||
405 | */ | ||
406 | #define C2_ADAPTER_PCI_REGS_OFFSET 0x10000 | ||
407 | |||
408 | #ifndef readq | ||
409 | static inline u64 readq(const void __iomem * addr) | ||
410 | { | ||
411 | u64 ret = readl(addr + 4); | ||
412 | ret <<= 32; | ||
413 | ret |= readl(addr); | ||
414 | |||
415 | return ret; | ||
416 | } | ||
417 | #endif | ||
418 | |||
419 | #ifndef writeq | ||
420 | static inline void __raw_writeq(u64 val, void __iomem * addr) | ||
421 | { | ||
422 | __raw_writel((u32) (val), addr); | ||
423 | __raw_writel((u32) (val >> 32), (addr + 4)); | ||
424 | } | ||
425 | #endif | ||
426 | |||
427 | #define C2_SET_CUR_RX(c2dev, cur_rx) \ | ||
428 | __raw_writel(cpu_to_be32(cur_rx), c2dev->mmio_txp_ring + 4092) | ||
429 | |||
430 | #define C2_GET_CUR_RX(c2dev) \ | ||
431 | be32_to_cpu(readl(c2dev->mmio_txp_ring + 4092)) | ||
432 | |||
433 | static inline struct c2_dev *to_c2dev(struct ib_device *ibdev) | ||
434 | { | ||
435 | return container_of(ibdev, struct c2_dev, ibdev); | ||
436 | } | ||
437 | |||
438 | static inline int c2_errno(void *reply) | ||
439 | { | ||
440 | switch (c2_wr_get_result(reply)) { | ||
441 | case C2_OK: | ||
442 | return 0; | ||
443 | case CCERR_NO_BUFS: | ||
444 | case CCERR_INSUFFICIENT_RESOURCES: | ||
445 | case CCERR_ZERO_RDMA_READ_RESOURCES: | ||
446 | return -ENOMEM; | ||
447 | case CCERR_MR_IN_USE: | ||
448 | case CCERR_QP_IN_USE: | ||
449 | return -EBUSY; | ||
450 | case CCERR_ADDR_IN_USE: | ||
451 | return -EADDRINUSE; | ||
452 | case CCERR_ADDR_NOT_AVAIL: | ||
453 | return -EADDRNOTAVAIL; | ||
454 | case CCERR_CONN_RESET: | ||
455 | return -ECONNRESET; | ||
456 | case CCERR_NOT_IMPLEMENTED: | ||
457 | case CCERR_INVALID_WQE: | ||
458 | return -ENOSYS; | ||
459 | case CCERR_QP_NOT_PRIVILEGED: | ||
460 | return -EPERM; | ||
461 | case CCERR_STACK_ERROR: | ||
462 | return -EPROTO; | ||
463 | case CCERR_ACCESS_VIOLATION: | ||
464 | case CCERR_BASE_AND_BOUNDS_VIOLATION: | ||
465 | return -EFAULT; | ||
466 | case CCERR_STAG_STATE_NOT_INVALID: | ||
467 | case CCERR_INVALID_ADDRESS: | ||
468 | case CCERR_INVALID_CQ: | ||
469 | case CCERR_INVALID_EP: | ||
470 | case CCERR_INVALID_MODIFIER: | ||
471 | case CCERR_INVALID_MTU: | ||
472 | case CCERR_INVALID_PD_ID: | ||
473 | case CCERR_INVALID_QP: | ||
474 | case CCERR_INVALID_RNIC: | ||
475 | case CCERR_INVALID_STAG: | ||
476 | return -EINVAL; | ||
477 | default: | ||
478 | return -EAGAIN; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | /* Device */ | ||
483 | extern int c2_register_device(struct c2_dev *c2dev); | ||
484 | extern void c2_unregister_device(struct c2_dev *c2dev); | ||
485 | extern int c2_rnic_init(struct c2_dev *c2dev); | ||
486 | extern void c2_rnic_term(struct c2_dev *c2dev); | ||
487 | extern void c2_rnic_interrupt(struct c2_dev *c2dev); | ||
488 | extern int c2_del_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask); | ||
489 | extern int c2_add_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask); | ||
490 | |||
491 | /* QPs */ | ||
492 | extern int c2_alloc_qp(struct c2_dev *c2dev, struct c2_pd *pd, | ||
493 | struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp); | ||
494 | extern void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp); | ||
495 | extern struct ib_qp *c2_get_qp(struct ib_device *device, int qpn); | ||
496 | extern int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp, | ||
497 | struct ib_qp_attr *attr, int attr_mask); | ||
498 | extern int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp, | ||
499 | int ord, int ird); | ||
500 | extern int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, | ||
501 | struct ib_send_wr **bad_wr); | ||
502 | extern int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, | ||
503 | struct ib_recv_wr **bad_wr); | ||
504 | extern void __devinit c2_init_qp_table(struct c2_dev *c2dev); | ||
505 | extern void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev); | ||
506 | extern void c2_set_qp_state(struct c2_qp *, int); | ||
507 | extern struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn); | ||
508 | |||
509 | /* PDs */ | ||
510 | extern int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd); | ||
511 | extern void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd); | ||
512 | extern int __devinit c2_init_pd_table(struct c2_dev *c2dev); | ||
513 | extern void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev); | ||
514 | |||
515 | /* CQs */ | ||
516 | extern int c2_init_cq(struct c2_dev *c2dev, int entries, | ||
517 | struct c2_ucontext *ctx, struct c2_cq *cq); | ||
518 | extern void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq); | ||
519 | extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index); | ||
520 | extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index); | ||
521 | extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); | ||
522 | extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify); | ||
523 | |||
524 | /* CM */ | ||
525 | extern int c2_llp_connect(struct iw_cm_id *cm_id, | ||
526 | struct iw_cm_conn_param *iw_param); | ||
527 | extern int c2_llp_accept(struct iw_cm_id *cm_id, | ||
528 | struct iw_cm_conn_param *iw_param); | ||
529 | extern int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, | ||
530 | u8 pdata_len); | ||
531 | extern int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog); | ||
532 | extern int c2_llp_service_destroy(struct iw_cm_id *cm_id); | ||
533 | |||
534 | /* MM */ | ||
535 | extern int c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list, | ||
536 | int page_size, int pbl_depth, u32 length, | ||
537 | u32 off, u64 *va, enum c2_acf acf, | ||
538 | struct c2_mr *mr); | ||
539 | extern int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index); | ||
540 | |||
541 | /* AE */ | ||
542 | extern void c2_ae_event(struct c2_dev *c2dev, u32 mq_index); | ||
543 | |||
544 | /* MQSP Allocator */ | ||
545 | extern int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask, | ||
546 | struct sp_chunk **root); | ||
547 | extern void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root); | ||
548 | extern u16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head, | ||
549 | dma_addr_t *dma_addr, gfp_t gfp_mask); | ||
550 | extern void c2_free_mqsp(u16 * mqsp); | ||
551 | #endif | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c new file mode 100644 index 000000000000..08f46c83a3a4 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_ae.c | |||
@@ -0,0 +1,321 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #include "c2.h" | ||
34 | #include <rdma/iw_cm.h> | ||
35 | #include "c2_status.h" | ||
36 | #include "c2_ae.h" | ||
37 | |||
38 | static int c2_convert_cm_status(u32 c2_status) | ||
39 | { | ||
40 | switch (c2_status) { | ||
41 | case C2_CONN_STATUS_SUCCESS: | ||
42 | return 0; | ||
43 | case C2_CONN_STATUS_REJECTED: | ||
44 | return -ENETRESET; | ||
45 | case C2_CONN_STATUS_REFUSED: | ||
46 | return -ECONNREFUSED; | ||
47 | case C2_CONN_STATUS_TIMEDOUT: | ||
48 | return -ETIMEDOUT; | ||
49 | case C2_CONN_STATUS_NETUNREACH: | ||
50 | return -ENETUNREACH; | ||
51 | case C2_CONN_STATUS_HOSTUNREACH: | ||
52 | return -EHOSTUNREACH; | ||
53 | case C2_CONN_STATUS_INVALID_RNIC: | ||
54 | return -EINVAL; | ||
55 | case C2_CONN_STATUS_INVALID_QP: | ||
56 | return -EINVAL; | ||
57 | case C2_CONN_STATUS_INVALID_QP_STATE: | ||
58 | return -EINVAL; | ||
59 | case C2_CONN_STATUS_ADDR_NOT_AVAIL: | ||
60 | return -EADDRNOTAVAIL; | ||
61 | default: | ||
62 | printk(KERN_ERR PFX | ||
63 | "%s - Unable to convert CM status: %d\n", | ||
64 | __FUNCTION__, c2_status); | ||
65 | return -EIO; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | #ifdef DEBUG | ||
70 | static const char* to_event_str(int event) | ||
71 | { | ||
72 | static const char* event_str[] = { | ||
73 | "CCAE_REMOTE_SHUTDOWN", | ||
74 | "CCAE_ACTIVE_CONNECT_RESULTS", | ||
75 | "CCAE_CONNECTION_REQUEST", | ||
76 | "CCAE_LLP_CLOSE_COMPLETE", | ||
77 | "CCAE_TERMINATE_MESSAGE_RECEIVED", | ||
78 | "CCAE_LLP_CONNECTION_RESET", | ||
79 | "CCAE_LLP_CONNECTION_LOST", | ||
80 | "CCAE_LLP_SEGMENT_SIZE_INVALID", | ||
81 | "CCAE_LLP_INVALID_CRC", | ||
82 | "CCAE_LLP_BAD_FPDU", | ||
83 | "CCAE_INVALID_DDP_VERSION", | ||
84 | "CCAE_INVALID_RDMA_VERSION", | ||
85 | "CCAE_UNEXPECTED_OPCODE", | ||
86 | "CCAE_INVALID_DDP_QUEUE_NUMBER", | ||
87 | "CCAE_RDMA_READ_NOT_ENABLED", | ||
88 | "CCAE_RDMA_WRITE_NOT_ENABLED", | ||
89 | "CCAE_RDMA_READ_TOO_SMALL", | ||
90 | "CCAE_NO_L_BIT", | ||
91 | "CCAE_TAGGED_INVALID_STAG", | ||
92 | "CCAE_TAGGED_BASE_BOUNDS_VIOLATION", | ||
93 | "CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION", | ||
94 | "CCAE_TAGGED_INVALID_PD", | ||
95 | "CCAE_WRAP_ERROR", | ||
96 | "CCAE_BAD_CLOSE", | ||
97 | "CCAE_BAD_LLP_CLOSE", | ||
98 | "CCAE_INVALID_MSN_RANGE", | ||
99 | "CCAE_INVALID_MSN_GAP", | ||
100 | "CCAE_IRRQ_OVERFLOW", | ||
101 | "CCAE_IRRQ_MSN_GAP", | ||
102 | "CCAE_IRRQ_MSN_RANGE", | ||
103 | "CCAE_IRRQ_INVALID_STAG", | ||
104 | "CCAE_IRRQ_BASE_BOUNDS_VIOLATION", | ||
105 | "CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION", | ||
106 | "CCAE_IRRQ_INVALID_PD", | ||
107 | "CCAE_IRRQ_WRAP_ERROR", | ||
108 | "CCAE_CQ_SQ_COMPLETION_OVERFLOW", | ||
109 | "CCAE_CQ_RQ_COMPLETION_ERROR", | ||
110 | "CCAE_QP_SRQ_WQE_ERROR", | ||
111 | "CCAE_QP_LOCAL_CATASTROPHIC_ERROR", | ||
112 | "CCAE_CQ_OVERFLOW", | ||
113 | "CCAE_CQ_OPERATION_ERROR", | ||
114 | "CCAE_SRQ_LIMIT_REACHED", | ||
115 | "CCAE_QP_RQ_LIMIT_REACHED", | ||
116 | "CCAE_SRQ_CATASTROPHIC_ERROR", | ||
117 | "CCAE_RNIC_CATASTROPHIC_ERROR" | ||
118 | }; | ||
119 | |||
120 | if (event < CCAE_REMOTE_SHUTDOWN || | ||
121 | event > CCAE_RNIC_CATASTROPHIC_ERROR) | ||
122 | return "<invalid event>"; | ||
123 | |||
124 | event -= CCAE_REMOTE_SHUTDOWN; | ||
125 | return event_str[event]; | ||
126 | } | ||
127 | |||
128 | static const char *to_qp_state_str(int state) | ||
129 | { | ||
130 | switch (state) { | ||
131 | case C2_QP_STATE_IDLE: | ||
132 | return "C2_QP_STATE_IDLE"; | ||
133 | case C2_QP_STATE_CONNECTING: | ||
134 | return "C2_QP_STATE_CONNECTING"; | ||
135 | case C2_QP_STATE_RTS: | ||
136 | return "C2_QP_STATE_RTS"; | ||
137 | case C2_QP_STATE_CLOSING: | ||
138 | return "C2_QP_STATE_CLOSING"; | ||
139 | case C2_QP_STATE_TERMINATE: | ||
140 | return "C2_QP_STATE_TERMINATE"; | ||
141 | case C2_QP_STATE_ERROR: | ||
142 | return "C2_QP_STATE_ERROR"; | ||
143 | default: | ||
144 | return "<invalid QP state>"; | ||
145 | }; | ||
146 | } | ||
147 | #endif | ||
148 | |||
149 | void c2_ae_event(struct c2_dev *c2dev, u32 mq_index) | ||
150 | { | ||
151 | struct c2_mq *mq = c2dev->qptr_array[mq_index]; | ||
152 | union c2wr *wr; | ||
153 | void *resource_user_context; | ||
154 | struct iw_cm_event cm_event; | ||
155 | struct ib_event ib_event; | ||
156 | enum c2_resource_indicator resource_indicator; | ||
157 | enum c2_event_id event_id; | ||
158 | unsigned long flags; | ||
159 | int status; | ||
160 | |||
161 | /* | ||
162 | * retreive the message | ||
163 | */ | ||
164 | wr = c2_mq_consume(mq); | ||
165 | if (!wr) | ||
166 | return; | ||
167 | |||
168 | memset(&ib_event, 0, sizeof(ib_event)); | ||
169 | memset(&cm_event, 0, sizeof(cm_event)); | ||
170 | |||
171 | event_id = c2_wr_get_id(wr); | ||
172 | resource_indicator = be32_to_cpu(wr->ae.ae_generic.resource_type); | ||
173 | resource_user_context = | ||
174 | (void *) (unsigned long) wr->ae.ae_generic.user_context; | ||
175 | |||
176 | status = cm_event.status = c2_convert_cm_status(c2_wr_get_result(wr)); | ||
177 | |||
178 | pr_debug("event received c2_dev=%p, event_id=%d, " | ||
179 | "resource_indicator=%d, user_context=%p, status = %d\n", | ||
180 | c2dev, event_id, resource_indicator, resource_user_context, | ||
181 | status); | ||
182 | |||
183 | switch (resource_indicator) { | ||
184 | case C2_RES_IND_QP:{ | ||
185 | |||
186 | struct c2_qp *qp = (struct c2_qp *)resource_user_context; | ||
187 | struct iw_cm_id *cm_id = qp->cm_id; | ||
188 | struct c2wr_ae_active_connect_results *res; | ||
189 | |||
190 | if (!cm_id) { | ||
191 | pr_debug("event received, but cm_id is <nul>, qp=%p!\n", | ||
192 | qp); | ||
193 | goto ignore_it; | ||
194 | } | ||
195 | pr_debug("%s: event = %s, user_context=%llx, " | ||
196 | "resource_type=%x, " | ||
197 | "resource=%x, qp_state=%s\n", | ||
198 | __FUNCTION__, | ||
199 | to_event_str(event_id), | ||
200 | be64_to_cpu(wr->ae.ae_generic.user_context), | ||
201 | be32_to_cpu(wr->ae.ae_generic.resource_type), | ||
202 | be32_to_cpu(wr->ae.ae_generic.resource), | ||
203 | to_qp_state_str(be32_to_cpu(wr->ae.ae_generic.qp_state))); | ||
204 | |||
205 | c2_set_qp_state(qp, be32_to_cpu(wr->ae.ae_generic.qp_state)); | ||
206 | |||
207 | switch (event_id) { | ||
208 | case CCAE_ACTIVE_CONNECT_RESULTS: | ||
209 | res = &wr->ae.ae_active_connect_results; | ||
210 | cm_event.event = IW_CM_EVENT_CONNECT_REPLY; | ||
211 | cm_event.local_addr.sin_addr.s_addr = res->laddr; | ||
212 | cm_event.remote_addr.sin_addr.s_addr = res->raddr; | ||
213 | cm_event.local_addr.sin_port = res->lport; | ||
214 | cm_event.remote_addr.sin_port = res->rport; | ||
215 | if (status == 0) { | ||
216 | cm_event.private_data_len = | ||
217 | be32_to_cpu(res->private_data_length); | ||
218 | cm_event.private_data = res->private_data; | ||
219 | } else { | ||
220 | spin_lock_irqsave(&qp->lock, flags); | ||
221 | if (qp->cm_id) { | ||
222 | qp->cm_id->rem_ref(qp->cm_id); | ||
223 | qp->cm_id = NULL; | ||
224 | } | ||
225 | spin_unlock_irqrestore(&qp->lock, flags); | ||
226 | cm_event.private_data_len = 0; | ||
227 | cm_event.private_data = NULL; | ||
228 | } | ||
229 | if (cm_id->event_handler) | ||
230 | cm_id->event_handler(cm_id, &cm_event); | ||
231 | break; | ||
232 | case CCAE_TERMINATE_MESSAGE_RECEIVED: | ||
233 | case CCAE_CQ_SQ_COMPLETION_OVERFLOW: | ||
234 | ib_event.device = &c2dev->ibdev; | ||
235 | ib_event.element.qp = &qp->ibqp; | ||
236 | ib_event.event = IB_EVENT_QP_REQ_ERR; | ||
237 | |||
238 | if (qp->ibqp.event_handler) | ||
239 | qp->ibqp.event_handler(&ib_event, | ||
240 | qp->ibqp. | ||
241 | qp_context); | ||
242 | break; | ||
243 | case CCAE_BAD_CLOSE: | ||
244 | case CCAE_LLP_CLOSE_COMPLETE: | ||
245 | case CCAE_LLP_CONNECTION_RESET: | ||
246 | case CCAE_LLP_CONNECTION_LOST: | ||
247 | BUG_ON(cm_id->event_handler==(void*)0x6b6b6b6b); | ||
248 | |||
249 | spin_lock_irqsave(&qp->lock, flags); | ||
250 | if (qp->cm_id) { | ||
251 | qp->cm_id->rem_ref(qp->cm_id); | ||
252 | qp->cm_id = NULL; | ||
253 | } | ||
254 | spin_unlock_irqrestore(&qp->lock, flags); | ||
255 | cm_event.event = IW_CM_EVENT_CLOSE; | ||
256 | cm_event.status = 0; | ||
257 | if (cm_id->event_handler) | ||
258 | cm_id->event_handler(cm_id, &cm_event); | ||
259 | break; | ||
260 | default: | ||
261 | BUG_ON(1); | ||
262 | pr_debug("%s:%d Unexpected event_id=%d on QP=%p, " | ||
263 | "CM_ID=%p\n", | ||
264 | __FUNCTION__, __LINE__, | ||
265 | event_id, qp, cm_id); | ||
266 | break; | ||
267 | } | ||
268 | break; | ||
269 | } | ||
270 | |||
271 | case C2_RES_IND_EP:{ | ||
272 | |||
273 | struct c2wr_ae_connection_request *req = | ||
274 | &wr->ae.ae_connection_request; | ||
275 | struct iw_cm_id *cm_id = | ||
276 | (struct iw_cm_id *)resource_user_context; | ||
277 | |||
278 | pr_debug("C2_RES_IND_EP event_id=%d\n", event_id); | ||
279 | if (event_id != CCAE_CONNECTION_REQUEST) { | ||
280 | pr_debug("%s: Invalid event_id: %d\n", | ||
281 | __FUNCTION__, event_id); | ||
282 | break; | ||
283 | } | ||
284 | cm_event.event = IW_CM_EVENT_CONNECT_REQUEST; | ||
285 | cm_event.provider_data = (void*)(unsigned long)req->cr_handle; | ||
286 | cm_event.local_addr.sin_addr.s_addr = req->laddr; | ||
287 | cm_event.remote_addr.sin_addr.s_addr = req->raddr; | ||
288 | cm_event.local_addr.sin_port = req->lport; | ||
289 | cm_event.remote_addr.sin_port = req->rport; | ||
290 | cm_event.private_data_len = | ||
291 | be32_to_cpu(req->private_data_length); | ||
292 | cm_event.private_data = req->private_data; | ||
293 | |||
294 | if (cm_id->event_handler) | ||
295 | cm_id->event_handler(cm_id, &cm_event); | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | case C2_RES_IND_CQ:{ | ||
300 | struct c2_cq *cq = | ||
301 | (struct c2_cq *) resource_user_context; | ||
302 | |||
303 | pr_debug("IB_EVENT_CQ_ERR\n"); | ||
304 | ib_event.device = &c2dev->ibdev; | ||
305 | ib_event.element.cq = &cq->ibcq; | ||
306 | ib_event.event = IB_EVENT_CQ_ERR; | ||
307 | |||
308 | if (cq->ibcq.event_handler) | ||
309 | cq->ibcq.event_handler(&ib_event, | ||
310 | cq->ibcq.cq_context); | ||
311 | } | ||
312 | |||
313 | default: | ||
314 | printk("Bad resource indicator = %d\n", | ||
315 | resource_indicator); | ||
316 | break; | ||
317 | } | ||
318 | |||
319 | ignore_it: | ||
320 | c2_mq_free(mq); | ||
321 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_ae.h b/drivers/infiniband/hw/amso1100/c2_ae.h new file mode 100644 index 000000000000..3a065c33b83b --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_ae.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #ifndef _C2_AE_H_ | ||
34 | #define _C2_AE_H_ | ||
35 | |||
36 | /* | ||
37 | * WARNING: If you change this file, also bump C2_IVN_BASE | ||
38 | * in common/include/clustercore/c2_ivn.h. | ||
39 | */ | ||
40 | |||
41 | /* | ||
42 | * Asynchronous Event Identifiers | ||
43 | * | ||
44 | * These start at 0x80 only so it's obvious from inspection that | ||
45 | * they are not work-request statuses. This isn't critical. | ||
46 | * | ||
47 | * NOTE: these event id's must fit in eight bits. | ||
48 | */ | ||
49 | enum c2_event_id { | ||
50 | CCAE_REMOTE_SHUTDOWN = 0x80, | ||
51 | CCAE_ACTIVE_CONNECT_RESULTS, | ||
52 | CCAE_CONNECTION_REQUEST, | ||
53 | CCAE_LLP_CLOSE_COMPLETE, | ||
54 | CCAE_TERMINATE_MESSAGE_RECEIVED, | ||
55 | CCAE_LLP_CONNECTION_RESET, | ||
56 | CCAE_LLP_CONNECTION_LOST, | ||
57 | CCAE_LLP_SEGMENT_SIZE_INVALID, | ||
58 | CCAE_LLP_INVALID_CRC, | ||
59 | CCAE_LLP_BAD_FPDU, | ||
60 | CCAE_INVALID_DDP_VERSION, | ||
61 | CCAE_INVALID_RDMA_VERSION, | ||
62 | CCAE_UNEXPECTED_OPCODE, | ||
63 | CCAE_INVALID_DDP_QUEUE_NUMBER, | ||
64 | CCAE_RDMA_READ_NOT_ENABLED, | ||
65 | CCAE_RDMA_WRITE_NOT_ENABLED, | ||
66 | CCAE_RDMA_READ_TOO_SMALL, | ||
67 | CCAE_NO_L_BIT, | ||
68 | CCAE_TAGGED_INVALID_STAG, | ||
69 | CCAE_TAGGED_BASE_BOUNDS_VIOLATION, | ||
70 | CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION, | ||
71 | CCAE_TAGGED_INVALID_PD, | ||
72 | CCAE_WRAP_ERROR, | ||
73 | CCAE_BAD_CLOSE, | ||
74 | CCAE_BAD_LLP_CLOSE, | ||
75 | CCAE_INVALID_MSN_RANGE, | ||
76 | CCAE_INVALID_MSN_GAP, | ||
77 | CCAE_IRRQ_OVERFLOW, | ||
78 | CCAE_IRRQ_MSN_GAP, | ||
79 | CCAE_IRRQ_MSN_RANGE, | ||
80 | CCAE_IRRQ_INVALID_STAG, | ||
81 | CCAE_IRRQ_BASE_BOUNDS_VIOLATION, | ||
82 | CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION, | ||
83 | CCAE_IRRQ_INVALID_PD, | ||
84 | CCAE_IRRQ_WRAP_ERROR, | ||
85 | CCAE_CQ_SQ_COMPLETION_OVERFLOW, | ||
86 | CCAE_CQ_RQ_COMPLETION_ERROR, | ||
87 | CCAE_QP_SRQ_WQE_ERROR, | ||
88 | CCAE_QP_LOCAL_CATASTROPHIC_ERROR, | ||
89 | CCAE_CQ_OVERFLOW, | ||
90 | CCAE_CQ_OPERATION_ERROR, | ||
91 | CCAE_SRQ_LIMIT_REACHED, | ||
92 | CCAE_QP_RQ_LIMIT_REACHED, | ||
93 | CCAE_SRQ_CATASTROPHIC_ERROR, | ||
94 | CCAE_RNIC_CATASTROPHIC_ERROR | ||
95 | /* WARNING If you add more id's, make sure their values fit in eight bits. */ | ||
96 | }; | ||
97 | |||
98 | /* | ||
99 | * Resource Indicators and Identifiers | ||
100 | */ | ||
101 | enum c2_resource_indicator { | ||
102 | C2_RES_IND_QP = 1, | ||
103 | C2_RES_IND_EP, | ||
104 | C2_RES_IND_CQ, | ||
105 | C2_RES_IND_SRQ, | ||
106 | }; | ||
107 | |||
108 | #endif /* _C2_AE_H_ */ | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_alloc.c b/drivers/infiniband/hw/amso1100/c2_alloc.c new file mode 100644 index 000000000000..1d2529992c0c --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_alloc.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #include <linux/errno.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/bitmap.h> | ||
37 | |||
38 | #include "c2.h" | ||
39 | |||
40 | static int c2_alloc_mqsp_chunk(struct c2_dev *c2dev, gfp_t gfp_mask, | ||
41 | struct sp_chunk **head) | ||
42 | { | ||
43 | int i; | ||
44 | struct sp_chunk *new_head; | ||
45 | |||
46 | new_head = (struct sp_chunk *) __get_free_page(gfp_mask); | ||
47 | if (new_head == NULL) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | new_head->dma_addr = dma_map_single(c2dev->ibdev.dma_device, new_head, | ||
51 | PAGE_SIZE, DMA_FROM_DEVICE); | ||
52 | pci_unmap_addr_set(new_head, mapping, new_head->dma_addr); | ||
53 | |||
54 | new_head->next = NULL; | ||
55 | new_head->head = 0; | ||
56 | |||
57 | /* build list where each index is the next free slot */ | ||
58 | for (i = 0; | ||
59 | i < (PAGE_SIZE - sizeof(struct sp_chunk) - | ||
60 | sizeof(u16)) / sizeof(u16) - 1; | ||
61 | i++) { | ||
62 | new_head->shared_ptr[i] = i + 1; | ||
63 | } | ||
64 | /* terminate list */ | ||
65 | new_head->shared_ptr[i] = 0xFFFF; | ||
66 | |||
67 | *head = new_head; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask, | ||
72 | struct sp_chunk **root) | ||
73 | { | ||
74 | return c2_alloc_mqsp_chunk(c2dev, gfp_mask, root); | ||
75 | } | ||
76 | |||
77 | void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root) | ||
78 | { | ||
79 | struct sp_chunk *next; | ||
80 | |||
81 | while (root) { | ||
82 | next = root->next; | ||
83 | dma_unmap_single(c2dev->ibdev.dma_device, | ||
84 | pci_unmap_addr(root, mapping), PAGE_SIZE, | ||
85 | DMA_FROM_DEVICE); | ||
86 | __free_page((struct page *) root); | ||
87 | root = next; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | u16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head, | ||
92 | dma_addr_t *dma_addr, gfp_t gfp_mask) | ||
93 | { | ||
94 | u16 mqsp; | ||
95 | |||
96 | while (head) { | ||
97 | mqsp = head->head; | ||
98 | if (mqsp != 0xFFFF) { | ||
99 | head->head = head->shared_ptr[mqsp]; | ||
100 | break; | ||
101 | } else if (head->next == NULL) { | ||
102 | if (c2_alloc_mqsp_chunk(c2dev, gfp_mask, &head->next) == | ||
103 | 0) { | ||
104 | head = head->next; | ||
105 | mqsp = head->head; | ||
106 | head->head = head->shared_ptr[mqsp]; | ||
107 | break; | ||
108 | } else | ||
109 | return NULL; | ||
110 | } else | ||
111 | head = head->next; | ||
112 | } | ||
113 | if (head) { | ||
114 | *dma_addr = head->dma_addr + | ||
115 | ((unsigned long) &(head->shared_ptr[mqsp]) - | ||
116 | (unsigned long) head); | ||
117 | pr_debug("%s addr %p dma_addr %llx\n", __FUNCTION__, | ||
118 | &(head->shared_ptr[mqsp]), (u64)*dma_addr); | ||
119 | return &(head->shared_ptr[mqsp]); | ||
120 | } | ||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | void c2_free_mqsp(u16 * mqsp) | ||
125 | { | ||
126 | struct sp_chunk *head; | ||
127 | u16 idx; | ||
128 | |||
129 | /* The chunk containing this ptr begins at the page boundary */ | ||
130 | head = (struct sp_chunk *) ((unsigned long) mqsp & PAGE_MASK); | ||
131 | |||
132 | /* Link head to new mqsp */ | ||
133 | *mqsp = head->head; | ||
134 | |||
135 | /* Compute the shared_ptr index */ | ||
136 | idx = ((unsigned long) mqsp & ~PAGE_MASK) >> 1; | ||
137 | idx -= (unsigned long) &(((struct sp_chunk *) 0)->shared_ptr[0]) >> 1; | ||
138 | |||
139 | /* Point this index at the head */ | ||
140 | head->shared_ptr[idx] = head->head; | ||
141 | |||
142 | /* Point head at this index */ | ||
143 | head->head = idx; | ||
144 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_cm.c b/drivers/infiniband/hw/amso1100/c2_cm.c new file mode 100644 index 000000000000..485254efdd1e --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_cm.c | |||
@@ -0,0 +1,452 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | * | ||
33 | */ | ||
34 | #include "c2.h" | ||
35 | #include "c2_wr.h" | ||
36 | #include "c2_vq.h" | ||
37 | #include <rdma/iw_cm.h> | ||
38 | |||
39 | int c2_llp_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param) | ||
40 | { | ||
41 | struct c2_dev *c2dev = to_c2dev(cm_id->device); | ||
42 | struct ib_qp *ibqp; | ||
43 | struct c2_qp *qp; | ||
44 | struct c2wr_qp_connect_req *wr; /* variable size needs a malloc. */ | ||
45 | struct c2_vq_req *vq_req; | ||
46 | int err; | ||
47 | |||
48 | ibqp = c2_get_qp(cm_id->device, iw_param->qpn); | ||
49 | if (!ibqp) | ||
50 | return -EINVAL; | ||
51 | qp = to_c2qp(ibqp); | ||
52 | |||
53 | /* Associate QP <--> CM_ID */ | ||
54 | cm_id->provider_data = qp; | ||
55 | cm_id->add_ref(cm_id); | ||
56 | qp->cm_id = cm_id; | ||
57 | |||
58 | /* | ||
59 | * only support the max private_data length | ||
60 | */ | ||
61 | if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) { | ||
62 | err = -EINVAL; | ||
63 | goto bail0; | ||
64 | } | ||
65 | /* | ||
66 | * Set the rdma read limits | ||
67 | */ | ||
68 | err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird); | ||
69 | if (err) | ||
70 | goto bail0; | ||
71 | |||
72 | /* | ||
73 | * Create and send a WR_QP_CONNECT... | ||
74 | */ | ||
75 | wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); | ||
76 | if (!wr) { | ||
77 | err = -ENOMEM; | ||
78 | goto bail0; | ||
79 | } | ||
80 | |||
81 | vq_req = vq_req_alloc(c2dev); | ||
82 | if (!vq_req) { | ||
83 | err = -ENOMEM; | ||
84 | goto bail1; | ||
85 | } | ||
86 | |||
87 | c2_wr_set_id(wr, CCWR_QP_CONNECT); | ||
88 | wr->hdr.context = 0; | ||
89 | wr->rnic_handle = c2dev->adapter_handle; | ||
90 | wr->qp_handle = qp->adapter_handle; | ||
91 | |||
92 | wr->remote_addr = cm_id->remote_addr.sin_addr.s_addr; | ||
93 | wr->remote_port = cm_id->remote_addr.sin_port; | ||
94 | |||
95 | /* | ||
96 | * Move any private data from the callers's buf into | ||
97 | * the WR. | ||
98 | */ | ||
99 | if (iw_param->private_data) { | ||
100 | wr->private_data_length = | ||
101 | cpu_to_be32(iw_param->private_data_len); | ||
102 | memcpy(&wr->private_data[0], iw_param->private_data, | ||
103 | iw_param->private_data_len); | ||
104 | } else | ||
105 | wr->private_data_length = 0; | ||
106 | |||
107 | /* | ||
108 | * Send WR to adapter. NOTE: There is no synch reply from | ||
109 | * the adapter. | ||
110 | */ | ||
111 | err = vq_send_wr(c2dev, (union c2wr *) wr); | ||
112 | vq_req_free(c2dev, vq_req); | ||
113 | |||
114 | bail1: | ||
115 | kfree(wr); | ||
116 | bail0: | ||
117 | if (err) { | ||
118 | /* | ||
119 | * If we fail, release reference on QP and | ||
120 | * disassociate QP from CM_ID | ||
121 | */ | ||
122 | cm_id->provider_data = NULL; | ||
123 | qp->cm_id = NULL; | ||
124 | cm_id->rem_ref(cm_id); | ||
125 | } | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog) | ||
130 | { | ||
131 | struct c2_dev *c2dev; | ||
132 | struct c2wr_ep_listen_create_req wr; | ||
133 | struct c2wr_ep_listen_create_rep *reply; | ||
134 | struct c2_vq_req *vq_req; | ||
135 | int err; | ||
136 | |||
137 | c2dev = to_c2dev(cm_id->device); | ||
138 | if (c2dev == NULL) | ||
139 | return -EINVAL; | ||
140 | |||
141 | /* | ||
142 | * Allocate verbs request. | ||
143 | */ | ||
144 | vq_req = vq_req_alloc(c2dev); | ||
145 | if (!vq_req) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | /* | ||
149 | * Build the WR | ||
150 | */ | ||
151 | c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE); | ||
152 | wr.hdr.context = (u64) (unsigned long) vq_req; | ||
153 | wr.rnic_handle = c2dev->adapter_handle; | ||
154 | wr.local_addr = cm_id->local_addr.sin_addr.s_addr; | ||
155 | wr.local_port = cm_id->local_addr.sin_port; | ||
156 | wr.backlog = cpu_to_be32(backlog); | ||
157 | wr.user_context = (u64) (unsigned long) cm_id; | ||
158 | |||
159 | /* | ||
160 | * Reference the request struct. Dereferenced in the int handler. | ||
161 | */ | ||
162 | vq_req_get(c2dev, vq_req); | ||
163 | |||
164 | /* | ||
165 | * Send WR to adapter | ||
166 | */ | ||
167 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
168 | if (err) { | ||
169 | vq_req_put(c2dev, vq_req); | ||
170 | goto bail0; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Wait for reply from adapter | ||
175 | */ | ||
176 | err = vq_wait_for_reply(c2dev, vq_req); | ||
177 | if (err) | ||
178 | goto bail0; | ||
179 | |||
180 | /* | ||
181 | * Process reply | ||
182 | */ | ||
183 | reply = | ||
184 | (struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg; | ||
185 | if (!reply) { | ||
186 | err = -ENOMEM; | ||
187 | goto bail1; | ||
188 | } | ||
189 | |||
190 | if ((err = c2_errno(reply)) != 0) | ||
191 | goto bail1; | ||
192 | |||
193 | /* | ||
194 | * Keep the adapter handle. Used in subsequent destroy | ||
195 | */ | ||
196 | cm_id->provider_data = (void*)(unsigned long) reply->ep_handle; | ||
197 | |||
198 | /* | ||
199 | * free vq stuff | ||
200 | */ | ||
201 | vq_repbuf_free(c2dev, reply); | ||
202 | vq_req_free(c2dev, vq_req); | ||
203 | |||
204 | return 0; | ||
205 | |||
206 | bail1: | ||
207 | vq_repbuf_free(c2dev, reply); | ||
208 | bail0: | ||
209 | vq_req_free(c2dev, vq_req); | ||
210 | return err; | ||
211 | } | ||
212 | |||
213 | |||
214 | int c2_llp_service_destroy(struct iw_cm_id *cm_id) | ||
215 | { | ||
216 | |||
217 | struct c2_dev *c2dev; | ||
218 | struct c2wr_ep_listen_destroy_req wr; | ||
219 | struct c2wr_ep_listen_destroy_rep *reply; | ||
220 | struct c2_vq_req *vq_req; | ||
221 | int err; | ||
222 | |||
223 | c2dev = to_c2dev(cm_id->device); | ||
224 | if (c2dev == NULL) | ||
225 | return -EINVAL; | ||
226 | |||
227 | /* | ||
228 | * Allocate verbs request. | ||
229 | */ | ||
230 | vq_req = vq_req_alloc(c2dev); | ||
231 | if (!vq_req) | ||
232 | return -ENOMEM; | ||
233 | |||
234 | /* | ||
235 | * Build the WR | ||
236 | */ | ||
237 | c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY); | ||
238 | wr.hdr.context = (unsigned long) vq_req; | ||
239 | wr.rnic_handle = c2dev->adapter_handle; | ||
240 | wr.ep_handle = (u32)(unsigned long)cm_id->provider_data; | ||
241 | |||
242 | /* | ||
243 | * reference the request struct. dereferenced in the int handler. | ||
244 | */ | ||
245 | vq_req_get(c2dev, vq_req); | ||
246 | |||
247 | /* | ||
248 | * Send WR to adapter | ||
249 | */ | ||
250 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
251 | if (err) { | ||
252 | vq_req_put(c2dev, vq_req); | ||
253 | goto bail0; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Wait for reply from adapter | ||
258 | */ | ||
259 | err = vq_wait_for_reply(c2dev, vq_req); | ||
260 | if (err) | ||
261 | goto bail0; | ||
262 | |||
263 | /* | ||
264 | * Process reply | ||
265 | */ | ||
266 | reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg; | ||
267 | if (!reply) { | ||
268 | err = -ENOMEM; | ||
269 | goto bail0; | ||
270 | } | ||
271 | if ((err = c2_errno(reply)) != 0) | ||
272 | goto bail1; | ||
273 | |||
274 | bail1: | ||
275 | vq_repbuf_free(c2dev, reply); | ||
276 | bail0: | ||
277 | vq_req_free(c2dev, vq_req); | ||
278 | return err; | ||
279 | } | ||
280 | |||
281 | int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param) | ||
282 | { | ||
283 | struct c2_dev *c2dev = to_c2dev(cm_id->device); | ||
284 | struct c2_qp *qp; | ||
285 | struct ib_qp *ibqp; | ||
286 | struct c2wr_cr_accept_req *wr; /* variable length WR */ | ||
287 | struct c2_vq_req *vq_req; | ||
288 | struct c2wr_cr_accept_rep *reply; /* VQ Reply msg ptr. */ | ||
289 | int err; | ||
290 | |||
291 | ibqp = c2_get_qp(cm_id->device, iw_param->qpn); | ||
292 | if (!ibqp) | ||
293 | return -EINVAL; | ||
294 | qp = to_c2qp(ibqp); | ||
295 | |||
296 | /* Set the RDMA read limits */ | ||
297 | err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird); | ||
298 | if (err) | ||
299 | goto bail0; | ||
300 | |||
301 | /* Allocate verbs request. */ | ||
302 | vq_req = vq_req_alloc(c2dev); | ||
303 | if (!vq_req) { | ||
304 | err = -ENOMEM; | ||
305 | goto bail1; | ||
306 | } | ||
307 | vq_req->qp = qp; | ||
308 | vq_req->cm_id = cm_id; | ||
309 | vq_req->event = IW_CM_EVENT_ESTABLISHED; | ||
310 | |||
311 | wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); | ||
312 | if (!wr) { | ||
313 | err = -ENOMEM; | ||
314 | goto bail2; | ||
315 | } | ||
316 | |||
317 | /* Build the WR */ | ||
318 | c2_wr_set_id(wr, CCWR_CR_ACCEPT); | ||
319 | wr->hdr.context = (unsigned long) vq_req; | ||
320 | wr->rnic_handle = c2dev->adapter_handle; | ||
321 | wr->ep_handle = (u32) (unsigned long) cm_id->provider_data; | ||
322 | wr->qp_handle = qp->adapter_handle; | ||
323 | |||
324 | /* Replace the cr_handle with the QP after accept */ | ||
325 | cm_id->provider_data = qp; | ||
326 | cm_id->add_ref(cm_id); | ||
327 | qp->cm_id = cm_id; | ||
328 | |||
329 | cm_id->provider_data = qp; | ||
330 | |||
331 | /* Validate private_data length */ | ||
332 | if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) { | ||
333 | err = -EINVAL; | ||
334 | goto bail2; | ||
335 | } | ||
336 | |||
337 | if (iw_param->private_data) { | ||
338 | wr->private_data_length = cpu_to_be32(iw_param->private_data_len); | ||
339 | memcpy(&wr->private_data[0], | ||
340 | iw_param->private_data, iw_param->private_data_len); | ||
341 | } else | ||
342 | wr->private_data_length = 0; | ||
343 | |||
344 | /* Reference the request struct. Dereferenced in the int handler. */ | ||
345 | vq_req_get(c2dev, vq_req); | ||
346 | |||
347 | /* Send WR to adapter */ | ||
348 | err = vq_send_wr(c2dev, (union c2wr *) wr); | ||
349 | if (err) { | ||
350 | vq_req_put(c2dev, vq_req); | ||
351 | goto bail2; | ||
352 | } | ||
353 | |||
354 | /* Wait for reply from adapter */ | ||
355 | err = vq_wait_for_reply(c2dev, vq_req); | ||
356 | if (err) | ||
357 | goto bail2; | ||
358 | |||
359 | /* Check that reply is present */ | ||
360 | reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg; | ||
361 | if (!reply) { | ||
362 | err = -ENOMEM; | ||
363 | goto bail2; | ||
364 | } | ||
365 | |||
366 | err = c2_errno(reply); | ||
367 | vq_repbuf_free(c2dev, reply); | ||
368 | |||
369 | if (!err) | ||
370 | c2_set_qp_state(qp, C2_QP_STATE_RTS); | ||
371 | bail2: | ||
372 | kfree(wr); | ||
373 | bail1: | ||
374 | vq_req_free(c2dev, vq_req); | ||
375 | bail0: | ||
376 | if (err) { | ||
377 | /* | ||
378 | * If we fail, release reference on QP and | ||
379 | * disassociate QP from CM_ID | ||
380 | */ | ||
381 | cm_id->provider_data = NULL; | ||
382 | qp->cm_id = NULL; | ||
383 | cm_id->rem_ref(cm_id); | ||
384 | } | ||
385 | return err; | ||
386 | } | ||
387 | |||
388 | int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) | ||
389 | { | ||
390 | struct c2_dev *c2dev; | ||
391 | struct c2wr_cr_reject_req wr; | ||
392 | struct c2_vq_req *vq_req; | ||
393 | struct c2wr_cr_reject_rep *reply; | ||
394 | int err; | ||
395 | |||
396 | c2dev = to_c2dev(cm_id->device); | ||
397 | |||
398 | /* | ||
399 | * Allocate verbs request. | ||
400 | */ | ||
401 | vq_req = vq_req_alloc(c2dev); | ||
402 | if (!vq_req) | ||
403 | return -ENOMEM; | ||
404 | |||
405 | /* | ||
406 | * Build the WR | ||
407 | */ | ||
408 | c2_wr_set_id(&wr, CCWR_CR_REJECT); | ||
409 | wr.hdr.context = (unsigned long) vq_req; | ||
410 | wr.rnic_handle = c2dev->adapter_handle; | ||
411 | wr.ep_handle = (u32) (unsigned long) cm_id->provider_data; | ||
412 | |||
413 | /* | ||
414 | * reference the request struct. dereferenced in the int handler. | ||
415 | */ | ||
416 | vq_req_get(c2dev, vq_req); | ||
417 | |||
418 | /* | ||
419 | * Send WR to adapter | ||
420 | */ | ||
421 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
422 | if (err) { | ||
423 | vq_req_put(c2dev, vq_req); | ||
424 | goto bail0; | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * Wait for reply from adapter | ||
429 | */ | ||
430 | err = vq_wait_for_reply(c2dev, vq_req); | ||
431 | if (err) | ||
432 | goto bail0; | ||
433 | |||
434 | /* | ||
435 | * Process reply | ||
436 | */ | ||
437 | reply = (struct c2wr_cr_reject_rep *) (unsigned long) | ||
438 | vq_req->reply_msg; | ||
439 | if (!reply) { | ||
440 | err = -ENOMEM; | ||
441 | goto bail0; | ||
442 | } | ||
443 | err = c2_errno(reply); | ||
444 | /* | ||
445 | * free vq stuff | ||
446 | */ | ||
447 | vq_repbuf_free(c2dev, reply); | ||
448 | |||
449 | bail0: | ||
450 | vq_req_free(c2dev, vq_req); | ||
451 | return err; | ||
452 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c new file mode 100644 index 000000000000..9d7bcc5ade93 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_cq.c | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | ||
3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. | ||
4 | * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved. | ||
5 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | ||
6 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. | ||
7 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
8 | * | ||
9 | * This software is available to you under a choice of one of two | ||
10 | * licenses. You may choose to be licensed under the terms of the GNU | ||
11 | * General Public License (GPL) Version 2, available from the file | ||
12 | * COPYING in the main directory of this source tree, or the | ||
13 | * OpenIB.org BSD license below: | ||
14 | * | ||
15 | * Redistribution and use in source and binary forms, with or | ||
16 | * without modification, are permitted provided that the following | ||
17 | * conditions are met: | ||
18 | * | ||
19 | * - Redistributions of source code must retain the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer. | ||
22 | * | ||
23 | * - Redistributions in binary form must reproduce the above | ||
24 | * copyright notice, this list of conditions and the following | ||
25 | * disclaimer in the documentation and/or other materials | ||
26 | * provided with the distribution. | ||
27 | * | ||
28 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
29 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
31 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
32 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
33 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
34 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
35 | * SOFTWARE. | ||
36 | * | ||
37 | */ | ||
38 | #include "c2.h" | ||
39 | #include "c2_vq.h" | ||
40 | #include "c2_status.h" | ||
41 | |||
42 | #define C2_CQ_MSG_SIZE ((sizeof(struct c2wr_ce) + 32-1) & ~(32-1)) | ||
43 | |||
44 | static struct c2_cq *c2_cq_get(struct c2_dev *c2dev, int cqn) | ||
45 | { | ||
46 | struct c2_cq *cq; | ||
47 | unsigned long flags; | ||
48 | |||
49 | spin_lock_irqsave(&c2dev->lock, flags); | ||
50 | cq = c2dev->qptr_array[cqn]; | ||
51 | if (!cq) { | ||
52 | spin_unlock_irqrestore(&c2dev->lock, flags); | ||
53 | return NULL; | ||
54 | } | ||
55 | atomic_inc(&cq->refcount); | ||
56 | spin_unlock_irqrestore(&c2dev->lock, flags); | ||
57 | return cq; | ||
58 | } | ||
59 | |||
60 | static void c2_cq_put(struct c2_cq *cq) | ||
61 | { | ||
62 | if (atomic_dec_and_test(&cq->refcount)) | ||
63 | wake_up(&cq->wait); | ||
64 | } | ||
65 | |||
66 | void c2_cq_event(struct c2_dev *c2dev, u32 mq_index) | ||
67 | { | ||
68 | struct c2_cq *cq; | ||
69 | |||
70 | cq = c2_cq_get(c2dev, mq_index); | ||
71 | if (!cq) { | ||
72 | printk("discarding events on destroyed CQN=%d\n", mq_index); | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); | ||
77 | c2_cq_put(cq); | ||
78 | } | ||
79 | |||
80 | void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index) | ||
81 | { | ||
82 | struct c2_cq *cq; | ||
83 | struct c2_mq *q; | ||
84 | |||
85 | cq = c2_cq_get(c2dev, mq_index); | ||
86 | if (!cq) | ||
87 | return; | ||
88 | |||
89 | spin_lock_irq(&cq->lock); | ||
90 | q = &cq->mq; | ||
91 | if (q && !c2_mq_empty(q)) { | ||
92 | u16 priv = q->priv; | ||
93 | struct c2wr_ce *msg; | ||
94 | |||
95 | while (priv != be16_to_cpu(*q->shared)) { | ||
96 | msg = (struct c2wr_ce *) | ||
97 | (q->msg_pool.host + priv * q->msg_size); | ||
98 | if (msg->qp_user_context == (u64) (unsigned long) qp) { | ||
99 | msg->qp_user_context = (u64) 0; | ||
100 | } | ||
101 | priv = (priv + 1) % q->q_size; | ||
102 | } | ||
103 | } | ||
104 | spin_unlock_irq(&cq->lock); | ||
105 | c2_cq_put(cq); | ||
106 | } | ||
107 | |||
108 | static inline enum ib_wc_status c2_cqe_status_to_openib(u8 status) | ||
109 | { | ||
110 | switch (status) { | ||
111 | case C2_OK: | ||
112 | return IB_WC_SUCCESS; | ||
113 | case CCERR_FLUSHED: | ||
114 | return IB_WC_WR_FLUSH_ERR; | ||
115 | case CCERR_BASE_AND_BOUNDS_VIOLATION: | ||
116 | return IB_WC_LOC_PROT_ERR; | ||
117 | case CCERR_ACCESS_VIOLATION: | ||
118 | return IB_WC_LOC_ACCESS_ERR; | ||
119 | case CCERR_TOTAL_LENGTH_TOO_BIG: | ||
120 | return IB_WC_LOC_LEN_ERR; | ||
121 | case CCERR_INVALID_WINDOW: | ||
122 | return IB_WC_MW_BIND_ERR; | ||
123 | default: | ||
124 | return IB_WC_GENERAL_ERR; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | |||
129 | static inline int c2_poll_one(struct c2_dev *c2dev, | ||
130 | struct c2_cq *cq, struct ib_wc *entry) | ||
131 | { | ||
132 | struct c2wr_ce *ce; | ||
133 | struct c2_qp *qp; | ||
134 | int is_recv = 0; | ||
135 | |||
136 | ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq); | ||
137 | if (!ce) { | ||
138 | return -EAGAIN; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * if the qp returned is null then this qp has already | ||
143 | * been freed and we are unable process the completion. | ||
144 | * try pulling the next message | ||
145 | */ | ||
146 | while ((qp = | ||
147 | (struct c2_qp *) (unsigned long) ce->qp_user_context) == NULL) { | ||
148 | c2_mq_free(&cq->mq); | ||
149 | ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq); | ||
150 | if (!ce) | ||
151 | return -EAGAIN; | ||
152 | } | ||
153 | |||
154 | entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce)); | ||
155 | entry->wr_id = ce->hdr.context; | ||
156 | entry->qp_num = ce->handle; | ||
157 | entry->wc_flags = 0; | ||
158 | entry->slid = 0; | ||
159 | entry->sl = 0; | ||
160 | entry->src_qp = 0; | ||
161 | entry->dlid_path_bits = 0; | ||
162 | entry->pkey_index = 0; | ||
163 | |||
164 | switch (c2_wr_get_id(ce)) { | ||
165 | case C2_WR_TYPE_SEND: | ||
166 | entry->opcode = IB_WC_SEND; | ||
167 | break; | ||
168 | case C2_WR_TYPE_RDMA_WRITE: | ||
169 | entry->opcode = IB_WC_RDMA_WRITE; | ||
170 | break; | ||
171 | case C2_WR_TYPE_RDMA_READ: | ||
172 | entry->opcode = IB_WC_RDMA_READ; | ||
173 | break; | ||
174 | case C2_WR_TYPE_BIND_MW: | ||
175 | entry->opcode = IB_WC_BIND_MW; | ||
176 | break; | ||
177 | case C2_WR_TYPE_RECV: | ||
178 | entry->byte_len = be32_to_cpu(ce->bytes_rcvd); | ||
179 | entry->opcode = IB_WC_RECV; | ||
180 | is_recv = 1; | ||
181 | break; | ||
182 | default: | ||
183 | break; | ||
184 | } | ||
185 | |||
186 | /* consume the WQEs */ | ||
187 | if (is_recv) | ||
188 | c2_mq_lconsume(&qp->rq_mq, 1); | ||
189 | else | ||
190 | c2_mq_lconsume(&qp->sq_mq, | ||
191 | be32_to_cpu(c2_wr_get_wqe_count(ce)) + 1); | ||
192 | |||
193 | /* free the message */ | ||
194 | c2_mq_free(&cq->mq); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) | ||
200 | { | ||
201 | struct c2_dev *c2dev = to_c2dev(ibcq->device); | ||
202 | struct c2_cq *cq = to_c2cq(ibcq); | ||
203 | unsigned long flags; | ||
204 | int npolled, err; | ||
205 | |||
206 | spin_lock_irqsave(&cq->lock, flags); | ||
207 | |||
208 | for (npolled = 0; npolled < num_entries; ++npolled) { | ||
209 | |||
210 | err = c2_poll_one(c2dev, cq, entry + npolled); | ||
211 | if (err) | ||
212 | break; | ||
213 | } | ||
214 | |||
215 | spin_unlock_irqrestore(&cq->lock, flags); | ||
216 | |||
217 | return npolled; | ||
218 | } | ||
219 | |||
220 | int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) | ||
221 | { | ||
222 | struct c2_mq_shared __iomem *shared; | ||
223 | struct c2_cq *cq; | ||
224 | |||
225 | cq = to_c2cq(ibcq); | ||
226 | shared = cq->mq.peer; | ||
227 | |||
228 | if (notify == IB_CQ_NEXT_COMP) | ||
229 | writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type); | ||
230 | else if (notify == IB_CQ_SOLICITED) | ||
231 | writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type); | ||
232 | else | ||
233 | return -EINVAL; | ||
234 | |||
235 | writeb(CQ_WAIT_FOR_DMA | CQ_ARMED, &shared->armed); | ||
236 | |||
237 | /* | ||
238 | * Now read back shared->armed to make the PCI | ||
239 | * write synchronous. This is necessary for | ||
240 | * correct cq notification semantics. | ||
241 | */ | ||
242 | readb(&shared->armed); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq) | ||
248 | { | ||
249 | |||
250 | dma_unmap_single(c2dev->ibdev.dma_device, pci_unmap_addr(mq, mapping), | ||
251 | mq->q_size * mq->msg_size, DMA_FROM_DEVICE); | ||
252 | free_pages((unsigned long) mq->msg_pool.host, | ||
253 | get_order(mq->q_size * mq->msg_size)); | ||
254 | } | ||
255 | |||
256 | static int c2_alloc_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq, int q_size, | ||
257 | int msg_size) | ||
258 | { | ||
259 | unsigned long pool_start; | ||
260 | |||
261 | pool_start = __get_free_pages(GFP_KERNEL, | ||
262 | get_order(q_size * msg_size)); | ||
263 | if (!pool_start) | ||
264 | return -ENOMEM; | ||
265 | |||
266 | c2_mq_rep_init(mq, | ||
267 | 0, /* index (currently unknown) */ | ||
268 | q_size, | ||
269 | msg_size, | ||
270 | (u8 *) pool_start, | ||
271 | NULL, /* peer (currently unknown) */ | ||
272 | C2_MQ_HOST_TARGET); | ||
273 | |||
274 | mq->host_dma = dma_map_single(c2dev->ibdev.dma_device, | ||
275 | (void *)pool_start, | ||
276 | q_size * msg_size, DMA_FROM_DEVICE); | ||
277 | pci_unmap_addr_set(mq, mapping, mq->host_dma); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | int c2_init_cq(struct c2_dev *c2dev, int entries, | ||
283 | struct c2_ucontext *ctx, struct c2_cq *cq) | ||
284 | { | ||
285 | struct c2wr_cq_create_req wr; | ||
286 | struct c2wr_cq_create_rep *reply; | ||
287 | unsigned long peer_pa; | ||
288 | struct c2_vq_req *vq_req; | ||
289 | int err; | ||
290 | |||
291 | might_sleep(); | ||
292 | |||
293 | cq->ibcq.cqe = entries - 1; | ||
294 | cq->is_kernel = !ctx; | ||
295 | |||
296 | /* Allocate a shared pointer */ | ||
297 | cq->mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, | ||
298 | &cq->mq.shared_dma, GFP_KERNEL); | ||
299 | if (!cq->mq.shared) | ||
300 | return -ENOMEM; | ||
301 | |||
302 | /* Allocate pages for the message pool */ | ||
303 | err = c2_alloc_cq_buf(c2dev, &cq->mq, entries + 1, C2_CQ_MSG_SIZE); | ||
304 | if (err) | ||
305 | goto bail0; | ||
306 | |||
307 | vq_req = vq_req_alloc(c2dev); | ||
308 | if (!vq_req) { | ||
309 | err = -ENOMEM; | ||
310 | goto bail1; | ||
311 | } | ||
312 | |||
313 | memset(&wr, 0, sizeof(wr)); | ||
314 | c2_wr_set_id(&wr, CCWR_CQ_CREATE); | ||
315 | wr.hdr.context = (unsigned long) vq_req; | ||
316 | wr.rnic_handle = c2dev->adapter_handle; | ||
317 | wr.msg_size = cpu_to_be32(cq->mq.msg_size); | ||
318 | wr.depth = cpu_to_be32(cq->mq.q_size); | ||
319 | wr.shared_ht = cpu_to_be64(cq->mq.shared_dma); | ||
320 | wr.msg_pool = cpu_to_be64(cq->mq.host_dma); | ||
321 | wr.user_context = (u64) (unsigned long) (cq); | ||
322 | |||
323 | vq_req_get(c2dev, vq_req); | ||
324 | |||
325 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
326 | if (err) { | ||
327 | vq_req_put(c2dev, vq_req); | ||
328 | goto bail2; | ||
329 | } | ||
330 | |||
331 | err = vq_wait_for_reply(c2dev, vq_req); | ||
332 | if (err) | ||
333 | goto bail2; | ||
334 | |||
335 | reply = (struct c2wr_cq_create_rep *) (unsigned long) (vq_req->reply_msg); | ||
336 | if (!reply) { | ||
337 | err = -ENOMEM; | ||
338 | goto bail2; | ||
339 | } | ||
340 | |||
341 | if ((err = c2_errno(reply)) != 0) | ||
342 | goto bail3; | ||
343 | |||
344 | cq->adapter_handle = reply->cq_handle; | ||
345 | cq->mq.index = be32_to_cpu(reply->mq_index); | ||
346 | |||
347 | peer_pa = c2dev->pa + be32_to_cpu(reply->adapter_shared); | ||
348 | cq->mq.peer = ioremap_nocache(peer_pa, PAGE_SIZE); | ||
349 | if (!cq->mq.peer) { | ||
350 | err = -ENOMEM; | ||
351 | goto bail3; | ||
352 | } | ||
353 | |||
354 | vq_repbuf_free(c2dev, reply); | ||
355 | vq_req_free(c2dev, vq_req); | ||
356 | |||
357 | spin_lock_init(&cq->lock); | ||
358 | atomic_set(&cq->refcount, 1); | ||
359 | init_waitqueue_head(&cq->wait); | ||
360 | |||
361 | /* | ||
362 | * Use the MQ index allocated by the adapter to | ||
363 | * store the CQ in the qptr_array | ||
364 | */ | ||
365 | cq->cqn = cq->mq.index; | ||
366 | c2dev->qptr_array[cq->cqn] = cq; | ||
367 | |||
368 | return 0; | ||
369 | |||
370 | bail3: | ||
371 | vq_repbuf_free(c2dev, reply); | ||
372 | bail2: | ||
373 | vq_req_free(c2dev, vq_req); | ||
374 | bail1: | ||
375 | c2_free_cq_buf(c2dev, &cq->mq); | ||
376 | bail0: | ||
377 | c2_free_mqsp(cq->mq.shared); | ||
378 | |||
379 | return err; | ||
380 | } | ||
381 | |||
382 | void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq) | ||
383 | { | ||
384 | int err; | ||
385 | struct c2_vq_req *vq_req; | ||
386 | struct c2wr_cq_destroy_req wr; | ||
387 | struct c2wr_cq_destroy_rep *reply; | ||
388 | |||
389 | might_sleep(); | ||
390 | |||
391 | /* Clear CQ from the qptr array */ | ||
392 | spin_lock_irq(&c2dev->lock); | ||
393 | c2dev->qptr_array[cq->mq.index] = NULL; | ||
394 | atomic_dec(&cq->refcount); | ||
395 | spin_unlock_irq(&c2dev->lock); | ||
396 | |||
397 | wait_event(cq->wait, !atomic_read(&cq->refcount)); | ||
398 | |||
399 | vq_req = vq_req_alloc(c2dev); | ||
400 | if (!vq_req) { | ||
401 | goto bail0; | ||
402 | } | ||
403 | |||
404 | memset(&wr, 0, sizeof(wr)); | ||
405 | c2_wr_set_id(&wr, CCWR_CQ_DESTROY); | ||
406 | wr.hdr.context = (unsigned long) vq_req; | ||
407 | wr.rnic_handle = c2dev->adapter_handle; | ||
408 | wr.cq_handle = cq->adapter_handle; | ||
409 | |||
410 | vq_req_get(c2dev, vq_req); | ||
411 | |||
412 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
413 | if (err) { | ||
414 | vq_req_put(c2dev, vq_req); | ||
415 | goto bail1; | ||
416 | } | ||
417 | |||
418 | err = vq_wait_for_reply(c2dev, vq_req); | ||
419 | if (err) | ||
420 | goto bail1; | ||
421 | |||
422 | reply = (struct c2wr_cq_destroy_rep *) (unsigned long) (vq_req->reply_msg); | ||
423 | |||
424 | vq_repbuf_free(c2dev, reply); | ||
425 | bail1: | ||
426 | vq_req_free(c2dev, vq_req); | ||
427 | bail0: | ||
428 | if (cq->is_kernel) { | ||
429 | c2_free_cq_buf(c2dev, &cq->mq); | ||
430 | } | ||
431 | |||
432 | return; | ||
433 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_intr.c b/drivers/infiniband/hw/amso1100/c2_intr.c new file mode 100644 index 000000000000..0d0bc33ca30a --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_intr.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #include "c2.h" | ||
34 | #include <rdma/iw_cm.h> | ||
35 | #include "c2_vq.h" | ||
36 | |||
37 | static void handle_mq(struct c2_dev *c2dev, u32 index); | ||
38 | static void handle_vq(struct c2_dev *c2dev, u32 mq_index); | ||
39 | |||
40 | /* | ||
41 | * Handle RNIC interrupts | ||
42 | */ | ||
43 | void c2_rnic_interrupt(struct c2_dev *c2dev) | ||
44 | { | ||
45 | unsigned int mq_index; | ||
46 | |||
47 | while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) { | ||
48 | mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT); | ||
49 | if (mq_index & 0x80000000) { | ||
50 | break; | ||
51 | } | ||
52 | |||
53 | c2dev->hints_read++; | ||
54 | handle_mq(c2dev, mq_index); | ||
55 | } | ||
56 | |||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Top level MQ handler | ||
61 | */ | ||
62 | static void handle_mq(struct c2_dev *c2dev, u32 mq_index) | ||
63 | { | ||
64 | if (c2dev->qptr_array[mq_index] == NULL) { | ||
65 | pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n", | ||
66 | mq_index); | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | switch (mq_index) { | ||
71 | case (0): | ||
72 | /* | ||
73 | * An index of 0 in the activity queue | ||
74 | * indicates the req vq now has messages | ||
75 | * available... | ||
76 | * | ||
77 | * Wake up any waiters waiting on req VQ | ||
78 | * message availability. | ||
79 | */ | ||
80 | wake_up(&c2dev->req_vq_wo); | ||
81 | break; | ||
82 | case (1): | ||
83 | handle_vq(c2dev, mq_index); | ||
84 | break; | ||
85 | case (2): | ||
86 | /* We have to purge the VQ in case there are pending | ||
87 | * accept reply requests that would result in the | ||
88 | * generation of an ESTABLISHED event. If we don't | ||
89 | * generate these first, a CLOSE event could end up | ||
90 | * being delivered before the ESTABLISHED event. | ||
91 | */ | ||
92 | handle_vq(c2dev, 1); | ||
93 | |||
94 | c2_ae_event(c2dev, mq_index); | ||
95 | break; | ||
96 | default: | ||
97 | /* There is no event synchronization between CQ events | ||
98 | * and AE or CM events. In fact, CQE could be | ||
99 | * delivered for all of the I/O up to and including the | ||
100 | * FLUSH for a peer disconenct prior to the ESTABLISHED | ||
101 | * event being delivered to the app. The reason for this | ||
102 | * is that CM events are delivered on a thread, while AE | ||
103 | * and CM events are delivered on interrupt context. | ||
104 | */ | ||
105 | c2_cq_event(c2dev, mq_index); | ||
106 | break; | ||
107 | } | ||
108 | |||
109 | return; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Handles verbs WR replies. | ||
114 | */ | ||
115 | static void handle_vq(struct c2_dev *c2dev, u32 mq_index) | ||
116 | { | ||
117 | void *adapter_msg, *reply_msg; | ||
118 | struct c2wr_hdr *host_msg; | ||
119 | struct c2wr_hdr tmp; | ||
120 | struct c2_mq *reply_vq; | ||
121 | struct c2_vq_req *req; | ||
122 | struct iw_cm_event cm_event; | ||
123 | int err; | ||
124 | |||
125 | reply_vq = (struct c2_mq *) c2dev->qptr_array[mq_index]; | ||
126 | |||
127 | /* | ||
128 | * get next msg from mq_index into adapter_msg. | ||
129 | * don't free it yet. | ||
130 | */ | ||
131 | adapter_msg = c2_mq_consume(reply_vq); | ||
132 | if (adapter_msg == NULL) { | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | host_msg = vq_repbuf_alloc(c2dev); | ||
137 | |||
138 | /* | ||
139 | * If we can't get a host buffer, then we'll still | ||
140 | * wakeup the waiter, we just won't give him the msg. | ||
141 | * It is assumed the waiter will deal with this... | ||
142 | */ | ||
143 | if (!host_msg) { | ||
144 | pr_debug("handle_vq: no repbufs!\n"); | ||
145 | |||
146 | /* | ||
147 | * just copy the WR header into a local variable. | ||
148 | * this allows us to still demux on the context | ||
149 | */ | ||
150 | host_msg = &tmp; | ||
151 | memcpy(host_msg, adapter_msg, sizeof(tmp)); | ||
152 | reply_msg = NULL; | ||
153 | } else { | ||
154 | memcpy(host_msg, adapter_msg, reply_vq->msg_size); | ||
155 | reply_msg = host_msg; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * consume the msg from the MQ | ||
160 | */ | ||
161 | c2_mq_free(reply_vq); | ||
162 | |||
163 | /* | ||
164 | * wakeup the waiter. | ||
165 | */ | ||
166 | req = (struct c2_vq_req *) (unsigned long) host_msg->context; | ||
167 | if (req == NULL) { | ||
168 | /* | ||
169 | * We should never get here, as the adapter should | ||
170 | * never send us a reply that we're not expecting. | ||
171 | */ | ||
172 | vq_repbuf_free(c2dev, host_msg); | ||
173 | pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n"); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | err = c2_errno(reply_msg); | ||
178 | if (!err) switch (req->event) { | ||
179 | case IW_CM_EVENT_ESTABLISHED: | ||
180 | c2_set_qp_state(req->qp, | ||
181 | C2_QP_STATE_RTS); | ||
182 | case IW_CM_EVENT_CLOSE: | ||
183 | |||
184 | /* | ||
185 | * Move the QP to RTS if this is | ||
186 | * the established event | ||
187 | */ | ||
188 | cm_event.event = req->event; | ||
189 | cm_event.status = 0; | ||
190 | cm_event.local_addr = req->cm_id->local_addr; | ||
191 | cm_event.remote_addr = req->cm_id->remote_addr; | ||
192 | cm_event.private_data = NULL; | ||
193 | cm_event.private_data_len = 0; | ||
194 | req->cm_id->event_handler(req->cm_id, &cm_event); | ||
195 | break; | ||
196 | default: | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | req->reply_msg = (u64) (unsigned long) (reply_msg); | ||
201 | atomic_set(&req->reply_ready, 1); | ||
202 | wake_up(&req->wait_object); | ||
203 | |||
204 | /* | ||
205 | * If the request was cancelled, then this put will | ||
206 | * free the vq_req memory...and reply_msg!!! | ||
207 | */ | ||
208 | vq_req_put(c2dev, req); | ||
209 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_mm.c b/drivers/infiniband/hw/amso1100/c2_mm.c new file mode 100644 index 000000000000..1e4f46493fcb --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_mm.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #include "c2.h" | ||
34 | #include "c2_vq.h" | ||
35 | |||
36 | #define PBL_VIRT 1 | ||
37 | #define PBL_PHYS 2 | ||
38 | |||
39 | /* | ||
40 | * Send all the PBL messages to convey the remainder of the PBL | ||
41 | * Wait for the adapter's reply on the last one. | ||
42 | * This is indicated by setting the MEM_PBL_COMPLETE in the flags. | ||
43 | * | ||
44 | * NOTE: vq_req is _not_ freed by this function. The VQ Host | ||
45 | * Reply buffer _is_ freed by this function. | ||
46 | */ | ||
47 | static int | ||
48 | send_pbl_messages(struct c2_dev *c2dev, u32 stag_index, | ||
49 | unsigned long va, u32 pbl_depth, | ||
50 | struct c2_vq_req *vq_req, int pbl_type) | ||
51 | { | ||
52 | u32 pbe_count; /* amt that fits in a PBL msg */ | ||
53 | u32 count; /* amt in this PBL MSG. */ | ||
54 | struct c2wr_nsmr_pbl_req *wr; /* PBL WR ptr */ | ||
55 | struct c2wr_nsmr_pbl_rep *reply; /* reply ptr */ | ||
56 | int err, pbl_virt, pbl_index, i; | ||
57 | |||
58 | switch (pbl_type) { | ||
59 | case PBL_VIRT: | ||
60 | pbl_virt = 1; | ||
61 | break; | ||
62 | case PBL_PHYS: | ||
63 | pbl_virt = 0; | ||
64 | break; | ||
65 | default: | ||
66 | return -EINVAL; | ||
67 | break; | ||
68 | } | ||
69 | |||
70 | pbe_count = (c2dev->req_vq.msg_size - | ||
71 | sizeof(struct c2wr_nsmr_pbl_req)) / sizeof(u64); | ||
72 | wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); | ||
73 | if (!wr) { | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | c2_wr_set_id(wr, CCWR_NSMR_PBL); | ||
77 | |||
78 | /* | ||
79 | * Only the last PBL message will generate a reply from the verbs, | ||
80 | * so we set the context to 0 indicating there is no kernel verbs | ||
81 | * handler blocked awaiting this reply. | ||
82 | */ | ||
83 | wr->hdr.context = 0; | ||
84 | wr->rnic_handle = c2dev->adapter_handle; | ||
85 | wr->stag_index = stag_index; /* already swapped */ | ||
86 | wr->flags = 0; | ||
87 | pbl_index = 0; | ||
88 | while (pbl_depth) { | ||
89 | count = min(pbe_count, pbl_depth); | ||
90 | wr->addrs_length = cpu_to_be32(count); | ||
91 | |||
92 | /* | ||
93 | * If this is the last message, then reference the | ||
94 | * vq request struct cuz we're gonna wait for a reply. | ||
95 | * also make this PBL msg as the last one. | ||
96 | */ | ||
97 | if (count == pbl_depth) { | ||
98 | /* | ||
99 | * reference the request struct. dereferenced in the | ||
100 | * int handler. | ||
101 | */ | ||
102 | vq_req_get(c2dev, vq_req); | ||
103 | wr->flags = cpu_to_be32(MEM_PBL_COMPLETE); | ||
104 | |||
105 | /* | ||
106 | * This is the last PBL message. | ||
107 | * Set the context to our VQ Request Object so we can | ||
108 | * wait for the reply. | ||
109 | */ | ||
110 | wr->hdr.context = (unsigned long) vq_req; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * If pbl_virt is set then va is a virtual address | ||
115 | * that describes a virtually contiguous memory | ||
116 | * allocation. The wr needs the start of each virtual page | ||
117 | * to be converted to the corresponding physical address | ||
118 | * of the page. If pbl_virt is not set then va is an array | ||
119 | * of physical addresses and there is no conversion to do. | ||
120 | * Just fill in the wr with what is in the array. | ||
121 | */ | ||
122 | for (i = 0; i < count; i++) { | ||
123 | if (pbl_virt) { | ||
124 | va += PAGE_SIZE; | ||
125 | } else { | ||
126 | wr->paddrs[i] = | ||
127 | cpu_to_be64(((u64 *)va)[pbl_index + i]); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * Send WR to adapter | ||
133 | */ | ||
134 | err = vq_send_wr(c2dev, (union c2wr *) wr); | ||
135 | if (err) { | ||
136 | if (count <= pbe_count) { | ||
137 | vq_req_put(c2dev, vq_req); | ||
138 | } | ||
139 | goto bail0; | ||
140 | } | ||
141 | pbl_depth -= count; | ||
142 | pbl_index += count; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Now wait for the reply... | ||
147 | */ | ||
148 | err = vq_wait_for_reply(c2dev, vq_req); | ||
149 | if (err) { | ||
150 | goto bail0; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Process reply | ||
155 | */ | ||
156 | reply = (struct c2wr_nsmr_pbl_rep *) (unsigned long) vq_req->reply_msg; | ||
157 | if (!reply) { | ||
158 | err = -ENOMEM; | ||
159 | goto bail0; | ||
160 | } | ||
161 | |||
162 | err = c2_errno(reply); | ||
163 | |||
164 | vq_repbuf_free(c2dev, reply); | ||
165 | bail0: | ||
166 | kfree(wr); | ||
167 | return err; | ||
168 | } | ||
169 | |||
170 | #define C2_PBL_MAX_DEPTH 131072 | ||
171 | int | ||
172 | c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list, | ||
173 | int page_size, int pbl_depth, u32 length, | ||
174 | u32 offset, u64 *va, enum c2_acf acf, | ||
175 | struct c2_mr *mr) | ||
176 | { | ||
177 | struct c2_vq_req *vq_req; | ||
178 | struct c2wr_nsmr_register_req *wr; | ||
179 | struct c2wr_nsmr_register_rep *reply; | ||
180 | u16 flags; | ||
181 | int i, pbe_count, count; | ||
182 | int err; | ||
183 | |||
184 | if (!va || !length || !addr_list || !pbl_depth) | ||
185 | return -EINTR; | ||
186 | |||
187 | /* | ||
188 | * Verify PBL depth is within rnic max | ||
189 | */ | ||
190 | if (pbl_depth > C2_PBL_MAX_DEPTH) { | ||
191 | return -EINTR; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * allocate verbs request object | ||
196 | */ | ||
197 | vq_req = vq_req_alloc(c2dev); | ||
198 | if (!vq_req) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); | ||
202 | if (!wr) { | ||
203 | err = -ENOMEM; | ||
204 | goto bail0; | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * build the WR | ||
209 | */ | ||
210 | c2_wr_set_id(wr, CCWR_NSMR_REGISTER); | ||
211 | wr->hdr.context = (unsigned long) vq_req; | ||
212 | wr->rnic_handle = c2dev->adapter_handle; | ||
213 | |||
214 | flags = (acf | MEM_VA_BASED | MEM_REMOTE); | ||
215 | |||
216 | /* | ||
217 | * compute how many pbes can fit in the message | ||
218 | */ | ||
219 | pbe_count = (c2dev->req_vq.msg_size - | ||
220 | sizeof(struct c2wr_nsmr_register_req)) / sizeof(u64); | ||
221 | |||
222 | if (pbl_depth <= pbe_count) { | ||
223 | flags |= MEM_PBL_COMPLETE; | ||
224 | } | ||
225 | wr->flags = cpu_to_be16(flags); | ||
226 | wr->stag_key = 0; //stag_key; | ||
227 | wr->va = cpu_to_be64(*va); | ||
228 | wr->pd_id = mr->pd->pd_id; | ||
229 | wr->pbe_size = cpu_to_be32(page_size); | ||
230 | wr->length = cpu_to_be32(length); | ||
231 | wr->pbl_depth = cpu_to_be32(pbl_depth); | ||
232 | wr->fbo = cpu_to_be32(offset); | ||
233 | count = min(pbl_depth, pbe_count); | ||
234 | wr->addrs_length = cpu_to_be32(count); | ||
235 | |||
236 | /* | ||
237 | * fill out the PBL for this message | ||
238 | */ | ||
239 | for (i = 0; i < count; i++) { | ||
240 | wr->paddrs[i] = cpu_to_be64(addr_list[i]); | ||
241 | } | ||
242 | |||
243 | /* | ||
244 | * regerence the request struct | ||
245 | */ | ||
246 | vq_req_get(c2dev, vq_req); | ||
247 | |||
248 | /* | ||
249 | * send the WR to the adapter | ||
250 | */ | ||
251 | err = vq_send_wr(c2dev, (union c2wr *) wr); | ||
252 | if (err) { | ||
253 | vq_req_put(c2dev, vq_req); | ||
254 | goto bail1; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * wait for reply from adapter | ||
259 | */ | ||
260 | err = vq_wait_for_reply(c2dev, vq_req); | ||
261 | if (err) { | ||
262 | goto bail1; | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * process reply | ||
267 | */ | ||
268 | reply = | ||
269 | (struct c2wr_nsmr_register_rep *) (unsigned long) (vq_req->reply_msg); | ||
270 | if (!reply) { | ||
271 | err = -ENOMEM; | ||
272 | goto bail1; | ||
273 | } | ||
274 | if ((err = c2_errno(reply))) { | ||
275 | goto bail2; | ||
276 | } | ||
277 | //*p_pb_entries = be32_to_cpu(reply->pbl_depth); | ||
278 | mr->ibmr.lkey = mr->ibmr.rkey = be32_to_cpu(reply->stag_index); | ||
279 | vq_repbuf_free(c2dev, reply); | ||
280 | |||
281 | /* | ||
282 | * if there are still more PBEs we need to send them to | ||
283 | * the adapter and wait for a reply on the final one. | ||
284 | * reuse vq_req for this purpose. | ||
285 | */ | ||
286 | pbl_depth -= count; | ||
287 | if (pbl_depth) { | ||
288 | |||
289 | vq_req->reply_msg = (unsigned long) NULL; | ||
290 | atomic_set(&vq_req->reply_ready, 0); | ||
291 | err = send_pbl_messages(c2dev, | ||
292 | cpu_to_be32(mr->ibmr.lkey), | ||
293 | (unsigned long) &addr_list[i], | ||
294 | pbl_depth, vq_req, PBL_PHYS); | ||
295 | if (err) { | ||
296 | goto bail1; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | vq_req_free(c2dev, vq_req); | ||
301 | kfree(wr); | ||
302 | |||
303 | return err; | ||
304 | |||
305 | bail2: | ||
306 | vq_repbuf_free(c2dev, reply); | ||
307 | bail1: | ||
308 | kfree(wr); | ||
309 | bail0: | ||
310 | vq_req_free(c2dev, vq_req); | ||
311 | return err; | ||
312 | } | ||
313 | |||
314 | int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index) | ||
315 | { | ||
316 | struct c2_vq_req *vq_req; /* verbs request object */ | ||
317 | struct c2wr_stag_dealloc_req wr; /* work request */ | ||
318 | struct c2wr_stag_dealloc_rep *reply; /* WR reply */ | ||
319 | int err; | ||
320 | |||
321 | |||
322 | /* | ||
323 | * allocate verbs request object | ||
324 | */ | ||
325 | vq_req = vq_req_alloc(c2dev); | ||
326 | if (!vq_req) { | ||
327 | return -ENOMEM; | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * Build the WR | ||
332 | */ | ||
333 | c2_wr_set_id(&wr, CCWR_STAG_DEALLOC); | ||
334 | wr.hdr.context = (u64) (unsigned long) vq_req; | ||
335 | wr.rnic_handle = c2dev->adapter_handle; | ||
336 | wr.stag_index = cpu_to_be32(stag_index); | ||
337 | |||
338 | /* | ||
339 | * reference the request struct. dereferenced in the int handler. | ||
340 | */ | ||
341 | vq_req_get(c2dev, vq_req); | ||
342 | |||
343 | /* | ||
344 | * Send WR to adapter | ||
345 | */ | ||
346 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
347 | if (err) { | ||
348 | vq_req_put(c2dev, vq_req); | ||
349 | goto bail0; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Wait for reply from adapter | ||
354 | */ | ||
355 | err = vq_wait_for_reply(c2dev, vq_req); | ||
356 | if (err) { | ||
357 | goto bail0; | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * Process reply | ||
362 | */ | ||
363 | reply = (struct c2wr_stag_dealloc_rep *) (unsigned long) vq_req->reply_msg; | ||
364 | if (!reply) { | ||
365 | err = -ENOMEM; | ||
366 | goto bail0; | ||
367 | } | ||
368 | |||
369 | err = c2_errno(reply); | ||
370 | |||
371 | vq_repbuf_free(c2dev, reply); | ||
372 | bail0: | ||
373 | vq_req_free(c2dev, vq_req); | ||
374 | return err; | ||
375 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_mq.c b/drivers/infiniband/hw/amso1100/c2_mq.c new file mode 100644 index 000000000000..b88a75592102 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_mq.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #include "c2.h" | ||
34 | #include "c2_mq.h" | ||
35 | |||
36 | void *c2_mq_alloc(struct c2_mq *q) | ||
37 | { | ||
38 | BUG_ON(q->magic != C2_MQ_MAGIC); | ||
39 | BUG_ON(q->type != C2_MQ_ADAPTER_TARGET); | ||
40 | |||
41 | if (c2_mq_full(q)) { | ||
42 | return NULL; | ||
43 | } else { | ||
44 | #ifdef DEBUG | ||
45 | struct c2wr_hdr *m = | ||
46 | (struct c2wr_hdr *) (q->msg_pool.host + q->priv * q->msg_size); | ||
47 | #ifdef CCMSGMAGIC | ||
48 | BUG_ON(m->magic != be32_to_cpu(~CCWR_MAGIC)); | ||
49 | m->magic = cpu_to_be32(CCWR_MAGIC); | ||
50 | #endif | ||
51 | return m; | ||
52 | #else | ||
53 | return q->msg_pool.host + q->priv * q->msg_size; | ||
54 | #endif | ||
55 | } | ||
56 | } | ||
57 | |||
58 | void c2_mq_produce(struct c2_mq *q) | ||
59 | { | ||
60 | BUG_ON(q->magic != C2_MQ_MAGIC); | ||
61 | BUG_ON(q->type != C2_MQ_ADAPTER_TARGET); | ||
62 | |||
63 | if (!c2_mq_full(q)) { | ||
64 | q->priv = (q->priv + 1) % q->q_size; | ||
65 | q->hint_count++; | ||
66 | /* Update peer's offset. */ | ||
67 | __raw_writew(cpu_to_be16(q->priv), &q->peer->shared); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | void *c2_mq_consume(struct c2_mq *q) | ||
72 | { | ||
73 | BUG_ON(q->magic != C2_MQ_MAGIC); | ||
74 | BUG_ON(q->type != C2_MQ_HOST_TARGET); | ||
75 | |||
76 | if (c2_mq_empty(q)) { | ||
77 | return NULL; | ||
78 | } else { | ||
79 | #ifdef DEBUG | ||
80 | struct c2wr_hdr *m = (struct c2wr_hdr *) | ||
81 | (q->msg_pool.host + q->priv * q->msg_size); | ||
82 | #ifdef CCMSGMAGIC | ||
83 | BUG_ON(m->magic != be32_to_cpu(CCWR_MAGIC)); | ||
84 | #endif | ||
85 | return m; | ||
86 | #else | ||
87 | return q->msg_pool.host + q->priv * q->msg_size; | ||
88 | #endif | ||
89 | } | ||
90 | } | ||
91 | |||
92 | void c2_mq_free(struct c2_mq *q) | ||
93 | { | ||
94 | BUG_ON(q->magic != C2_MQ_MAGIC); | ||
95 | BUG_ON(q->type != C2_MQ_HOST_TARGET); | ||
96 | |||
97 | if (!c2_mq_empty(q)) { | ||
98 | |||
99 | #ifdef CCMSGMAGIC | ||
100 | { | ||
101 | struct c2wr_hdr __iomem *m = (struct c2wr_hdr __iomem *) | ||
102 | (q->msg_pool.adapter + q->priv * q->msg_size); | ||
103 | __raw_writel(cpu_to_be32(~CCWR_MAGIC), &m->magic); | ||
104 | } | ||
105 | #endif | ||
106 | q->priv = (q->priv + 1) % q->q_size; | ||
107 | /* Update peer's offset. */ | ||
108 | __raw_writew(cpu_to_be16(q->priv), &q->peer->shared); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | |||
113 | void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count) | ||
114 | { | ||
115 | BUG_ON(q->magic != C2_MQ_MAGIC); | ||
116 | BUG_ON(q->type != C2_MQ_ADAPTER_TARGET); | ||
117 | |||
118 | while (wqe_count--) { | ||
119 | BUG_ON(c2_mq_empty(q)); | ||
120 | *q->shared = cpu_to_be16((be16_to_cpu(*q->shared)+1) % q->q_size); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | #if 0 | ||
125 | u32 c2_mq_count(struct c2_mq *q) | ||
126 | { | ||
127 | s32 count; | ||
128 | |||
129 | if (q->type == C2_MQ_HOST_TARGET) | ||
130 | count = be16_to_cpu(*q->shared) - q->priv; | ||
131 | else | ||
132 | count = q->priv - be16_to_cpu(*q->shared); | ||
133 | |||
134 | if (count < 0) | ||
135 | count += q->q_size; | ||
136 | |||
137 | return (u32) count; | ||
138 | } | ||
139 | #endif /* 0 */ | ||
140 | |||
141 | void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size, | ||
142 | u8 __iomem *pool_start, u16 __iomem *peer, u32 type) | ||
143 | { | ||
144 | BUG_ON(!q->shared); | ||
145 | |||
146 | /* This code assumes the byte swapping has already been done! */ | ||
147 | q->index = index; | ||
148 | q->q_size = q_size; | ||
149 | q->msg_size = msg_size; | ||
150 | q->msg_pool.adapter = pool_start; | ||
151 | q->peer = (struct c2_mq_shared __iomem *) peer; | ||
152 | q->magic = C2_MQ_MAGIC; | ||
153 | q->type = type; | ||
154 | q->priv = 0; | ||
155 | q->hint_count = 0; | ||
156 | return; | ||
157 | } | ||
158 | void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size, | ||
159 | u8 *pool_start, u16 __iomem *peer, u32 type) | ||
160 | { | ||
161 | BUG_ON(!q->shared); | ||
162 | |||
163 | /* This code assumes the byte swapping has already been done! */ | ||
164 | q->index = index; | ||
165 | q->q_size = q_size; | ||
166 | q->msg_size = msg_size; | ||
167 | q->msg_pool.host = pool_start; | ||
168 | q->peer = (struct c2_mq_shared __iomem *) peer; | ||
169 | q->magic = C2_MQ_MAGIC; | ||
170 | q->type = type; | ||
171 | q->priv = 0; | ||
172 | q->hint_count = 0; | ||
173 | return; | ||
174 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_mq.h b/drivers/infiniband/hw/amso1100/c2_mq.h new file mode 100644 index 000000000000..9185bbb21658 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_mq.h | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #ifndef _C2_MQ_H_ | ||
35 | #define _C2_MQ_H_ | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/dma-mapping.h> | ||
38 | #include "c2_wr.h" | ||
39 | |||
40 | enum c2_shared_regs { | ||
41 | |||
42 | C2_SHARED_ARMED = 0x10, | ||
43 | C2_SHARED_NOTIFY = 0x18, | ||
44 | C2_SHARED_SHARED = 0x40, | ||
45 | }; | ||
46 | |||
47 | struct c2_mq_shared { | ||
48 | u16 unused1; | ||
49 | u8 armed; | ||
50 | u8 notification_type; | ||
51 | u32 unused2; | ||
52 | u16 shared; | ||
53 | /* Pad to 64 bytes. */ | ||
54 | u8 pad[64 - sizeof(u16) - 2 * sizeof(u8) - sizeof(u32) - sizeof(u16)]; | ||
55 | }; | ||
56 | |||
57 | enum c2_mq_type { | ||
58 | C2_MQ_HOST_TARGET = 1, | ||
59 | C2_MQ_ADAPTER_TARGET = 2, | ||
60 | }; | ||
61 | |||
62 | /* | ||
63 | * c2_mq_t is for kernel-mode MQs like the VQs Cand the AEQ. | ||
64 | * c2_user_mq_t (which is the same format) is for user-mode MQs... | ||
65 | */ | ||
66 | #define C2_MQ_MAGIC 0x4d512020 /* 'MQ ' */ | ||
67 | struct c2_mq { | ||
68 | u32 magic; | ||
69 | union { | ||
70 | u8 *host; | ||
71 | u8 __iomem *adapter; | ||
72 | } msg_pool; | ||
73 | dma_addr_t host_dma; | ||
74 | DECLARE_PCI_UNMAP_ADDR(mapping); | ||
75 | u16 hint_count; | ||
76 | u16 priv; | ||
77 | struct c2_mq_shared __iomem *peer; | ||
78 | u16 *shared; | ||
79 | dma_addr_t shared_dma; | ||
80 | u32 q_size; | ||
81 | u32 msg_size; | ||
82 | u32 index; | ||
83 | enum c2_mq_type type; | ||
84 | }; | ||
85 | |||
86 | static __inline__ int c2_mq_empty(struct c2_mq *q) | ||
87 | { | ||
88 | return q->priv == be16_to_cpu(*q->shared); | ||
89 | } | ||
90 | |||
91 | static __inline__ int c2_mq_full(struct c2_mq *q) | ||
92 | { | ||
93 | return q->priv == (be16_to_cpu(*q->shared) + q->q_size - 1) % q->q_size; | ||
94 | } | ||
95 | |||
96 | extern void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count); | ||
97 | extern void *c2_mq_alloc(struct c2_mq *q); | ||
98 | extern void c2_mq_produce(struct c2_mq *q); | ||
99 | extern void *c2_mq_consume(struct c2_mq *q); | ||
100 | extern void c2_mq_free(struct c2_mq *q); | ||
101 | extern void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size, | ||
102 | u8 __iomem *pool_start, u16 __iomem *peer, u32 type); | ||
103 | extern void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size, | ||
104 | u8 *pool_start, u16 __iomem *peer, u32 type); | ||
105 | |||
106 | #endif /* _C2_MQ_H_ */ | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_pd.c b/drivers/infiniband/hw/amso1100/c2_pd.c new file mode 100644 index 000000000000..00c709926c8d --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_pd.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * Copyright (c) 2005 Cisco Systems. All rights reserved. | ||
4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | ||
5 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
6 | * | ||
7 | * This software is available to you under a choice of one of two | ||
8 | * licenses. You may choose to be licensed under the terms of the GNU | ||
9 | * General Public License (GPL) Version 2, available from the file | ||
10 | * COPYING in the main directory of this source tree, or the | ||
11 | * OpenIB.org BSD license below: | ||
12 | * | ||
13 | * Redistribution and use in source and binary forms, with or | ||
14 | * without modification, are permitted provided that the following | ||
15 | * conditions are met: | ||
16 | * | ||
17 | * - Redistributions of source code must retain the above | ||
18 | * copyright notice, this list of conditions and the following | ||
19 | * disclaimer. | ||
20 | * | ||
21 | * - Redistributions in binary form must reproduce the above | ||
22 | * copyright notice, this list of conditions and the following | ||
23 | * disclaimer in the documentation and/or other materials | ||
24 | * provided with the distribution. | ||
25 | * | ||
26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
27 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
29 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
30 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
31 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
32 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
33 | * SOFTWARE. | ||
34 | */ | ||
35 | |||
36 | #include <linux/init.h> | ||
37 | #include <linux/errno.h> | ||
38 | |||
39 | #include "c2.h" | ||
40 | #include "c2_provider.h" | ||
41 | |||
42 | int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd) | ||
43 | { | ||
44 | u32 obj; | ||
45 | int ret = 0; | ||
46 | |||
47 | spin_lock(&c2dev->pd_table.lock); | ||
48 | obj = find_next_zero_bit(c2dev->pd_table.table, c2dev->pd_table.max, | ||
49 | c2dev->pd_table.last); | ||
50 | if (obj >= c2dev->pd_table.max) | ||
51 | obj = find_first_zero_bit(c2dev->pd_table.table, | ||
52 | c2dev->pd_table.max); | ||
53 | if (obj < c2dev->pd_table.max) { | ||
54 | pd->pd_id = obj; | ||
55 | __set_bit(obj, c2dev->pd_table.table); | ||
56 | c2dev->pd_table.last = obj+1; | ||
57 | if (c2dev->pd_table.last >= c2dev->pd_table.max) | ||
58 | c2dev->pd_table.last = 0; | ||
59 | } else | ||
60 | ret = -ENOMEM; | ||
61 | spin_unlock(&c2dev->pd_table.lock); | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd) | ||
66 | { | ||
67 | spin_lock(&c2dev->pd_table.lock); | ||
68 | __clear_bit(pd->pd_id, c2dev->pd_table.table); | ||
69 | spin_unlock(&c2dev->pd_table.lock); | ||
70 | } | ||
71 | |||
72 | int __devinit c2_init_pd_table(struct c2_dev *c2dev) | ||
73 | { | ||
74 | |||
75 | c2dev->pd_table.last = 0; | ||
76 | c2dev->pd_table.max = c2dev->props.max_pd; | ||
77 | spin_lock_init(&c2dev->pd_table.lock); | ||
78 | c2dev->pd_table.table = kmalloc(BITS_TO_LONGS(c2dev->props.max_pd) * | ||
79 | sizeof(long), GFP_KERNEL); | ||
80 | if (!c2dev->pd_table.table) | ||
81 | return -ENOMEM; | ||
82 | bitmap_zero(c2dev->pd_table.table, c2dev->props.max_pd); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev) | ||
87 | { | ||
88 | kfree(c2dev->pd_table.table); | ||
89 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c new file mode 100644 index 000000000000..dd6af551108b --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_provider.c | |||
@@ -0,0 +1,870 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/moduleparam.h> | ||
37 | #include <linux/pci.h> | ||
38 | #include <linux/netdevice.h> | ||
39 | #include <linux/etherdevice.h> | ||
40 | #include <linux/inetdevice.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/ethtool.h> | ||
43 | #include <linux/mii.h> | ||
44 | #include <linux/if_vlan.h> | ||
45 | #include <linux/crc32.h> | ||
46 | #include <linux/in.h> | ||
47 | #include <linux/ip.h> | ||
48 | #include <linux/tcp.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/dma-mapping.h> | ||
51 | #include <linux/if_arp.h> | ||
52 | #include <linux/vmalloc.h> | ||
53 | |||
54 | #include <asm/io.h> | ||
55 | #include <asm/irq.h> | ||
56 | #include <asm/byteorder.h> | ||
57 | |||
58 | #include <rdma/ib_smi.h> | ||
59 | #include <rdma/ib_user_verbs.h> | ||
60 | #include "c2.h" | ||
61 | #include "c2_provider.h" | ||
62 | #include "c2_user.h" | ||
63 | |||
64 | static int c2_query_device(struct ib_device *ibdev, | ||
65 | struct ib_device_attr *props) | ||
66 | { | ||
67 | struct c2_dev *c2dev = to_c2dev(ibdev); | ||
68 | |||
69 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
70 | |||
71 | *props = c2dev->props; | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int c2_query_port(struct ib_device *ibdev, | ||
76 | u8 port, struct ib_port_attr *props) | ||
77 | { | ||
78 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
79 | |||
80 | props->max_mtu = IB_MTU_4096; | ||
81 | props->lid = 0; | ||
82 | props->lmc = 0; | ||
83 | props->sm_lid = 0; | ||
84 | props->sm_sl = 0; | ||
85 | props->state = IB_PORT_ACTIVE; | ||
86 | props->phys_state = 0; | ||
87 | props->port_cap_flags = | ||
88 | IB_PORT_CM_SUP | | ||
89 | IB_PORT_REINIT_SUP | | ||
90 | IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP; | ||
91 | props->gid_tbl_len = 1; | ||
92 | props->pkey_tbl_len = 1; | ||
93 | props->qkey_viol_cntr = 0; | ||
94 | props->active_width = 1; | ||
95 | props->active_speed = 1; | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int c2_modify_port(struct ib_device *ibdev, | ||
101 | u8 port, int port_modify_mask, | ||
102 | struct ib_port_modify *props) | ||
103 | { | ||
104 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int c2_query_pkey(struct ib_device *ibdev, | ||
109 | u8 port, u16 index, u16 * pkey) | ||
110 | { | ||
111 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
112 | *pkey = 0; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int c2_query_gid(struct ib_device *ibdev, u8 port, | ||
117 | int index, union ib_gid *gid) | ||
118 | { | ||
119 | struct c2_dev *c2dev = to_c2dev(ibdev); | ||
120 | |||
121 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
122 | memset(&(gid->raw[0]), 0, sizeof(gid->raw)); | ||
123 | memcpy(&(gid->raw[0]), c2dev->pseudo_netdev->dev_addr, 6); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | /* Allocate the user context data structure. This keeps track | ||
129 | * of all objects associated with a particular user-mode client. | ||
130 | */ | ||
131 | static struct ib_ucontext *c2_alloc_ucontext(struct ib_device *ibdev, | ||
132 | struct ib_udata *udata) | ||
133 | { | ||
134 | struct c2_ucontext *context; | ||
135 | |||
136 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
137 | context = kmalloc(sizeof(*context), GFP_KERNEL); | ||
138 | if (!context) | ||
139 | return ERR_PTR(-ENOMEM); | ||
140 | |||
141 | return &context->ibucontext; | ||
142 | } | ||
143 | |||
144 | static int c2_dealloc_ucontext(struct ib_ucontext *context) | ||
145 | { | ||
146 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
147 | kfree(context); | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int c2_mmap_uar(struct ib_ucontext *context, struct vm_area_struct *vma) | ||
152 | { | ||
153 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
154 | return -ENOSYS; | ||
155 | } | ||
156 | |||
157 | static struct ib_pd *c2_alloc_pd(struct ib_device *ibdev, | ||
158 | struct ib_ucontext *context, | ||
159 | struct ib_udata *udata) | ||
160 | { | ||
161 | struct c2_pd *pd; | ||
162 | int err; | ||
163 | |||
164 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
165 | |||
166 | pd = kmalloc(sizeof(*pd), GFP_KERNEL); | ||
167 | if (!pd) | ||
168 | return ERR_PTR(-ENOMEM); | ||
169 | |||
170 | err = c2_pd_alloc(to_c2dev(ibdev), !context, pd); | ||
171 | if (err) { | ||
172 | kfree(pd); | ||
173 | return ERR_PTR(err); | ||
174 | } | ||
175 | |||
176 | if (context) { | ||
177 | if (ib_copy_to_udata(udata, &pd->pd_id, sizeof(__u32))) { | ||
178 | c2_pd_free(to_c2dev(ibdev), pd); | ||
179 | kfree(pd); | ||
180 | return ERR_PTR(-EFAULT); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | return &pd->ibpd; | ||
185 | } | ||
186 | |||
187 | static int c2_dealloc_pd(struct ib_pd *pd) | ||
188 | { | ||
189 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
190 | c2_pd_free(to_c2dev(pd->device), to_c2pd(pd)); | ||
191 | kfree(pd); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static struct ib_ah *c2_ah_create(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | ||
197 | { | ||
198 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
199 | return ERR_PTR(-ENOSYS); | ||
200 | } | ||
201 | |||
202 | static int c2_ah_destroy(struct ib_ah *ah) | ||
203 | { | ||
204 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
205 | return -ENOSYS; | ||
206 | } | ||
207 | |||
208 | static void c2_add_ref(struct ib_qp *ibqp) | ||
209 | { | ||
210 | struct c2_qp *qp; | ||
211 | BUG_ON(!ibqp); | ||
212 | qp = to_c2qp(ibqp); | ||
213 | atomic_inc(&qp->refcount); | ||
214 | } | ||
215 | |||
216 | static void c2_rem_ref(struct ib_qp *ibqp) | ||
217 | { | ||
218 | struct c2_qp *qp; | ||
219 | BUG_ON(!ibqp); | ||
220 | qp = to_c2qp(ibqp); | ||
221 | if (atomic_dec_and_test(&qp->refcount)) | ||
222 | wake_up(&qp->wait); | ||
223 | } | ||
224 | |||
225 | struct ib_qp *c2_get_qp(struct ib_device *device, int qpn) | ||
226 | { | ||
227 | struct c2_dev* c2dev = to_c2dev(device); | ||
228 | struct c2_qp *qp; | ||
229 | |||
230 | qp = c2_find_qpn(c2dev, qpn); | ||
231 | pr_debug("%s Returning QP=%p for QPN=%d, device=%p, refcount=%d\n", | ||
232 | __FUNCTION__, qp, qpn, device, | ||
233 | (qp?atomic_read(&qp->refcount):0)); | ||
234 | |||
235 | return (qp?&qp->ibqp:NULL); | ||
236 | } | ||
237 | |||
238 | static struct ib_qp *c2_create_qp(struct ib_pd *pd, | ||
239 | struct ib_qp_init_attr *init_attr, | ||
240 | struct ib_udata *udata) | ||
241 | { | ||
242 | struct c2_qp *qp; | ||
243 | int err; | ||
244 | |||
245 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
246 | |||
247 | switch (init_attr->qp_type) { | ||
248 | case IB_QPT_RC: | ||
249 | qp = kzalloc(sizeof(*qp), GFP_KERNEL); | ||
250 | if (!qp) { | ||
251 | pr_debug("%s: Unable to allocate QP\n", __FUNCTION__); | ||
252 | return ERR_PTR(-ENOMEM); | ||
253 | } | ||
254 | spin_lock_init(&qp->lock); | ||
255 | if (pd->uobject) { | ||
256 | /* userspace specific */ | ||
257 | } | ||
258 | |||
259 | err = c2_alloc_qp(to_c2dev(pd->device), | ||
260 | to_c2pd(pd), init_attr, qp); | ||
261 | |||
262 | if (err && pd->uobject) { | ||
263 | /* userspace specific */ | ||
264 | } | ||
265 | |||
266 | break; | ||
267 | default: | ||
268 | pr_debug("%s: Invalid QP type: %d\n", __FUNCTION__, | ||
269 | init_attr->qp_type); | ||
270 | return ERR_PTR(-EINVAL); | ||
271 | break; | ||
272 | } | ||
273 | |||
274 | if (err) { | ||
275 | kfree(qp); | ||
276 | return ERR_PTR(err); | ||
277 | } | ||
278 | |||
279 | return &qp->ibqp; | ||
280 | } | ||
281 | |||
282 | static int c2_destroy_qp(struct ib_qp *ib_qp) | ||
283 | { | ||
284 | struct c2_qp *qp = to_c2qp(ib_qp); | ||
285 | |||
286 | pr_debug("%s:%u qp=%p,qp->state=%d\n", | ||
287 | __FUNCTION__, __LINE__,ib_qp,qp->state); | ||
288 | c2_free_qp(to_c2dev(ib_qp->device), qp); | ||
289 | kfree(qp); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries, | ||
294 | struct ib_ucontext *context, | ||
295 | struct ib_udata *udata) | ||
296 | { | ||
297 | struct c2_cq *cq; | ||
298 | int err; | ||
299 | |||
300 | cq = kmalloc(sizeof(*cq), GFP_KERNEL); | ||
301 | if (!cq) { | ||
302 | pr_debug("%s: Unable to allocate CQ\n", __FUNCTION__); | ||
303 | return ERR_PTR(-ENOMEM); | ||
304 | } | ||
305 | |||
306 | err = c2_init_cq(to_c2dev(ibdev), entries, NULL, cq); | ||
307 | if (err) { | ||
308 | pr_debug("%s: error initializing CQ\n", __FUNCTION__); | ||
309 | kfree(cq); | ||
310 | return ERR_PTR(err); | ||
311 | } | ||
312 | |||
313 | return &cq->ibcq; | ||
314 | } | ||
315 | |||
316 | static int c2_destroy_cq(struct ib_cq *ib_cq) | ||
317 | { | ||
318 | struct c2_cq *cq = to_c2cq(ib_cq); | ||
319 | |||
320 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
321 | |||
322 | c2_free_cq(to_c2dev(ib_cq->device), cq); | ||
323 | kfree(cq); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static inline u32 c2_convert_access(int acc) | ||
329 | { | ||
330 | return (acc & IB_ACCESS_REMOTE_WRITE ? C2_ACF_REMOTE_WRITE : 0) | | ||
331 | (acc & IB_ACCESS_REMOTE_READ ? C2_ACF_REMOTE_READ : 0) | | ||
332 | (acc & IB_ACCESS_LOCAL_WRITE ? C2_ACF_LOCAL_WRITE : 0) | | ||
333 | C2_ACF_LOCAL_READ | C2_ACF_WINDOW_BIND; | ||
334 | } | ||
335 | |||
336 | static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd, | ||
337 | struct ib_phys_buf *buffer_list, | ||
338 | int num_phys_buf, int acc, u64 * iova_start) | ||
339 | { | ||
340 | struct c2_mr *mr; | ||
341 | u64 *page_list; | ||
342 | u32 total_len; | ||
343 | int err, i, j, k, page_shift, pbl_depth; | ||
344 | |||
345 | pbl_depth = 0; | ||
346 | total_len = 0; | ||
347 | |||
348 | page_shift = PAGE_SHIFT; | ||
349 | /* | ||
350 | * If there is only 1 buffer we assume this could | ||
351 | * be a map of all phy mem...use a 32k page_shift. | ||
352 | */ | ||
353 | if (num_phys_buf == 1) | ||
354 | page_shift += 3; | ||
355 | |||
356 | for (i = 0; i < num_phys_buf; i++) { | ||
357 | |||
358 | if (buffer_list[i].addr & ~PAGE_MASK) { | ||
359 | pr_debug("Unaligned Memory Buffer: 0x%x\n", | ||
360 | (unsigned int) buffer_list[i].addr); | ||
361 | return ERR_PTR(-EINVAL); | ||
362 | } | ||
363 | |||
364 | if (!buffer_list[i].size) { | ||
365 | pr_debug("Invalid Buffer Size\n"); | ||
366 | return ERR_PTR(-EINVAL); | ||
367 | } | ||
368 | |||
369 | total_len += buffer_list[i].size; | ||
370 | pbl_depth += ALIGN(buffer_list[i].size, | ||
371 | (1 << page_shift)) >> page_shift; | ||
372 | } | ||
373 | |||
374 | page_list = vmalloc(sizeof(u64) * pbl_depth); | ||
375 | if (!page_list) { | ||
376 | pr_debug("couldn't vmalloc page_list of size %zd\n", | ||
377 | (sizeof(u64) * pbl_depth)); | ||
378 | return ERR_PTR(-ENOMEM); | ||
379 | } | ||
380 | |||
381 | for (i = 0, j = 0; i < num_phys_buf; i++) { | ||
382 | |||
383 | int naddrs; | ||
384 | |||
385 | naddrs = ALIGN(buffer_list[i].size, | ||
386 | (1 << page_shift)) >> page_shift; | ||
387 | for (k = 0; k < naddrs; k++) | ||
388 | page_list[j++] = (buffer_list[i].addr + | ||
389 | (k << page_shift)); | ||
390 | } | ||
391 | |||
392 | mr = kmalloc(sizeof(*mr), GFP_KERNEL); | ||
393 | if (!mr) | ||
394 | return ERR_PTR(-ENOMEM); | ||
395 | |||
396 | mr->pd = to_c2pd(ib_pd); | ||
397 | pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, " | ||
398 | "*iova_start %llx, first pa %llx, last pa %llx\n", | ||
399 | __FUNCTION__, page_shift, pbl_depth, total_len, | ||
400 | *iova_start, page_list[0], page_list[pbl_depth-1]); | ||
401 | err = c2_nsmr_register_phys_kern(to_c2dev(ib_pd->device), page_list, | ||
402 | (1 << page_shift), pbl_depth, | ||
403 | total_len, 0, iova_start, | ||
404 | c2_convert_access(acc), mr); | ||
405 | vfree(page_list); | ||
406 | if (err) { | ||
407 | kfree(mr); | ||
408 | return ERR_PTR(err); | ||
409 | } | ||
410 | |||
411 | return &mr->ibmr; | ||
412 | } | ||
413 | |||
414 | static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc) | ||
415 | { | ||
416 | struct ib_phys_buf bl; | ||
417 | u64 kva = 0; | ||
418 | |||
419 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
420 | |||
421 | /* AMSO1100 limit */ | ||
422 | bl.size = 0xffffffff; | ||
423 | bl.addr = 0; | ||
424 | return c2_reg_phys_mr(pd, &bl, 1, acc, &kva); | ||
425 | } | ||
426 | |||
427 | static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, | ||
428 | int acc, struct ib_udata *udata) | ||
429 | { | ||
430 | u64 *pages; | ||
431 | u64 kva = 0; | ||
432 | int shift, n, len; | ||
433 | int i, j, k; | ||
434 | int err = 0; | ||
435 | struct ib_umem_chunk *chunk; | ||
436 | struct c2_pd *c2pd = to_c2pd(pd); | ||
437 | struct c2_mr *c2mr; | ||
438 | |||
439 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
440 | shift = ffs(region->page_size) - 1; | ||
441 | |||
442 | c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL); | ||
443 | if (!c2mr) | ||
444 | return ERR_PTR(-ENOMEM); | ||
445 | c2mr->pd = c2pd; | ||
446 | |||
447 | n = 0; | ||
448 | list_for_each_entry(chunk, ®ion->chunk_list, list) | ||
449 | n += chunk->nents; | ||
450 | |||
451 | pages = kmalloc(n * sizeof(u64), GFP_KERNEL); | ||
452 | if (!pages) { | ||
453 | err = -ENOMEM; | ||
454 | goto err; | ||
455 | } | ||
456 | |||
457 | i = 0; | ||
458 | list_for_each_entry(chunk, ®ion->chunk_list, list) { | ||
459 | for (j = 0; j < chunk->nmap; ++j) { | ||
460 | len = sg_dma_len(&chunk->page_list[j]) >> shift; | ||
461 | for (k = 0; k < len; ++k) { | ||
462 | pages[i++] = | ||
463 | sg_dma_address(&chunk->page_list[j]) + | ||
464 | (region->page_size * k); | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | |||
469 | kva = (u64)region->virt_base; | ||
470 | err = c2_nsmr_register_phys_kern(to_c2dev(pd->device), | ||
471 | pages, | ||
472 | region->page_size, | ||
473 | i, | ||
474 | region->length, | ||
475 | region->offset, | ||
476 | &kva, | ||
477 | c2_convert_access(acc), | ||
478 | c2mr); | ||
479 | kfree(pages); | ||
480 | if (err) { | ||
481 | kfree(c2mr); | ||
482 | return ERR_PTR(err); | ||
483 | } | ||
484 | return &c2mr->ibmr; | ||
485 | |||
486 | err: | ||
487 | kfree(c2mr); | ||
488 | return ERR_PTR(err); | ||
489 | } | ||
490 | |||
491 | static int c2_dereg_mr(struct ib_mr *ib_mr) | ||
492 | { | ||
493 | struct c2_mr *mr = to_c2mr(ib_mr); | ||
494 | int err; | ||
495 | |||
496 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
497 | |||
498 | err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey); | ||
499 | if (err) | ||
500 | pr_debug("c2_stag_dealloc failed: %d\n", err); | ||
501 | else | ||
502 | kfree(mr); | ||
503 | |||
504 | return err; | ||
505 | } | ||
506 | |||
507 | static ssize_t show_rev(struct class_device *cdev, char *buf) | ||
508 | { | ||
509 | struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev); | ||
510 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
511 | return sprintf(buf, "%x\n", dev->props.hw_ver); | ||
512 | } | ||
513 | |||
514 | static ssize_t show_fw_ver(struct class_device *cdev, char *buf) | ||
515 | { | ||
516 | struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev); | ||
517 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
518 | return sprintf(buf, "%x.%x.%x\n", | ||
519 | (int) (dev->props.fw_ver >> 32), | ||
520 | (int) (dev->props.fw_ver >> 16) & 0xffff, | ||
521 | (int) (dev->props.fw_ver & 0xffff)); | ||
522 | } | ||
523 | |||
524 | static ssize_t show_hca(struct class_device *cdev, char *buf) | ||
525 | { | ||
526 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
527 | return sprintf(buf, "AMSO1100\n"); | ||
528 | } | ||
529 | |||
530 | static ssize_t show_board(struct class_device *cdev, char *buf) | ||
531 | { | ||
532 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
533 | return sprintf(buf, "%.*s\n", 32, "AMSO1100 Board ID"); | ||
534 | } | ||
535 | |||
536 | static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); | ||
537 | static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); | ||
538 | static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); | ||
539 | static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); | ||
540 | |||
541 | static struct class_device_attribute *c2_class_attributes[] = { | ||
542 | &class_device_attr_hw_rev, | ||
543 | &class_device_attr_fw_ver, | ||
544 | &class_device_attr_hca_type, | ||
545 | &class_device_attr_board_id | ||
546 | }; | ||
547 | |||
548 | static int c2_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | ||
549 | int attr_mask, struct ib_udata *udata) | ||
550 | { | ||
551 | int err; | ||
552 | |||
553 | err = | ||
554 | c2_qp_modify(to_c2dev(ibqp->device), to_c2qp(ibqp), attr, | ||
555 | attr_mask); | ||
556 | |||
557 | return err; | ||
558 | } | ||
559 | |||
560 | static int c2_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
561 | { | ||
562 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
563 | return -ENOSYS; | ||
564 | } | ||
565 | |||
566 | static int c2_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
567 | { | ||
568 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
569 | return -ENOSYS; | ||
570 | } | ||
571 | |||
572 | static int c2_process_mad(struct ib_device *ibdev, | ||
573 | int mad_flags, | ||
574 | u8 port_num, | ||
575 | struct ib_wc *in_wc, | ||
576 | struct ib_grh *in_grh, | ||
577 | struct ib_mad *in_mad, struct ib_mad *out_mad) | ||
578 | { | ||
579 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
580 | return -ENOSYS; | ||
581 | } | ||
582 | |||
583 | static int c2_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param) | ||
584 | { | ||
585 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
586 | |||
587 | /* Request a connection */ | ||
588 | return c2_llp_connect(cm_id, iw_param); | ||
589 | } | ||
590 | |||
591 | static int c2_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param) | ||
592 | { | ||
593 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
594 | |||
595 | /* Accept the new connection */ | ||
596 | return c2_llp_accept(cm_id, iw_param); | ||
597 | } | ||
598 | |||
599 | static int c2_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) | ||
600 | { | ||
601 | int err; | ||
602 | |||
603 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
604 | |||
605 | err = c2_llp_reject(cm_id, pdata, pdata_len); | ||
606 | return err; | ||
607 | } | ||
608 | |||
609 | static int c2_service_create(struct iw_cm_id *cm_id, int backlog) | ||
610 | { | ||
611 | int err; | ||
612 | |||
613 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
614 | err = c2_llp_service_create(cm_id, backlog); | ||
615 | pr_debug("%s:%u err=%d\n", | ||
616 | __FUNCTION__, __LINE__, | ||
617 | err); | ||
618 | return err; | ||
619 | } | ||
620 | |||
621 | static int c2_service_destroy(struct iw_cm_id *cm_id) | ||
622 | { | ||
623 | int err; | ||
624 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
625 | |||
626 | err = c2_llp_service_destroy(cm_id); | ||
627 | |||
628 | return err; | ||
629 | } | ||
630 | |||
631 | static int c2_pseudo_up(struct net_device *netdev) | ||
632 | { | ||
633 | struct in_device *ind; | ||
634 | struct c2_dev *c2dev = netdev->priv; | ||
635 | |||
636 | ind = in_dev_get(netdev); | ||
637 | if (!ind) | ||
638 | return 0; | ||
639 | |||
640 | pr_debug("adding...\n"); | ||
641 | for_ifa(ind) { | ||
642 | #ifdef DEBUG | ||
643 | u8 *ip = (u8 *) & ifa->ifa_address; | ||
644 | |||
645 | pr_debug("%s: %d.%d.%d.%d\n", | ||
646 | ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]); | ||
647 | #endif | ||
648 | c2_add_addr(c2dev, ifa->ifa_address, ifa->ifa_mask); | ||
649 | } | ||
650 | endfor_ifa(ind); | ||
651 | in_dev_put(ind); | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static int c2_pseudo_down(struct net_device *netdev) | ||
657 | { | ||
658 | struct in_device *ind; | ||
659 | struct c2_dev *c2dev = netdev->priv; | ||
660 | |||
661 | ind = in_dev_get(netdev); | ||
662 | if (!ind) | ||
663 | return 0; | ||
664 | |||
665 | pr_debug("deleting...\n"); | ||
666 | for_ifa(ind) { | ||
667 | #ifdef DEBUG | ||
668 | u8 *ip = (u8 *) & ifa->ifa_address; | ||
669 | |||
670 | pr_debug("%s: %d.%d.%d.%d\n", | ||
671 | ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]); | ||
672 | #endif | ||
673 | c2_del_addr(c2dev, ifa->ifa_address, ifa->ifa_mask); | ||
674 | } | ||
675 | endfor_ifa(ind); | ||
676 | in_dev_put(ind); | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static int c2_pseudo_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | ||
682 | { | ||
683 | kfree_skb(skb); | ||
684 | return NETDEV_TX_OK; | ||
685 | } | ||
686 | |||
687 | static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu) | ||
688 | { | ||
689 | int ret = 0; | ||
690 | |||
691 | if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) | ||
692 | return -EINVAL; | ||
693 | |||
694 | netdev->mtu = new_mtu; | ||
695 | |||
696 | /* TODO: Tell rnic about new rmda interface mtu */ | ||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | static void setup(struct net_device *netdev) | ||
701 | { | ||
702 | SET_MODULE_OWNER(netdev); | ||
703 | netdev->open = c2_pseudo_up; | ||
704 | netdev->stop = c2_pseudo_down; | ||
705 | netdev->hard_start_xmit = c2_pseudo_xmit_frame; | ||
706 | netdev->get_stats = NULL; | ||
707 | netdev->tx_timeout = NULL; | ||
708 | netdev->set_mac_address = NULL; | ||
709 | netdev->change_mtu = c2_pseudo_change_mtu; | ||
710 | netdev->watchdog_timeo = 0; | ||
711 | netdev->type = ARPHRD_ETHER; | ||
712 | netdev->mtu = 1500; | ||
713 | netdev->hard_header_len = ETH_HLEN; | ||
714 | netdev->addr_len = ETH_ALEN; | ||
715 | netdev->tx_queue_len = 0; | ||
716 | netdev->flags |= IFF_NOARP; | ||
717 | return; | ||
718 | } | ||
719 | |||
720 | static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev) | ||
721 | { | ||
722 | char name[IFNAMSIZ]; | ||
723 | struct net_device *netdev; | ||
724 | |||
725 | /* change ethxxx to iwxxx */ | ||
726 | strcpy(name, "iw"); | ||
727 | strcat(name, &c2dev->netdev->name[3]); | ||
728 | netdev = alloc_netdev(sizeof(*netdev), name, setup); | ||
729 | if (!netdev) { | ||
730 | printk(KERN_ERR PFX "%s - etherdev alloc failed", | ||
731 | __FUNCTION__); | ||
732 | return NULL; | ||
733 | } | ||
734 | |||
735 | netdev->priv = c2dev; | ||
736 | |||
737 | SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev); | ||
738 | |||
739 | memcpy_fromio(netdev->dev_addr, c2dev->kva + C2_REGS_RDMA_ENADDR, 6); | ||
740 | |||
741 | /* Print out the MAC address */ | ||
742 | pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X\n", | ||
743 | netdev->name, | ||
744 | netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], | ||
745 | netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); | ||
746 | |||
747 | #if 0 | ||
748 | /* Disable network packets */ | ||
749 | netif_stop_queue(netdev); | ||
750 | #endif | ||
751 | return netdev; | ||
752 | } | ||
753 | |||
754 | int c2_register_device(struct c2_dev *dev) | ||
755 | { | ||
756 | int ret; | ||
757 | int i; | ||
758 | |||
759 | /* Register pseudo network device */ | ||
760 | dev->pseudo_netdev = c2_pseudo_netdev_init(dev); | ||
761 | if (dev->pseudo_netdev) { | ||
762 | ret = register_netdev(dev->pseudo_netdev); | ||
763 | if (ret) { | ||
764 | printk(KERN_ERR PFX | ||
765 | "Unable to register netdev, ret = %d\n", ret); | ||
766 | free_netdev(dev->pseudo_netdev); | ||
767 | return ret; | ||
768 | } | ||
769 | } | ||
770 | |||
771 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
772 | strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX); | ||
773 | dev->ibdev.owner = THIS_MODULE; | ||
774 | dev->ibdev.uverbs_cmd_mask = | ||
775 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | | ||
776 | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | | ||
777 | (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | | ||
778 | (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | | ||
779 | (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | | ||
780 | (1ull << IB_USER_VERBS_CMD_REG_MR) | | ||
781 | (1ull << IB_USER_VERBS_CMD_DEREG_MR) | | ||
782 | (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | | ||
783 | (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | | ||
784 | (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | | ||
785 | (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) | | ||
786 | (1ull << IB_USER_VERBS_CMD_CREATE_QP) | | ||
787 | (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | | ||
788 | (1ull << IB_USER_VERBS_CMD_POLL_CQ) | | ||
789 | (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | | ||
790 | (1ull << IB_USER_VERBS_CMD_POST_SEND) | | ||
791 | (1ull << IB_USER_VERBS_CMD_POST_RECV); | ||
792 | |||
793 | dev->ibdev.node_type = RDMA_NODE_RNIC; | ||
794 | memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); | ||
795 | memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6); | ||
796 | dev->ibdev.phys_port_cnt = 1; | ||
797 | dev->ibdev.dma_device = &dev->pcidev->dev; | ||
798 | dev->ibdev.class_dev.dev = &dev->pcidev->dev; | ||
799 | dev->ibdev.query_device = c2_query_device; | ||
800 | dev->ibdev.query_port = c2_query_port; | ||
801 | dev->ibdev.modify_port = c2_modify_port; | ||
802 | dev->ibdev.query_pkey = c2_query_pkey; | ||
803 | dev->ibdev.query_gid = c2_query_gid; | ||
804 | dev->ibdev.alloc_ucontext = c2_alloc_ucontext; | ||
805 | dev->ibdev.dealloc_ucontext = c2_dealloc_ucontext; | ||
806 | dev->ibdev.mmap = c2_mmap_uar; | ||
807 | dev->ibdev.alloc_pd = c2_alloc_pd; | ||
808 | dev->ibdev.dealloc_pd = c2_dealloc_pd; | ||
809 | dev->ibdev.create_ah = c2_ah_create; | ||
810 | dev->ibdev.destroy_ah = c2_ah_destroy; | ||
811 | dev->ibdev.create_qp = c2_create_qp; | ||
812 | dev->ibdev.modify_qp = c2_modify_qp; | ||
813 | dev->ibdev.destroy_qp = c2_destroy_qp; | ||
814 | dev->ibdev.create_cq = c2_create_cq; | ||
815 | dev->ibdev.destroy_cq = c2_destroy_cq; | ||
816 | dev->ibdev.poll_cq = c2_poll_cq; | ||
817 | dev->ibdev.get_dma_mr = c2_get_dma_mr; | ||
818 | dev->ibdev.reg_phys_mr = c2_reg_phys_mr; | ||
819 | dev->ibdev.reg_user_mr = c2_reg_user_mr; | ||
820 | dev->ibdev.dereg_mr = c2_dereg_mr; | ||
821 | |||
822 | dev->ibdev.alloc_fmr = NULL; | ||
823 | dev->ibdev.unmap_fmr = NULL; | ||
824 | dev->ibdev.dealloc_fmr = NULL; | ||
825 | dev->ibdev.map_phys_fmr = NULL; | ||
826 | |||
827 | dev->ibdev.attach_mcast = c2_multicast_attach; | ||
828 | dev->ibdev.detach_mcast = c2_multicast_detach; | ||
829 | dev->ibdev.process_mad = c2_process_mad; | ||
830 | |||
831 | dev->ibdev.req_notify_cq = c2_arm_cq; | ||
832 | dev->ibdev.post_send = c2_post_send; | ||
833 | dev->ibdev.post_recv = c2_post_receive; | ||
834 | |||
835 | dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL); | ||
836 | dev->ibdev.iwcm->add_ref = c2_add_ref; | ||
837 | dev->ibdev.iwcm->rem_ref = c2_rem_ref; | ||
838 | dev->ibdev.iwcm->get_qp = c2_get_qp; | ||
839 | dev->ibdev.iwcm->connect = c2_connect; | ||
840 | dev->ibdev.iwcm->accept = c2_accept; | ||
841 | dev->ibdev.iwcm->reject = c2_reject; | ||
842 | dev->ibdev.iwcm->create_listen = c2_service_create; | ||
843 | dev->ibdev.iwcm->destroy_listen = c2_service_destroy; | ||
844 | |||
845 | ret = ib_register_device(&dev->ibdev); | ||
846 | if (ret) | ||
847 | return ret; | ||
848 | |||
849 | for (i = 0; i < ARRAY_SIZE(c2_class_attributes); ++i) { | ||
850 | ret = class_device_create_file(&dev->ibdev.class_dev, | ||
851 | c2_class_attributes[i]); | ||
852 | if (ret) { | ||
853 | unregister_netdev(dev->pseudo_netdev); | ||
854 | free_netdev(dev->pseudo_netdev); | ||
855 | ib_unregister_device(&dev->ibdev); | ||
856 | return ret; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | void c2_unregister_device(struct c2_dev *dev) | ||
865 | { | ||
866 | pr_debug("%s:%u\n", __FUNCTION__, __LINE__); | ||
867 | unregister_netdev(dev->pseudo_netdev); | ||
868 | free_netdev(dev->pseudo_netdev); | ||
869 | ib_unregister_device(&dev->ibdev); | ||
870 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.h b/drivers/infiniband/hw/amso1100/c2_provider.h new file mode 100644 index 000000000000..fc906223220f --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_provider.h | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #ifndef C2_PROVIDER_H | ||
36 | #define C2_PROVIDER_H | ||
37 | #include <linux/inetdevice.h> | ||
38 | |||
39 | #include <rdma/ib_verbs.h> | ||
40 | #include <rdma/ib_pack.h> | ||
41 | |||
42 | #include "c2_mq.h" | ||
43 | #include <rdma/iw_cm.h> | ||
44 | |||
45 | #define C2_MPT_FLAG_ATOMIC (1 << 14) | ||
46 | #define C2_MPT_FLAG_REMOTE_WRITE (1 << 13) | ||
47 | #define C2_MPT_FLAG_REMOTE_READ (1 << 12) | ||
48 | #define C2_MPT_FLAG_LOCAL_WRITE (1 << 11) | ||
49 | #define C2_MPT_FLAG_LOCAL_READ (1 << 10) | ||
50 | |||
51 | struct c2_buf_list { | ||
52 | void *buf; | ||
53 | DECLARE_PCI_UNMAP_ADDR(mapping) | ||
54 | }; | ||
55 | |||
56 | |||
57 | /* The user context keeps track of objects allocated for a | ||
58 | * particular user-mode client. */ | ||
59 | struct c2_ucontext { | ||
60 | struct ib_ucontext ibucontext; | ||
61 | }; | ||
62 | |||
63 | struct c2_mtt; | ||
64 | |||
65 | /* All objects associated with a PD are kept in the | ||
66 | * associated user context if present. | ||
67 | */ | ||
68 | struct c2_pd { | ||
69 | struct ib_pd ibpd; | ||
70 | u32 pd_id; | ||
71 | }; | ||
72 | |||
73 | struct c2_mr { | ||
74 | struct ib_mr ibmr; | ||
75 | struct c2_pd *pd; | ||
76 | }; | ||
77 | |||
78 | struct c2_av; | ||
79 | |||
80 | enum c2_ah_type { | ||
81 | C2_AH_ON_HCA, | ||
82 | C2_AH_PCI_POOL, | ||
83 | C2_AH_KMALLOC | ||
84 | }; | ||
85 | |||
86 | struct c2_ah { | ||
87 | struct ib_ah ibah; | ||
88 | }; | ||
89 | |||
90 | struct c2_cq { | ||
91 | struct ib_cq ibcq; | ||
92 | spinlock_t lock; | ||
93 | atomic_t refcount; | ||
94 | int cqn; | ||
95 | int is_kernel; | ||
96 | wait_queue_head_t wait; | ||
97 | |||
98 | u32 adapter_handle; | ||
99 | struct c2_mq mq; | ||
100 | }; | ||
101 | |||
102 | struct c2_wq { | ||
103 | spinlock_t lock; | ||
104 | }; | ||
105 | struct iw_cm_id; | ||
106 | struct c2_qp { | ||
107 | struct ib_qp ibqp; | ||
108 | struct iw_cm_id *cm_id; | ||
109 | spinlock_t lock; | ||
110 | atomic_t refcount; | ||
111 | wait_queue_head_t wait; | ||
112 | int qpn; | ||
113 | |||
114 | u32 adapter_handle; | ||
115 | u32 send_sgl_depth; | ||
116 | u32 recv_sgl_depth; | ||
117 | u32 rdma_write_sgl_depth; | ||
118 | u8 state; | ||
119 | |||
120 | struct c2_mq sq_mq; | ||
121 | struct c2_mq rq_mq; | ||
122 | }; | ||
123 | |||
124 | struct c2_cr_query_attrs { | ||
125 | u32 local_addr; | ||
126 | u32 remote_addr; | ||
127 | u16 local_port; | ||
128 | u16 remote_port; | ||
129 | }; | ||
130 | |||
131 | static inline struct c2_pd *to_c2pd(struct ib_pd *ibpd) | ||
132 | { | ||
133 | return container_of(ibpd, struct c2_pd, ibpd); | ||
134 | } | ||
135 | |||
136 | static inline struct c2_ucontext *to_c2ucontext(struct ib_ucontext *ibucontext) | ||
137 | { | ||
138 | return container_of(ibucontext, struct c2_ucontext, ibucontext); | ||
139 | } | ||
140 | |||
141 | static inline struct c2_mr *to_c2mr(struct ib_mr *ibmr) | ||
142 | { | ||
143 | return container_of(ibmr, struct c2_mr, ibmr); | ||
144 | } | ||
145 | |||
146 | |||
147 | static inline struct c2_ah *to_c2ah(struct ib_ah *ibah) | ||
148 | { | ||
149 | return container_of(ibah, struct c2_ah, ibah); | ||
150 | } | ||
151 | |||
152 | static inline struct c2_cq *to_c2cq(struct ib_cq *ibcq) | ||
153 | { | ||
154 | return container_of(ibcq, struct c2_cq, ibcq); | ||
155 | } | ||
156 | |||
157 | static inline struct c2_qp *to_c2qp(struct ib_qp *ibqp) | ||
158 | { | ||
159 | return container_of(ibqp, struct c2_qp, ibqp); | ||
160 | } | ||
161 | |||
162 | static inline int is_rnic_addr(struct net_device *netdev, u32 addr) | ||
163 | { | ||
164 | struct in_device *ind; | ||
165 | int ret = 0; | ||
166 | |||
167 | ind = in_dev_get(netdev); | ||
168 | if (!ind) | ||
169 | return 0; | ||
170 | |||
171 | for_ifa(ind) { | ||
172 | if (ifa->ifa_address == addr) { | ||
173 | ret = 1; | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | endfor_ifa(ind); | ||
178 | in_dev_put(ind); | ||
179 | return ret; | ||
180 | } | ||
181 | #endif /* C2_PROVIDER_H */ | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c new file mode 100644 index 000000000000..12261132b077 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_qp.c | |||
@@ -0,0 +1,975 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * Copyright (c) 2005 Cisco Systems. All rights reserved. | ||
4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | ||
5 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. | ||
6 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
7 | * | ||
8 | * This software is available to you under a choice of one of two | ||
9 | * licenses. You may choose to be licensed under the terms of the GNU | ||
10 | * General Public License (GPL) Version 2, available from the file | ||
11 | * COPYING in the main directory of this source tree, or the | ||
12 | * OpenIB.org BSD license below: | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or | ||
15 | * without modification, are permitted provided that the following | ||
16 | * conditions are met: | ||
17 | * | ||
18 | * - Redistributions of source code must retain the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer. | ||
21 | * | ||
22 | * - Redistributions in binary form must reproduce the above | ||
23 | * copyright notice, this list of conditions and the following | ||
24 | * disclaimer in the documentation and/or other materials | ||
25 | * provided with the distribution. | ||
26 | * | ||
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
34 | * SOFTWARE. | ||
35 | * | ||
36 | */ | ||
37 | |||
38 | #include "c2.h" | ||
39 | #include "c2_vq.h" | ||
40 | #include "c2_status.h" | ||
41 | |||
42 | #define C2_MAX_ORD_PER_QP 128 | ||
43 | #define C2_MAX_IRD_PER_QP 128 | ||
44 | |||
45 | #define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count) | ||
46 | #define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16) | ||
47 | #define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF) | ||
48 | |||
49 | #define NO_SUPPORT -1 | ||
50 | static const u8 c2_opcode[] = { | ||
51 | [IB_WR_SEND] = C2_WR_TYPE_SEND, | ||
52 | [IB_WR_SEND_WITH_IMM] = NO_SUPPORT, | ||
53 | [IB_WR_RDMA_WRITE] = C2_WR_TYPE_RDMA_WRITE, | ||
54 | [IB_WR_RDMA_WRITE_WITH_IMM] = NO_SUPPORT, | ||
55 | [IB_WR_RDMA_READ] = C2_WR_TYPE_RDMA_READ, | ||
56 | [IB_WR_ATOMIC_CMP_AND_SWP] = NO_SUPPORT, | ||
57 | [IB_WR_ATOMIC_FETCH_AND_ADD] = NO_SUPPORT, | ||
58 | }; | ||
59 | |||
60 | static int to_c2_state(enum ib_qp_state ib_state) | ||
61 | { | ||
62 | switch (ib_state) { | ||
63 | case IB_QPS_RESET: | ||
64 | return C2_QP_STATE_IDLE; | ||
65 | case IB_QPS_RTS: | ||
66 | return C2_QP_STATE_RTS; | ||
67 | case IB_QPS_SQD: | ||
68 | return C2_QP_STATE_CLOSING; | ||
69 | case IB_QPS_SQE: | ||
70 | return C2_QP_STATE_CLOSING; | ||
71 | case IB_QPS_ERR: | ||
72 | return C2_QP_STATE_ERROR; | ||
73 | default: | ||
74 | return -1; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static int to_ib_state(enum c2_qp_state c2_state) | ||
79 | { | ||
80 | switch (c2_state) { | ||
81 | case C2_QP_STATE_IDLE: | ||
82 | return IB_QPS_RESET; | ||
83 | case C2_QP_STATE_CONNECTING: | ||
84 | return IB_QPS_RTR; | ||
85 | case C2_QP_STATE_RTS: | ||
86 | return IB_QPS_RTS; | ||
87 | case C2_QP_STATE_CLOSING: | ||
88 | return IB_QPS_SQD; | ||
89 | case C2_QP_STATE_ERROR: | ||
90 | return IB_QPS_ERR; | ||
91 | case C2_QP_STATE_TERMINATE: | ||
92 | return IB_QPS_SQE; | ||
93 | default: | ||
94 | return -1; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static const char *to_ib_state_str(int ib_state) | ||
99 | { | ||
100 | static const char *state_str[] = { | ||
101 | "IB_QPS_RESET", | ||
102 | "IB_QPS_INIT", | ||
103 | "IB_QPS_RTR", | ||
104 | "IB_QPS_RTS", | ||
105 | "IB_QPS_SQD", | ||
106 | "IB_QPS_SQE", | ||
107 | "IB_QPS_ERR" | ||
108 | }; | ||
109 | if (ib_state < IB_QPS_RESET || | ||
110 | ib_state > IB_QPS_ERR) | ||
111 | return "<invalid IB QP state>"; | ||
112 | |||
113 | ib_state -= IB_QPS_RESET; | ||
114 | return state_str[ib_state]; | ||
115 | } | ||
116 | |||
117 | void c2_set_qp_state(struct c2_qp *qp, int c2_state) | ||
118 | { | ||
119 | int new_state = to_ib_state(c2_state); | ||
120 | |||
121 | pr_debug("%s: qp[%p] state modify %s --> %s\n", | ||
122 | __FUNCTION__, | ||
123 | qp, | ||
124 | to_ib_state_str(qp->state), | ||
125 | to_ib_state_str(new_state)); | ||
126 | qp->state = new_state; | ||
127 | } | ||
128 | |||
129 | #define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF | ||
130 | |||
131 | int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp, | ||
132 | struct ib_qp_attr *attr, int attr_mask) | ||
133 | { | ||
134 | struct c2wr_qp_modify_req wr; | ||
135 | struct c2wr_qp_modify_rep *reply; | ||
136 | struct c2_vq_req *vq_req; | ||
137 | unsigned long flags; | ||
138 | u8 next_state; | ||
139 | int err; | ||
140 | |||
141 | pr_debug("%s:%d qp=%p, %s --> %s\n", | ||
142 | __FUNCTION__, __LINE__, | ||
143 | qp, | ||
144 | to_ib_state_str(qp->state), | ||
145 | to_ib_state_str(attr->qp_state)); | ||
146 | |||
147 | vq_req = vq_req_alloc(c2dev); | ||
148 | if (!vq_req) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | c2_wr_set_id(&wr, CCWR_QP_MODIFY); | ||
152 | wr.hdr.context = (unsigned long) vq_req; | ||
153 | wr.rnic_handle = c2dev->adapter_handle; | ||
154 | wr.qp_handle = qp->adapter_handle; | ||
155 | wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); | ||
156 | wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); | ||
157 | wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); | ||
158 | wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); | ||
159 | |||
160 | if (attr_mask & IB_QP_STATE) { | ||
161 | /* Ensure the state is valid */ | ||
162 | if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR) | ||
163 | return -EINVAL; | ||
164 | |||
165 | wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state)); | ||
166 | |||
167 | if (attr->qp_state == IB_QPS_ERR) { | ||
168 | spin_lock_irqsave(&qp->lock, flags); | ||
169 | if (qp->cm_id && qp->state == IB_QPS_RTS) { | ||
170 | pr_debug("Generating CLOSE event for QP-->ERR, " | ||
171 | "qp=%p, cm_id=%p\n",qp,qp->cm_id); | ||
172 | /* Generate an CLOSE event */ | ||
173 | vq_req->cm_id = qp->cm_id; | ||
174 | vq_req->event = IW_CM_EVENT_CLOSE; | ||
175 | } | ||
176 | spin_unlock_irqrestore(&qp->lock, flags); | ||
177 | } | ||
178 | next_state = attr->qp_state; | ||
179 | |||
180 | } else if (attr_mask & IB_QP_CUR_STATE) { | ||
181 | |||
182 | if (attr->cur_qp_state != IB_QPS_RTR && | ||
183 | attr->cur_qp_state != IB_QPS_RTS && | ||
184 | attr->cur_qp_state != IB_QPS_SQD && | ||
185 | attr->cur_qp_state != IB_QPS_SQE) | ||
186 | return -EINVAL; | ||
187 | else | ||
188 | wr.next_qp_state = | ||
189 | cpu_to_be32(to_c2_state(attr->cur_qp_state)); | ||
190 | |||
191 | next_state = attr->cur_qp_state; | ||
192 | |||
193 | } else { | ||
194 | err = 0; | ||
195 | goto bail0; | ||
196 | } | ||
197 | |||
198 | /* reference the request struct */ | ||
199 | vq_req_get(c2dev, vq_req); | ||
200 | |||
201 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
202 | if (err) { | ||
203 | vq_req_put(c2dev, vq_req); | ||
204 | goto bail0; | ||
205 | } | ||
206 | |||
207 | err = vq_wait_for_reply(c2dev, vq_req); | ||
208 | if (err) | ||
209 | goto bail0; | ||
210 | |||
211 | reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg; | ||
212 | if (!reply) { | ||
213 | err = -ENOMEM; | ||
214 | goto bail0; | ||
215 | } | ||
216 | |||
217 | err = c2_errno(reply); | ||
218 | if (!err) | ||
219 | qp->state = next_state; | ||
220 | #ifdef DEBUG | ||
221 | else | ||
222 | pr_debug("%s: c2_errno=%d\n", __FUNCTION__, err); | ||
223 | #endif | ||
224 | /* | ||
225 | * If we're going to error and generating the event here, then | ||
226 | * we need to remove the reference because there will be no | ||
227 | * close event generated by the adapter | ||
228 | */ | ||
229 | spin_lock_irqsave(&qp->lock, flags); | ||
230 | if (vq_req->event==IW_CM_EVENT_CLOSE && qp->cm_id) { | ||
231 | qp->cm_id->rem_ref(qp->cm_id); | ||
232 | qp->cm_id = NULL; | ||
233 | } | ||
234 | spin_unlock_irqrestore(&qp->lock, flags); | ||
235 | |||
236 | vq_repbuf_free(c2dev, reply); | ||
237 | bail0: | ||
238 | vq_req_free(c2dev, vq_req); | ||
239 | |||
240 | pr_debug("%s:%d qp=%p, cur_state=%s\n", | ||
241 | __FUNCTION__, __LINE__, | ||
242 | qp, | ||
243 | to_ib_state_str(qp->state)); | ||
244 | return err; | ||
245 | } | ||
246 | |||
247 | int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp, | ||
248 | int ord, int ird) | ||
249 | { | ||
250 | struct c2wr_qp_modify_req wr; | ||
251 | struct c2wr_qp_modify_rep *reply; | ||
252 | struct c2_vq_req *vq_req; | ||
253 | int err; | ||
254 | |||
255 | vq_req = vq_req_alloc(c2dev); | ||
256 | if (!vq_req) | ||
257 | return -ENOMEM; | ||
258 | |||
259 | c2_wr_set_id(&wr, CCWR_QP_MODIFY); | ||
260 | wr.hdr.context = (unsigned long) vq_req; | ||
261 | wr.rnic_handle = c2dev->adapter_handle; | ||
262 | wr.qp_handle = qp->adapter_handle; | ||
263 | wr.ord = cpu_to_be32(ord); | ||
264 | wr.ird = cpu_to_be32(ird); | ||
265 | wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); | ||
266 | wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); | ||
267 | wr.next_qp_state = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); | ||
268 | |||
269 | /* reference the request struct */ | ||
270 | vq_req_get(c2dev, vq_req); | ||
271 | |||
272 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
273 | if (err) { | ||
274 | vq_req_put(c2dev, vq_req); | ||
275 | goto bail0; | ||
276 | } | ||
277 | |||
278 | err = vq_wait_for_reply(c2dev, vq_req); | ||
279 | if (err) | ||
280 | goto bail0; | ||
281 | |||
282 | reply = (struct c2wr_qp_modify_rep *) (unsigned long) | ||
283 | vq_req->reply_msg; | ||
284 | if (!reply) { | ||
285 | err = -ENOMEM; | ||
286 | goto bail0; | ||
287 | } | ||
288 | |||
289 | err = c2_errno(reply); | ||
290 | vq_repbuf_free(c2dev, reply); | ||
291 | bail0: | ||
292 | vq_req_free(c2dev, vq_req); | ||
293 | return err; | ||
294 | } | ||
295 | |||
296 | static int destroy_qp(struct c2_dev *c2dev, struct c2_qp *qp) | ||
297 | { | ||
298 | struct c2_vq_req *vq_req; | ||
299 | struct c2wr_qp_destroy_req wr; | ||
300 | struct c2wr_qp_destroy_rep *reply; | ||
301 | unsigned long flags; | ||
302 | int err; | ||
303 | |||
304 | /* | ||
305 | * Allocate a verb request message | ||
306 | */ | ||
307 | vq_req = vq_req_alloc(c2dev); | ||
308 | if (!vq_req) { | ||
309 | return -ENOMEM; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Initialize the WR | ||
314 | */ | ||
315 | c2_wr_set_id(&wr, CCWR_QP_DESTROY); | ||
316 | wr.hdr.context = (unsigned long) vq_req; | ||
317 | wr.rnic_handle = c2dev->adapter_handle; | ||
318 | wr.qp_handle = qp->adapter_handle; | ||
319 | |||
320 | /* | ||
321 | * reference the request struct. dereferenced in the int handler. | ||
322 | */ | ||
323 | vq_req_get(c2dev, vq_req); | ||
324 | |||
325 | spin_lock_irqsave(&qp->lock, flags); | ||
326 | if (qp->cm_id && qp->state == IB_QPS_RTS) { | ||
327 | pr_debug("destroy_qp: generating CLOSE event for QP-->ERR, " | ||
328 | "qp=%p, cm_id=%p\n",qp,qp->cm_id); | ||
329 | /* Generate an CLOSE event */ | ||
330 | vq_req->qp = qp; | ||
331 | vq_req->cm_id = qp->cm_id; | ||
332 | vq_req->event = IW_CM_EVENT_CLOSE; | ||
333 | } | ||
334 | spin_unlock_irqrestore(&qp->lock, flags); | ||
335 | |||
336 | /* | ||
337 | * Send WR to adapter | ||
338 | */ | ||
339 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
340 | if (err) { | ||
341 | vq_req_put(c2dev, vq_req); | ||
342 | goto bail0; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Wait for reply from adapter | ||
347 | */ | ||
348 | err = vq_wait_for_reply(c2dev, vq_req); | ||
349 | if (err) { | ||
350 | goto bail0; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * Process reply | ||
355 | */ | ||
356 | reply = (struct c2wr_qp_destroy_rep *) (unsigned long) (vq_req->reply_msg); | ||
357 | if (!reply) { | ||
358 | err = -ENOMEM; | ||
359 | goto bail0; | ||
360 | } | ||
361 | |||
362 | spin_lock_irqsave(&qp->lock, flags); | ||
363 | if (qp->cm_id) { | ||
364 | qp->cm_id->rem_ref(qp->cm_id); | ||
365 | qp->cm_id = NULL; | ||
366 | } | ||
367 | spin_unlock_irqrestore(&qp->lock, flags); | ||
368 | |||
369 | vq_repbuf_free(c2dev, reply); | ||
370 | bail0: | ||
371 | vq_req_free(c2dev, vq_req); | ||
372 | return err; | ||
373 | } | ||
374 | |||
375 | static int c2_alloc_qpn(struct c2_dev *c2dev, struct c2_qp *qp) | ||
376 | { | ||
377 | int ret; | ||
378 | |||
379 | do { | ||
380 | spin_lock_irq(&c2dev->qp_table.lock); | ||
381 | ret = idr_get_new_above(&c2dev->qp_table.idr, qp, | ||
382 | c2dev->qp_table.last++, &qp->qpn); | ||
383 | spin_unlock_irq(&c2dev->qp_table.lock); | ||
384 | } while ((ret == -EAGAIN) && | ||
385 | idr_pre_get(&c2dev->qp_table.idr, GFP_KERNEL)); | ||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | static void c2_free_qpn(struct c2_dev *c2dev, int qpn) | ||
390 | { | ||
391 | spin_lock_irq(&c2dev->qp_table.lock); | ||
392 | idr_remove(&c2dev->qp_table.idr, qpn); | ||
393 | spin_unlock_irq(&c2dev->qp_table.lock); | ||
394 | } | ||
395 | |||
396 | struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn) | ||
397 | { | ||
398 | unsigned long flags; | ||
399 | struct c2_qp *qp; | ||
400 | |||
401 | spin_lock_irqsave(&c2dev->qp_table.lock, flags); | ||
402 | qp = idr_find(&c2dev->qp_table.idr, qpn); | ||
403 | spin_unlock_irqrestore(&c2dev->qp_table.lock, flags); | ||
404 | return qp; | ||
405 | } | ||
406 | |||
407 | int c2_alloc_qp(struct c2_dev *c2dev, | ||
408 | struct c2_pd *pd, | ||
409 | struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp) | ||
410 | { | ||
411 | struct c2wr_qp_create_req wr; | ||
412 | struct c2wr_qp_create_rep *reply; | ||
413 | struct c2_vq_req *vq_req; | ||
414 | struct c2_cq *send_cq = to_c2cq(qp_attrs->send_cq); | ||
415 | struct c2_cq *recv_cq = to_c2cq(qp_attrs->recv_cq); | ||
416 | unsigned long peer_pa; | ||
417 | u32 q_size, msg_size, mmap_size; | ||
418 | void __iomem *mmap; | ||
419 | int err; | ||
420 | |||
421 | err = c2_alloc_qpn(c2dev, qp); | ||
422 | if (err) | ||
423 | return err; | ||
424 | qp->ibqp.qp_num = qp->qpn; | ||
425 | qp->ibqp.qp_type = IB_QPT_RC; | ||
426 | |||
427 | /* Allocate the SQ and RQ shared pointers */ | ||
428 | qp->sq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, | ||
429 | &qp->sq_mq.shared_dma, GFP_KERNEL); | ||
430 | if (!qp->sq_mq.shared) { | ||
431 | err = -ENOMEM; | ||
432 | goto bail0; | ||
433 | } | ||
434 | |||
435 | qp->rq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, | ||
436 | &qp->rq_mq.shared_dma, GFP_KERNEL); | ||
437 | if (!qp->rq_mq.shared) { | ||
438 | err = -ENOMEM; | ||
439 | goto bail1; | ||
440 | } | ||
441 | |||
442 | /* Allocate the verbs request */ | ||
443 | vq_req = vq_req_alloc(c2dev); | ||
444 | if (vq_req == NULL) { | ||
445 | err = -ENOMEM; | ||
446 | goto bail2; | ||
447 | } | ||
448 | |||
449 | /* Initialize the work request */ | ||
450 | memset(&wr, 0, sizeof(wr)); | ||
451 | c2_wr_set_id(&wr, CCWR_QP_CREATE); | ||
452 | wr.hdr.context = (unsigned long) vq_req; | ||
453 | wr.rnic_handle = c2dev->adapter_handle; | ||
454 | wr.sq_cq_handle = send_cq->adapter_handle; | ||
455 | wr.rq_cq_handle = recv_cq->adapter_handle; | ||
456 | wr.sq_depth = cpu_to_be32(qp_attrs->cap.max_send_wr + 1); | ||
457 | wr.rq_depth = cpu_to_be32(qp_attrs->cap.max_recv_wr + 1); | ||
458 | wr.srq_handle = 0; | ||
459 | wr.flags = cpu_to_be32(QP_RDMA_READ | QP_RDMA_WRITE | QP_MW_BIND | | ||
460 | QP_ZERO_STAG | QP_RDMA_READ_RESPONSE); | ||
461 | wr.send_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge); | ||
462 | wr.recv_sgl_depth = cpu_to_be32(qp_attrs->cap.max_recv_sge); | ||
463 | wr.rdma_write_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge); | ||
464 | wr.shared_sq_ht = cpu_to_be64(qp->sq_mq.shared_dma); | ||
465 | wr.shared_rq_ht = cpu_to_be64(qp->rq_mq.shared_dma); | ||
466 | wr.ord = cpu_to_be32(C2_MAX_ORD_PER_QP); | ||
467 | wr.ird = cpu_to_be32(C2_MAX_IRD_PER_QP); | ||
468 | wr.pd_id = pd->pd_id; | ||
469 | wr.user_context = (unsigned long) qp; | ||
470 | |||
471 | vq_req_get(c2dev, vq_req); | ||
472 | |||
473 | /* Send the WR to the adapter */ | ||
474 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
475 | if (err) { | ||
476 | vq_req_put(c2dev, vq_req); | ||
477 | goto bail3; | ||
478 | } | ||
479 | |||
480 | /* Wait for the verb reply */ | ||
481 | err = vq_wait_for_reply(c2dev, vq_req); | ||
482 | if (err) { | ||
483 | goto bail3; | ||
484 | } | ||
485 | |||
486 | /* Process the reply */ | ||
487 | reply = (struct c2wr_qp_create_rep *) (unsigned long) (vq_req->reply_msg); | ||
488 | if (!reply) { | ||
489 | err = -ENOMEM; | ||
490 | goto bail3; | ||
491 | } | ||
492 | |||
493 | if ((err = c2_wr_get_result(reply)) != 0) { | ||
494 | goto bail4; | ||
495 | } | ||
496 | |||
497 | /* Fill in the kernel QP struct */ | ||
498 | atomic_set(&qp->refcount, 1); | ||
499 | qp->adapter_handle = reply->qp_handle; | ||
500 | qp->state = IB_QPS_RESET; | ||
501 | qp->send_sgl_depth = qp_attrs->cap.max_send_sge; | ||
502 | qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge; | ||
503 | qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge; | ||
504 | |||
505 | /* Initialize the SQ MQ */ | ||
506 | q_size = be32_to_cpu(reply->sq_depth); | ||
507 | msg_size = be32_to_cpu(reply->sq_msg_size); | ||
508 | peer_pa = c2dev->pa + be32_to_cpu(reply->sq_mq_start); | ||
509 | mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size); | ||
510 | mmap = ioremap_nocache(peer_pa, mmap_size); | ||
511 | if (!mmap) { | ||
512 | err = -ENOMEM; | ||
513 | goto bail5; | ||
514 | } | ||
515 | |||
516 | c2_mq_req_init(&qp->sq_mq, | ||
517 | be32_to_cpu(reply->sq_mq_index), | ||
518 | q_size, | ||
519 | msg_size, | ||
520 | mmap + sizeof(struct c2_mq_shared), /* pool start */ | ||
521 | mmap, /* peer */ | ||
522 | C2_MQ_ADAPTER_TARGET); | ||
523 | |||
524 | /* Initialize the RQ mq */ | ||
525 | q_size = be32_to_cpu(reply->rq_depth); | ||
526 | msg_size = be32_to_cpu(reply->rq_msg_size); | ||
527 | peer_pa = c2dev->pa + be32_to_cpu(reply->rq_mq_start); | ||
528 | mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size); | ||
529 | mmap = ioremap_nocache(peer_pa, mmap_size); | ||
530 | if (!mmap) { | ||
531 | err = -ENOMEM; | ||
532 | goto bail6; | ||
533 | } | ||
534 | |||
535 | c2_mq_req_init(&qp->rq_mq, | ||
536 | be32_to_cpu(reply->rq_mq_index), | ||
537 | q_size, | ||
538 | msg_size, | ||
539 | mmap + sizeof(struct c2_mq_shared), /* pool start */ | ||
540 | mmap, /* peer */ | ||
541 | C2_MQ_ADAPTER_TARGET); | ||
542 | |||
543 | vq_repbuf_free(c2dev, reply); | ||
544 | vq_req_free(c2dev, vq_req); | ||
545 | |||
546 | return 0; | ||
547 | |||
548 | bail6: | ||
549 | iounmap(qp->sq_mq.peer); | ||
550 | bail5: | ||
551 | destroy_qp(c2dev, qp); | ||
552 | bail4: | ||
553 | vq_repbuf_free(c2dev, reply); | ||
554 | bail3: | ||
555 | vq_req_free(c2dev, vq_req); | ||
556 | bail2: | ||
557 | c2_free_mqsp(qp->rq_mq.shared); | ||
558 | bail1: | ||
559 | c2_free_mqsp(qp->sq_mq.shared); | ||
560 | bail0: | ||
561 | c2_free_qpn(c2dev, qp->qpn); | ||
562 | return err; | ||
563 | } | ||
564 | |||
565 | void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp) | ||
566 | { | ||
567 | struct c2_cq *send_cq; | ||
568 | struct c2_cq *recv_cq; | ||
569 | |||
570 | send_cq = to_c2cq(qp->ibqp.send_cq); | ||
571 | recv_cq = to_c2cq(qp->ibqp.recv_cq); | ||
572 | |||
573 | /* | ||
574 | * Lock CQs here, so that CQ polling code can do QP lookup | ||
575 | * without taking a lock. | ||
576 | */ | ||
577 | spin_lock_irq(&send_cq->lock); | ||
578 | if (send_cq != recv_cq) | ||
579 | spin_lock(&recv_cq->lock); | ||
580 | |||
581 | c2_free_qpn(c2dev, qp->qpn); | ||
582 | |||
583 | if (send_cq != recv_cq) | ||
584 | spin_unlock(&recv_cq->lock); | ||
585 | spin_unlock_irq(&send_cq->lock); | ||
586 | |||
587 | /* | ||
588 | * Destory qp in the rnic... | ||
589 | */ | ||
590 | destroy_qp(c2dev, qp); | ||
591 | |||
592 | /* | ||
593 | * Mark any unreaped CQEs as null and void. | ||
594 | */ | ||
595 | c2_cq_clean(c2dev, qp, send_cq->cqn); | ||
596 | if (send_cq != recv_cq) | ||
597 | c2_cq_clean(c2dev, qp, recv_cq->cqn); | ||
598 | /* | ||
599 | * Unmap the MQs and return the shared pointers | ||
600 | * to the message pool. | ||
601 | */ | ||
602 | iounmap(qp->sq_mq.peer); | ||
603 | iounmap(qp->rq_mq.peer); | ||
604 | c2_free_mqsp(qp->sq_mq.shared); | ||
605 | c2_free_mqsp(qp->rq_mq.shared); | ||
606 | |||
607 | atomic_dec(&qp->refcount); | ||
608 | wait_event(qp->wait, !atomic_read(&qp->refcount)); | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * Function: move_sgl | ||
613 | * | ||
614 | * Description: | ||
615 | * Move an SGL from the user's work request struct into a CCIL Work Request | ||
616 | * message, swapping to WR byte order and ensure the total length doesn't | ||
617 | * overflow. | ||
618 | * | ||
619 | * IN: | ||
620 | * dst - ptr to CCIL Work Request message SGL memory. | ||
621 | * src - ptr to the consumers SGL memory. | ||
622 | * | ||
623 | * OUT: none | ||
624 | * | ||
625 | * Return: | ||
626 | * CCIL status codes. | ||
627 | */ | ||
628 | static int | ||
629 | move_sgl(struct c2_data_addr * dst, struct ib_sge *src, int count, u32 * p_len, | ||
630 | u8 * actual_count) | ||
631 | { | ||
632 | u32 tot = 0; /* running total */ | ||
633 | u8 acount = 0; /* running total non-0 len sge's */ | ||
634 | |||
635 | while (count > 0) { | ||
636 | /* | ||
637 | * If the addition of this SGE causes the | ||
638 | * total SGL length to exceed 2^32-1, then | ||
639 | * fail-n-bail. | ||
640 | * | ||
641 | * If the current total plus the next element length | ||
642 | * wraps, then it will go negative and be less than the | ||
643 | * current total... | ||
644 | */ | ||
645 | if ((tot + src->length) < tot) { | ||
646 | return -EINVAL; | ||
647 | } | ||
648 | /* | ||
649 | * Bug: 1456 (as well as 1498 & 1643) | ||
650 | * Skip over any sge's supplied with len=0 | ||
651 | */ | ||
652 | if (src->length) { | ||
653 | tot += src->length; | ||
654 | dst->stag = cpu_to_be32(src->lkey); | ||
655 | dst->to = cpu_to_be64(src->addr); | ||
656 | dst->length = cpu_to_be32(src->length); | ||
657 | dst++; | ||
658 | acount++; | ||
659 | } | ||
660 | src++; | ||
661 | count--; | ||
662 | } | ||
663 | |||
664 | if (acount == 0) { | ||
665 | /* | ||
666 | * Bug: 1476 (as well as 1498, 1456 and 1643) | ||
667 | * Setup the SGL in the WR to make it easier for the RNIC. | ||
668 | * This way, the FW doesn't have to deal with special cases. | ||
669 | * Setting length=0 should be sufficient. | ||
670 | */ | ||
671 | dst->stag = 0; | ||
672 | dst->to = 0; | ||
673 | dst->length = 0; | ||
674 | } | ||
675 | |||
676 | *p_len = tot; | ||
677 | *actual_count = acount; | ||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | /* | ||
682 | * Function: c2_activity (private function) | ||
683 | * | ||
684 | * Description: | ||
685 | * Post an mq index to the host->adapter activity fifo. | ||
686 | * | ||
687 | * IN: | ||
688 | * c2dev - ptr to c2dev structure | ||
689 | * mq_index - mq index to post | ||
690 | * shared - value most recently written to shared | ||
691 | * | ||
692 | * OUT: | ||
693 | * | ||
694 | * Return: | ||
695 | * none | ||
696 | */ | ||
697 | static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared) | ||
698 | { | ||
699 | /* | ||
700 | * First read the register to see if the FIFO is full, and if so, | ||
701 | * spin until it's not. This isn't perfect -- there is no | ||
702 | * synchronization among the clients of the register, but in | ||
703 | * practice it prevents multiple CPU from hammering the bus | ||
704 | * with PCI RETRY. Note that when this does happen, the card | ||
705 | * cannot get on the bus and the card and system hang in a | ||
706 | * deadlock -- thus the need for this code. [TOT] | ||
707 | */ | ||
708 | while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000) { | ||
709 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
710 | schedule_timeout(0); | ||
711 | } | ||
712 | |||
713 | __raw_writel(C2_HINT_MAKE(mq_index, shared), | ||
714 | c2dev->regs + PCI_BAR0_ADAPTER_HINT); | ||
715 | } | ||
716 | |||
717 | /* | ||
718 | * Function: qp_wr_post | ||
719 | * | ||
720 | * Description: | ||
721 | * This in-line function allocates a MQ msg, then moves the host-copy of | ||
722 | * the completed WR into msg. Then it posts the message. | ||
723 | * | ||
724 | * IN: | ||
725 | * q - ptr to user MQ. | ||
726 | * wr - ptr to host-copy of the WR. | ||
727 | * qp - ptr to user qp | ||
728 | * size - Number of bytes to post. Assumed to be divisible by 4. | ||
729 | * | ||
730 | * OUT: none | ||
731 | * | ||
732 | * Return: | ||
733 | * CCIL status codes. | ||
734 | */ | ||
735 | static int qp_wr_post(struct c2_mq *q, union c2wr * wr, struct c2_qp *qp, u32 size) | ||
736 | { | ||
737 | union c2wr *msg; | ||
738 | |||
739 | msg = c2_mq_alloc(q); | ||
740 | if (msg == NULL) { | ||
741 | return -EINVAL; | ||
742 | } | ||
743 | #ifdef CCMSGMAGIC | ||
744 | ((c2wr_hdr_t *) wr)->magic = cpu_to_be32(CCWR_MAGIC); | ||
745 | #endif | ||
746 | |||
747 | /* | ||
748 | * Since all header fields in the WR are the same as the | ||
749 | * CQE, set the following so the adapter need not. | ||
750 | */ | ||
751 | c2_wr_set_result(wr, CCERR_PENDING); | ||
752 | |||
753 | /* | ||
754 | * Copy the wr down to the adapter | ||
755 | */ | ||
756 | memcpy((void *) msg, (void *) wr, size); | ||
757 | |||
758 | c2_mq_produce(q); | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | |||
763 | int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, | ||
764 | struct ib_send_wr **bad_wr) | ||
765 | { | ||
766 | struct c2_dev *c2dev = to_c2dev(ibqp->device); | ||
767 | struct c2_qp *qp = to_c2qp(ibqp); | ||
768 | union c2wr wr; | ||
769 | int err = 0; | ||
770 | |||
771 | u32 flags; | ||
772 | u32 tot_len; | ||
773 | u8 actual_sge_count; | ||
774 | u32 msg_size; | ||
775 | |||
776 | if (qp->state > IB_QPS_RTS) | ||
777 | return -EINVAL; | ||
778 | |||
779 | while (ib_wr) { | ||
780 | |||
781 | flags = 0; | ||
782 | wr.sqwr.sq_hdr.user_hdr.hdr.context = ib_wr->wr_id; | ||
783 | if (ib_wr->send_flags & IB_SEND_SIGNALED) { | ||
784 | flags |= SQ_SIGNALED; | ||
785 | } | ||
786 | |||
787 | switch (ib_wr->opcode) { | ||
788 | case IB_WR_SEND: | ||
789 | if (ib_wr->send_flags & IB_SEND_SOLICITED) { | ||
790 | c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE); | ||
791 | msg_size = sizeof(struct c2wr_send_req); | ||
792 | } else { | ||
793 | c2_wr_set_id(&wr, C2_WR_TYPE_SEND); | ||
794 | msg_size = sizeof(struct c2wr_send_req); | ||
795 | } | ||
796 | |||
797 | wr.sqwr.send.remote_stag = 0; | ||
798 | msg_size += sizeof(struct c2_data_addr) * ib_wr->num_sge; | ||
799 | if (ib_wr->num_sge > qp->send_sgl_depth) { | ||
800 | err = -EINVAL; | ||
801 | break; | ||
802 | } | ||
803 | if (ib_wr->send_flags & IB_SEND_FENCE) { | ||
804 | flags |= SQ_READ_FENCE; | ||
805 | } | ||
806 | err = move_sgl((struct c2_data_addr *) & (wr.sqwr.send.data), | ||
807 | ib_wr->sg_list, | ||
808 | ib_wr->num_sge, | ||
809 | &tot_len, &actual_sge_count); | ||
810 | wr.sqwr.send.sge_len = cpu_to_be32(tot_len); | ||
811 | c2_wr_set_sge_count(&wr, actual_sge_count); | ||
812 | break; | ||
813 | case IB_WR_RDMA_WRITE: | ||
814 | c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_WRITE); | ||
815 | msg_size = sizeof(struct c2wr_rdma_write_req) + | ||
816 | (sizeof(struct c2_data_addr) * ib_wr->num_sge); | ||
817 | if (ib_wr->num_sge > qp->rdma_write_sgl_depth) { | ||
818 | err = -EINVAL; | ||
819 | break; | ||
820 | } | ||
821 | if (ib_wr->send_flags & IB_SEND_FENCE) { | ||
822 | flags |= SQ_READ_FENCE; | ||
823 | } | ||
824 | wr.sqwr.rdma_write.remote_stag = | ||
825 | cpu_to_be32(ib_wr->wr.rdma.rkey); | ||
826 | wr.sqwr.rdma_write.remote_to = | ||
827 | cpu_to_be64(ib_wr->wr.rdma.remote_addr); | ||
828 | err = move_sgl((struct c2_data_addr *) | ||
829 | & (wr.sqwr.rdma_write.data), | ||
830 | ib_wr->sg_list, | ||
831 | ib_wr->num_sge, | ||
832 | &tot_len, &actual_sge_count); | ||
833 | wr.sqwr.rdma_write.sge_len = cpu_to_be32(tot_len); | ||
834 | c2_wr_set_sge_count(&wr, actual_sge_count); | ||
835 | break; | ||
836 | case IB_WR_RDMA_READ: | ||
837 | c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_READ); | ||
838 | msg_size = sizeof(struct c2wr_rdma_read_req); | ||
839 | |||
840 | /* IWarp only suppots 1 sge for RDMA reads */ | ||
841 | if (ib_wr->num_sge > 1) { | ||
842 | err = -EINVAL; | ||
843 | break; | ||
844 | } | ||
845 | |||
846 | /* | ||
847 | * Move the local and remote stag/to/len into the WR. | ||
848 | */ | ||
849 | wr.sqwr.rdma_read.local_stag = | ||
850 | cpu_to_be32(ib_wr->sg_list->lkey); | ||
851 | wr.sqwr.rdma_read.local_to = | ||
852 | cpu_to_be64(ib_wr->sg_list->addr); | ||
853 | wr.sqwr.rdma_read.remote_stag = | ||
854 | cpu_to_be32(ib_wr->wr.rdma.rkey); | ||
855 | wr.sqwr.rdma_read.remote_to = | ||
856 | cpu_to_be64(ib_wr->wr.rdma.remote_addr); | ||
857 | wr.sqwr.rdma_read.length = | ||
858 | cpu_to_be32(ib_wr->sg_list->length); | ||
859 | break; | ||
860 | default: | ||
861 | /* error */ | ||
862 | msg_size = 0; | ||
863 | err = -EINVAL; | ||
864 | break; | ||
865 | } | ||
866 | |||
867 | /* | ||
868 | * If we had an error on the last wr build, then | ||
869 | * break out. Possible errors include bogus WR | ||
870 | * type, and a bogus SGL length... | ||
871 | */ | ||
872 | if (err) { | ||
873 | break; | ||
874 | } | ||
875 | |||
876 | /* | ||
877 | * Store flags | ||
878 | */ | ||
879 | c2_wr_set_flags(&wr, flags); | ||
880 | |||
881 | /* | ||
882 | * Post the puppy! | ||
883 | */ | ||
884 | err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size); | ||
885 | if (err) { | ||
886 | break; | ||
887 | } | ||
888 | |||
889 | /* | ||
890 | * Enqueue mq index to activity FIFO. | ||
891 | */ | ||
892 | c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count); | ||
893 | |||
894 | ib_wr = ib_wr->next; | ||
895 | } | ||
896 | |||
897 | if (err) | ||
898 | *bad_wr = ib_wr; | ||
899 | return err; | ||
900 | } | ||
901 | |||
902 | int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, | ||
903 | struct ib_recv_wr **bad_wr) | ||
904 | { | ||
905 | struct c2_dev *c2dev = to_c2dev(ibqp->device); | ||
906 | struct c2_qp *qp = to_c2qp(ibqp); | ||
907 | union c2wr wr; | ||
908 | int err = 0; | ||
909 | |||
910 | if (qp->state > IB_QPS_RTS) | ||
911 | return -EINVAL; | ||
912 | |||
913 | /* | ||
914 | * Try and post each work request | ||
915 | */ | ||
916 | while (ib_wr) { | ||
917 | u32 tot_len; | ||
918 | u8 actual_sge_count; | ||
919 | |||
920 | if (ib_wr->num_sge > qp->recv_sgl_depth) { | ||
921 | err = -EINVAL; | ||
922 | break; | ||
923 | } | ||
924 | |||
925 | /* | ||
926 | * Create local host-copy of the WR | ||
927 | */ | ||
928 | wr.rqwr.rq_hdr.user_hdr.hdr.context = ib_wr->wr_id; | ||
929 | c2_wr_set_id(&wr, CCWR_RECV); | ||
930 | c2_wr_set_flags(&wr, 0); | ||
931 | |||
932 | /* sge_count is limited to eight bits. */ | ||
933 | BUG_ON(ib_wr->num_sge >= 256); | ||
934 | err = move_sgl((struct c2_data_addr *) & (wr.rqwr.data), | ||
935 | ib_wr->sg_list, | ||
936 | ib_wr->num_sge, &tot_len, &actual_sge_count); | ||
937 | c2_wr_set_sge_count(&wr, actual_sge_count); | ||
938 | |||
939 | /* | ||
940 | * If we had an error on the last wr build, then | ||
941 | * break out. Possible errors include bogus WR | ||
942 | * type, and a bogus SGL length... | ||
943 | */ | ||
944 | if (err) { | ||
945 | break; | ||
946 | } | ||
947 | |||
948 | err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size); | ||
949 | if (err) { | ||
950 | break; | ||
951 | } | ||
952 | |||
953 | /* | ||
954 | * Enqueue mq index to activity FIFO | ||
955 | */ | ||
956 | c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count); | ||
957 | |||
958 | ib_wr = ib_wr->next; | ||
959 | } | ||
960 | |||
961 | if (err) | ||
962 | *bad_wr = ib_wr; | ||
963 | return err; | ||
964 | } | ||
965 | |||
966 | void __devinit c2_init_qp_table(struct c2_dev *c2dev) | ||
967 | { | ||
968 | spin_lock_init(&c2dev->qp_table.lock); | ||
969 | idr_init(&c2dev->qp_table.idr); | ||
970 | } | ||
971 | |||
972 | void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev) | ||
973 | { | ||
974 | idr_destroy(&c2dev->qp_table.idr); | ||
975 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c new file mode 100644 index 000000000000..f49a32b7a8f6 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_rnic.c | |||
@@ -0,0 +1,664 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | #include <linux/pci.h> | ||
39 | #include <linux/netdevice.h> | ||
40 | #include <linux/etherdevice.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/ethtool.h> | ||
43 | #include <linux/mii.h> | ||
44 | #include <linux/if_vlan.h> | ||
45 | #include <linux/crc32.h> | ||
46 | #include <linux/in.h> | ||
47 | #include <linux/ip.h> | ||
48 | #include <linux/tcp.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/dma-mapping.h> | ||
51 | #include <linux/mm.h> | ||
52 | #include <linux/inet.h> | ||
53 | #include <linux/vmalloc.h> | ||
54 | |||
55 | #include <linux/route.h> | ||
56 | |||
57 | #include <asm/io.h> | ||
58 | #include <asm/irq.h> | ||
59 | #include <asm/byteorder.h> | ||
60 | #include <rdma/ib_smi.h> | ||
61 | #include "c2.h" | ||
62 | #include "c2_vq.h" | ||
63 | |||
64 | /* Device capabilities */ | ||
65 | #define C2_MIN_PAGESIZE 1024 | ||
66 | |||
67 | #define C2_MAX_MRS 32768 | ||
68 | #define C2_MAX_QPS 16000 | ||
69 | #define C2_MAX_WQE_SZ 256 | ||
70 | #define C2_MAX_QP_WR ((128*1024)/C2_MAX_WQE_SZ) | ||
71 | #define C2_MAX_SGES 4 | ||
72 | #define C2_MAX_SGE_RD 1 | ||
73 | #define C2_MAX_CQS 32768 | ||
74 | #define C2_MAX_CQES 4096 | ||
75 | #define C2_MAX_PDS 16384 | ||
76 | |||
77 | /* | ||
78 | * Send the adapter INIT message to the amso1100 | ||
79 | */ | ||
80 | static int c2_adapter_init(struct c2_dev *c2dev) | ||
81 | { | ||
82 | struct c2wr_init_req wr; | ||
83 | int err; | ||
84 | |||
85 | memset(&wr, 0, sizeof(wr)); | ||
86 | c2_wr_set_id(&wr, CCWR_INIT); | ||
87 | wr.hdr.context = 0; | ||
88 | wr.hint_count = cpu_to_be64(c2dev->hint_count_dma); | ||
89 | wr.q0_host_shared = cpu_to_be64(c2dev->req_vq.shared_dma); | ||
90 | wr.q1_host_shared = cpu_to_be64(c2dev->rep_vq.shared_dma); | ||
91 | wr.q1_host_msg_pool = cpu_to_be64(c2dev->rep_vq.host_dma); | ||
92 | wr.q2_host_shared = cpu_to_be64(c2dev->aeq.shared_dma); | ||
93 | wr.q2_host_msg_pool = cpu_to_be64(c2dev->aeq.host_dma); | ||
94 | |||
95 | /* Post the init message */ | ||
96 | err = vq_send_wr(c2dev, (union c2wr *) & wr); | ||
97 | |||
98 | return err; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Send the adapter TERM message to the amso1100 | ||
103 | */ | ||
104 | static void c2_adapter_term(struct c2_dev *c2dev) | ||
105 | { | ||
106 | struct c2wr_init_req wr; | ||
107 | |||
108 | memset(&wr, 0, sizeof(wr)); | ||
109 | c2_wr_set_id(&wr, CCWR_TERM); | ||
110 | wr.hdr.context = 0; | ||
111 | |||
112 | /* Post the init message */ | ||
113 | vq_send_wr(c2dev, (union c2wr *) & wr); | ||
114 | c2dev->init = 0; | ||
115 | |||
116 | return; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Query the adapter | ||
121 | */ | ||
122 | static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props) | ||
123 | { | ||
124 | struct c2_vq_req *vq_req; | ||
125 | struct c2wr_rnic_query_req wr; | ||
126 | struct c2wr_rnic_query_rep *reply; | ||
127 | int err; | ||
128 | |||
129 | vq_req = vq_req_alloc(c2dev); | ||
130 | if (!vq_req) | ||
131 | return -ENOMEM; | ||
132 | |||
133 | c2_wr_set_id(&wr, CCWR_RNIC_QUERY); | ||
134 | wr.hdr.context = (unsigned long) vq_req; | ||
135 | wr.rnic_handle = c2dev->adapter_handle; | ||
136 | |||
137 | vq_req_get(c2dev, vq_req); | ||
138 | |||
139 | err = vq_send_wr(c2dev, (union c2wr *) &wr); | ||
140 | if (err) { | ||
141 | vq_req_put(c2dev, vq_req); | ||
142 | goto bail1; | ||
143 | } | ||
144 | |||
145 | err = vq_wait_for_reply(c2dev, vq_req); | ||
146 | if (err) | ||
147 | goto bail1; | ||
148 | |||
149 | reply = | ||
150 | (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg); | ||
151 | if (!reply) | ||
152 | err = -ENOMEM; | ||
153 | |||
154 | err = c2_errno(reply); | ||
155 | if (err) | ||
156 | goto bail2; | ||
157 | |||
158 | props->fw_ver = | ||
159 | ((u64)be32_to_cpu(reply->fw_ver_major) << 32) | | ||
160 | ((be32_to_cpu(reply->fw_ver_minor) && 0xFFFF) << 16) | | ||
161 | (be32_to_cpu(reply->fw_ver_patch) && 0xFFFF); | ||
162 | memcpy(&props->sys_image_guid, c2dev->netdev->dev_addr, 6); | ||
163 | props->max_mr_size = 0xFFFFFFFF; | ||
164 | props->page_size_cap = ~(C2_MIN_PAGESIZE-1); | ||
165 | props->vendor_id = be32_to_cpu(reply->vendor_id); | ||
166 | props->vendor_part_id = be32_to_cpu(reply->part_number); | ||
167 | props->hw_ver = be32_to_cpu(reply->hw_version); | ||
168 | props->max_qp = be32_to_cpu(reply->max_qps); | ||
169 | props->max_qp_wr = be32_to_cpu(reply->max_qp_depth); | ||
170 | props->device_cap_flags = c2dev->device_cap_flags; | ||
171 | props->max_sge = C2_MAX_SGES; | ||
172 | props->max_sge_rd = C2_MAX_SGE_RD; | ||
173 | props->max_cq = be32_to_cpu(reply->max_cqs); | ||
174 | props->max_cqe = be32_to_cpu(reply->max_cq_depth); | ||
175 | props->max_mr = be32_to_cpu(reply->max_mrs); | ||
176 | props->max_pd = be32_to_cpu(reply->max_pds); | ||
177 | props->max_qp_rd_atom = be32_to_cpu(reply->max_qp_ird); | ||
178 | props->max_ee_rd_atom = 0; | ||
179 | props->max_res_rd_atom = be32_to_cpu(reply->max_global_ird); | ||
180 | props->max_qp_init_rd_atom = be32_to_cpu(reply->max_qp_ord); | ||
181 | props->max_ee_init_rd_atom = 0; | ||
182 | props->atomic_cap = IB_ATOMIC_NONE; | ||
183 | props->max_ee = 0; | ||
184 | props->max_rdd = 0; | ||
185 | props->max_mw = be32_to_cpu(reply->max_mws); | ||
186 | props->max_raw_ipv6_qp = 0; | ||
187 | props->max_raw_ethy_qp = 0; | ||
188 | props->max_mcast_grp = 0; | ||
189 | props->max_mcast_qp_attach = 0; | ||
190 | props->max_total_mcast_qp_attach = 0; | ||
191 | props->max_ah = 0; | ||
192 | props->max_fmr = 0; | ||
193 | props->max_map_per_fmr = 0; | ||
194 | props->max_srq = 0; | ||
195 | props->max_srq_wr = 0; | ||
196 | props->max_srq_sge = 0; | ||
197 | props->max_pkeys = 0; | ||
198 | props->local_ca_ack_delay = 0; | ||
199 | |||
200 | bail2: | ||
201 | vq_repbuf_free(c2dev, reply); | ||
202 | |||
203 | bail1: | ||
204 | vq_req_free(c2dev, vq_req); | ||
205 | return err; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * Add an IP address to the RNIC interface | ||
210 | */ | ||
211 | int c2_add_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask) | ||
212 | { | ||
213 | struct c2_vq_req *vq_req; | ||
214 | struct c2wr_rnic_setconfig_req *wr; | ||
215 | struct c2wr_rnic_setconfig_rep *reply; | ||
216 | struct c2_netaddr netaddr; | ||
217 | int err, len; | ||
218 | |||
219 | vq_req = vq_req_alloc(c2dev); | ||
220 | if (!vq_req) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | len = sizeof(struct c2_netaddr); | ||
224 | wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); | ||
225 | if (!wr) { | ||
226 | err = -ENOMEM; | ||
227 | goto bail0; | ||
228 | } | ||
229 | |||
230 | c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG); | ||
231 | wr->hdr.context = (unsigned long) vq_req; | ||
232 | wr->rnic_handle = c2dev->adapter_handle; | ||
233 | wr->option = cpu_to_be32(C2_CFG_ADD_ADDR); | ||
234 | |||
235 | netaddr.ip_addr = inaddr; | ||
236 | netaddr.netmask = inmask; | ||
237 | netaddr.mtu = 0; | ||
238 | |||
239 | memcpy(wr->data, &netaddr, len); | ||
240 | |||
241 | vq_req_get(c2dev, vq_req); | ||
242 | |||
243 | err = vq_send_wr(c2dev, (union c2wr *) wr); | ||
244 | if (err) { | ||
245 | vq_req_put(c2dev, vq_req); | ||
246 | goto bail1; | ||
247 | } | ||
248 | |||
249 | err = vq_wait_for_reply(c2dev, vq_req); | ||
250 | if (err) | ||
251 | goto bail1; | ||
252 | |||
253 | reply = | ||
254 | (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg); | ||
255 | if (!reply) { | ||
256 | err = -ENOMEM; | ||
257 | goto bail1; | ||
258 | } | ||
259 | |||
260 | err = c2_errno(reply); | ||
261 | vq_repbuf_free(c2dev, reply); | ||
262 | |||
263 | bail1: | ||
264 | kfree(wr); | ||
265 | bail0: | ||
266 | vq_req_free(c2dev, vq_req); | ||
267 | return err; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Delete an IP address from the RNIC interface | ||
272 | */ | ||
273 | int c2_del_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask) | ||
274 | { | ||
275 | struct c2_vq_req *vq_req; | ||
276 | struct c2wr_rnic_setconfig_req *wr; | ||
277 | struct c2wr_rnic_setconfig_rep *reply; | ||
278 | struct c2_netaddr netaddr; | ||
279 | int err, len; | ||
280 | |||
281 | vq_req = vq_req_alloc(c2dev); | ||
282 | if (!vq_req) | ||
283 | return -ENOMEM; | ||
284 | |||
285 | len = sizeof(struct c2_netaddr); | ||
286 | wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); | ||
287 | if (!wr) { | ||
288 | err = -ENOMEM; | ||
289 | goto bail0; | ||
290 | } | ||
291 | |||
292 | c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG); | ||
293 | wr->hdr.context = (unsigned long) vq_req; | ||
294 | wr->rnic_handle = c2dev->adapter_handle; | ||
295 | wr->option = cpu_to_be32(C2_CFG_DEL_ADDR); | ||
296 | |||
297 | netaddr.ip_addr = inaddr; | ||
298 | netaddr.netmask = inmask; | ||
299 | netaddr.mtu = 0; | ||
300 | |||
301 | memcpy(wr->data, &netaddr, len); | ||
302 | |||
303 | vq_req_get(c2dev, vq_req); | ||
304 | |||
305 | err = vq_send_wr(c2dev, (union c2wr *) wr); | ||
306 | if (err) { | ||
307 | vq_req_put(c2dev, vq_req); | ||
308 | goto bail1; | ||
309 | } | ||
310 | |||
311 | err = vq_wait_for_reply(c2dev, vq_req); | ||
312 | if (err) | ||
313 | goto bail1; | ||
314 | |||
315 | reply = | ||
316 | (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg); | ||
317 | if (!reply) { | ||
318 | err = -ENOMEM; | ||
319 | goto bail1; | ||
320 | } | ||
321 | |||
322 | err = c2_errno(reply); | ||
323 | vq_repbuf_free(c2dev, reply); | ||
324 | |||
325 | bail1: | ||
326 | kfree(wr); | ||
327 | bail0: | ||
328 | vq_req_free(c2dev, vq_req); | ||
329 | return err; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Open a single RNIC instance to use with all | ||
334 | * low level openib calls | ||
335 | */ | ||
336 | static int c2_rnic_open(struct c2_dev *c2dev) | ||
337 | { | ||
338 | struct c2_vq_req *vq_req; | ||
339 | union c2wr wr; | ||
340 | struct c2wr_rnic_open_rep *reply; | ||
341 | int err; | ||
342 | |||
343 | vq_req = vq_req_alloc(c2dev); | ||
344 | if (vq_req == NULL) { | ||
345 | return -ENOMEM; | ||
346 | } | ||
347 | |||
348 | memset(&wr, 0, sizeof(wr)); | ||
349 | c2_wr_set_id(&wr, CCWR_RNIC_OPEN); | ||
350 | wr.rnic_open.req.hdr.context = (unsigned long) (vq_req); | ||
351 | wr.rnic_open.req.flags = cpu_to_be16(RNIC_PRIV_MODE); | ||
352 | wr.rnic_open.req.port_num = cpu_to_be16(0); | ||
353 | wr.rnic_open.req.user_context = (unsigned long) c2dev; | ||
354 | |||
355 | vq_req_get(c2dev, vq_req); | ||
356 | |||
357 | err = vq_send_wr(c2dev, &wr); | ||
358 | if (err) { | ||
359 | vq_req_put(c2dev, vq_req); | ||
360 | goto bail0; | ||
361 | } | ||
362 | |||
363 | err = vq_wait_for_reply(c2dev, vq_req); | ||
364 | if (err) { | ||
365 | goto bail0; | ||
366 | } | ||
367 | |||
368 | reply = (struct c2wr_rnic_open_rep *) (unsigned long) (vq_req->reply_msg); | ||
369 | if (!reply) { | ||
370 | err = -ENOMEM; | ||
371 | goto bail0; | ||
372 | } | ||
373 | |||
374 | if ((err = c2_errno(reply)) != 0) { | ||
375 | goto bail1; | ||
376 | } | ||
377 | |||
378 | c2dev->adapter_handle = reply->rnic_handle; | ||
379 | |||
380 | bail1: | ||
381 | vq_repbuf_free(c2dev, reply); | ||
382 | bail0: | ||
383 | vq_req_free(c2dev, vq_req); | ||
384 | return err; | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * Close the RNIC instance | ||
389 | */ | ||
390 | static int c2_rnic_close(struct c2_dev *c2dev) | ||
391 | { | ||
392 | struct c2_vq_req *vq_req; | ||
393 | union c2wr wr; | ||
394 | struct c2wr_rnic_close_rep *reply; | ||
395 | int err; | ||
396 | |||
397 | vq_req = vq_req_alloc(c2dev); | ||
398 | if (vq_req == NULL) { | ||
399 | return -ENOMEM; | ||
400 | } | ||
401 | |||
402 | memset(&wr, 0, sizeof(wr)); | ||
403 | c2_wr_set_id(&wr, CCWR_RNIC_CLOSE); | ||
404 | wr.rnic_close.req.hdr.context = (unsigned long) vq_req; | ||
405 | wr.rnic_close.req.rnic_handle = c2dev->adapter_handle; | ||
406 | |||
407 | vq_req_get(c2dev, vq_req); | ||
408 | |||
409 | err = vq_send_wr(c2dev, &wr); | ||
410 | if (err) { | ||
411 | vq_req_put(c2dev, vq_req); | ||
412 | goto bail0; | ||
413 | } | ||
414 | |||
415 | err = vq_wait_for_reply(c2dev, vq_req); | ||
416 | if (err) { | ||
417 | goto bail0; | ||
418 | } | ||
419 | |||
420 | reply = (struct c2wr_rnic_close_rep *) (unsigned long) (vq_req->reply_msg); | ||
421 | if (!reply) { | ||
422 | err = -ENOMEM; | ||
423 | goto bail0; | ||
424 | } | ||
425 | |||
426 | if ((err = c2_errno(reply)) != 0) { | ||
427 | goto bail1; | ||
428 | } | ||
429 | |||
430 | c2dev->adapter_handle = 0; | ||
431 | |||
432 | bail1: | ||
433 | vq_repbuf_free(c2dev, reply); | ||
434 | bail0: | ||
435 | vq_req_free(c2dev, vq_req); | ||
436 | return err; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * Called by c2_probe to initialize the RNIC. This principally | ||
441 | * involves initalizing the various limits and resouce pools that | ||
442 | * comprise the RNIC instance. | ||
443 | */ | ||
444 | int c2_rnic_init(struct c2_dev *c2dev) | ||
445 | { | ||
446 | int err; | ||
447 | u32 qsize, msgsize; | ||
448 | void *q1_pages; | ||
449 | void *q2_pages; | ||
450 | void __iomem *mmio_regs; | ||
451 | |||
452 | /* Device capabilities */ | ||
453 | c2dev->device_cap_flags = | ||
454 | (IB_DEVICE_RESIZE_MAX_WR | | ||
455 | IB_DEVICE_CURR_QP_STATE_MOD | | ||
456 | IB_DEVICE_SYS_IMAGE_GUID | | ||
457 | IB_DEVICE_ZERO_STAG | | ||
458 | IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW); | ||
459 | |||
460 | /* Allocate the qptr_array */ | ||
461 | c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *)); | ||
462 | if (!c2dev->qptr_array) { | ||
463 | return -ENOMEM; | ||
464 | } | ||
465 | |||
466 | /* Inialize the qptr_array */ | ||
467 | memset(c2dev->qptr_array, 0, C2_MAX_CQS * sizeof(void *)); | ||
468 | c2dev->qptr_array[0] = (void *) &c2dev->req_vq; | ||
469 | c2dev->qptr_array[1] = (void *) &c2dev->rep_vq; | ||
470 | c2dev->qptr_array[2] = (void *) &c2dev->aeq; | ||
471 | |||
472 | /* Initialize data structures */ | ||
473 | init_waitqueue_head(&c2dev->req_vq_wo); | ||
474 | spin_lock_init(&c2dev->vqlock); | ||
475 | spin_lock_init(&c2dev->lock); | ||
476 | |||
477 | /* Allocate MQ shared pointer pool for kernel clients. User | ||
478 | * mode client pools are hung off the user context | ||
479 | */ | ||
480 | err = c2_init_mqsp_pool(c2dev, GFP_KERNEL, &c2dev->kern_mqsp_pool); | ||
481 | if (err) { | ||
482 | goto bail0; | ||
483 | } | ||
484 | |||
485 | /* Allocate shared pointers for Q0, Q1, and Q2 from | ||
486 | * the shared pointer pool. | ||
487 | */ | ||
488 | |||
489 | c2dev->hint_count = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, | ||
490 | &c2dev->hint_count_dma, | ||
491 | GFP_KERNEL); | ||
492 | c2dev->req_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, | ||
493 | &c2dev->req_vq.shared_dma, | ||
494 | GFP_KERNEL); | ||
495 | c2dev->rep_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, | ||
496 | &c2dev->rep_vq.shared_dma, | ||
497 | GFP_KERNEL); | ||
498 | c2dev->aeq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, | ||
499 | &c2dev->aeq.shared_dma, GFP_KERNEL); | ||
500 | if (!c2dev->hint_count || !c2dev->req_vq.shared || | ||
501 | !c2dev->rep_vq.shared || !c2dev->aeq.shared) { | ||
502 | err = -ENOMEM; | ||
503 | goto bail1; | ||
504 | } | ||
505 | |||
506 | mmio_regs = c2dev->kva; | ||
507 | /* Initialize the Verbs Request Queue */ | ||
508 | c2_mq_req_init(&c2dev->req_vq, 0, | ||
509 | be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_QSIZE)), | ||
510 | be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_MSGSIZE)), | ||
511 | mmio_regs + | ||
512 | be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_POOLSTART)), | ||
513 | mmio_regs + | ||
514 | be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_SHARED)), | ||
515 | C2_MQ_ADAPTER_TARGET); | ||
516 | |||
517 | /* Initialize the Verbs Reply Queue */ | ||
518 | qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_QSIZE)); | ||
519 | msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_MSGSIZE)); | ||
520 | q1_pages = kmalloc(qsize * msgsize, GFP_KERNEL); | ||
521 | if (!q1_pages) { | ||
522 | err = -ENOMEM; | ||
523 | goto bail1; | ||
524 | } | ||
525 | c2dev->rep_vq.host_dma = dma_map_single(c2dev->ibdev.dma_device, | ||
526 | (void *)q1_pages, qsize * msgsize, | ||
527 | DMA_FROM_DEVICE); | ||
528 | pci_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma); | ||
529 | pr_debug("%s rep_vq va %p dma %llx\n", __FUNCTION__, q1_pages, | ||
530 | (u64)c2dev->rep_vq.host_dma); | ||
531 | c2_mq_rep_init(&c2dev->rep_vq, | ||
532 | 1, | ||
533 | qsize, | ||
534 | msgsize, | ||
535 | q1_pages, | ||
536 | mmio_regs + | ||
537 | be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_SHARED)), | ||
538 | C2_MQ_HOST_TARGET); | ||
539 | |||
540 | /* Initialize the Asynchronus Event Queue */ | ||
541 | qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_QSIZE)); | ||
542 | msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_MSGSIZE)); | ||
543 | q2_pages = kmalloc(qsize * msgsize, GFP_KERNEL); | ||
544 | if (!q2_pages) { | ||
545 | err = -ENOMEM; | ||
546 | goto bail2; | ||
547 | } | ||
548 | c2dev->aeq.host_dma = dma_map_single(c2dev->ibdev.dma_device, | ||
549 | (void *)q2_pages, qsize * msgsize, | ||
550 | DMA_FROM_DEVICE); | ||
551 | pci_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma); | ||
552 | pr_debug("%s aeq va %p dma %llx\n", __FUNCTION__, q1_pages, | ||
553 | (u64)c2dev->rep_vq.host_dma); | ||
554 | c2_mq_rep_init(&c2dev->aeq, | ||
555 | 2, | ||
556 | qsize, | ||
557 | msgsize, | ||
558 | q2_pages, | ||
559 | mmio_regs + | ||
560 | be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_SHARED)), | ||
561 | C2_MQ_HOST_TARGET); | ||
562 | |||
563 | /* Initialize the verbs request allocator */ | ||
564 | err = vq_init(c2dev); | ||
565 | if (err) | ||
566 | goto bail3; | ||
567 | |||
568 | /* Enable interrupts on the adapter */ | ||
569 | writel(0, c2dev->regs + C2_IDIS); | ||
570 | |||
571 | /* create the WR init message */ | ||
572 | err = c2_adapter_init(c2dev); | ||
573 | if (err) | ||
574 | goto bail4; | ||
575 | c2dev->init++; | ||
576 | |||
577 | /* open an adapter instance */ | ||
578 | err = c2_rnic_open(c2dev); | ||
579 | if (err) | ||
580 | goto bail4; | ||
581 | |||
582 | /* Initialize cached the adapter limits */ | ||
583 | if (c2_rnic_query(c2dev, &c2dev->props)) | ||
584 | goto bail5; | ||
585 | |||
586 | /* Initialize the PD pool */ | ||
587 | err = c2_init_pd_table(c2dev); | ||
588 | if (err) | ||
589 | goto bail5; | ||
590 | |||
591 | /* Initialize the QP pool */ | ||
592 | c2_init_qp_table(c2dev); | ||
593 | return 0; | ||
594 | |||
595 | bail5: | ||
596 | c2_rnic_close(c2dev); | ||
597 | bail4: | ||
598 | vq_term(c2dev); | ||
599 | bail3: | ||
600 | dma_unmap_single(c2dev->ibdev.dma_device, | ||
601 | pci_unmap_addr(&c2dev->aeq, mapping), | ||
602 | c2dev->aeq.q_size * c2dev->aeq.msg_size, | ||
603 | DMA_FROM_DEVICE); | ||
604 | kfree(q2_pages); | ||
605 | bail2: | ||
606 | dma_unmap_single(c2dev->ibdev.dma_device, | ||
607 | pci_unmap_addr(&c2dev->rep_vq, mapping), | ||
608 | c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size, | ||
609 | DMA_FROM_DEVICE); | ||
610 | kfree(q1_pages); | ||
611 | bail1: | ||
612 | c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool); | ||
613 | bail0: | ||
614 | vfree(c2dev->qptr_array); | ||
615 | |||
616 | return err; | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * Called by c2_remove to cleanup the RNIC resources. | ||
621 | */ | ||
622 | void c2_rnic_term(struct c2_dev *c2dev) | ||
623 | { | ||
624 | |||
625 | /* Close the open adapter instance */ | ||
626 | c2_rnic_close(c2dev); | ||
627 | |||
628 | /* Send the TERM message to the adapter */ | ||
629 | c2_adapter_term(c2dev); | ||
630 | |||
631 | /* Disable interrupts on the adapter */ | ||
632 | writel(1, c2dev->regs + C2_IDIS); | ||
633 | |||
634 | /* Free the QP pool */ | ||
635 | c2_cleanup_qp_table(c2dev); | ||
636 | |||
637 | /* Free the PD pool */ | ||
638 | c2_cleanup_pd_table(c2dev); | ||
639 | |||
640 | /* Free the verbs request allocator */ | ||
641 | vq_term(c2dev); | ||
642 | |||
643 | /* Unmap and free the asynchronus event queue */ | ||
644 | dma_unmap_single(c2dev->ibdev.dma_device, | ||
645 | pci_unmap_addr(&c2dev->aeq, mapping), | ||
646 | c2dev->aeq.q_size * c2dev->aeq.msg_size, | ||
647 | DMA_FROM_DEVICE); | ||
648 | kfree(c2dev->aeq.msg_pool.host); | ||
649 | |||
650 | /* Unmap and free the verbs reply queue */ | ||
651 | dma_unmap_single(c2dev->ibdev.dma_device, | ||
652 | pci_unmap_addr(&c2dev->rep_vq, mapping), | ||
653 | c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size, | ||
654 | DMA_FROM_DEVICE); | ||
655 | kfree(c2dev->rep_vq.msg_pool.host); | ||
656 | |||
657 | /* Free the MQ shared pointer pool */ | ||
658 | c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool); | ||
659 | |||
660 | /* Free the qptr_array */ | ||
661 | vfree(c2dev->qptr_array); | ||
662 | |||
663 | return; | ||
664 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_status.h b/drivers/infiniband/hw/amso1100/c2_status.h new file mode 100644 index 000000000000..6ee4aa92d875 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_status.h | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #ifndef _C2_STATUS_H_ | ||
34 | #define _C2_STATUS_H_ | ||
35 | |||
36 | /* | ||
37 | * Verbs Status Codes | ||
38 | */ | ||
39 | enum c2_status { | ||
40 | C2_OK = 0, /* This must be zero */ | ||
41 | CCERR_INSUFFICIENT_RESOURCES = 1, | ||
42 | CCERR_INVALID_MODIFIER = 2, | ||
43 | CCERR_INVALID_MODE = 3, | ||
44 | CCERR_IN_USE = 4, | ||
45 | CCERR_INVALID_RNIC = 5, | ||
46 | CCERR_INTERRUPTED_OPERATION = 6, | ||
47 | CCERR_INVALID_EH = 7, | ||
48 | CCERR_INVALID_CQ = 8, | ||
49 | CCERR_CQ_EMPTY = 9, | ||
50 | CCERR_NOT_IMPLEMENTED = 10, | ||
51 | CCERR_CQ_DEPTH_TOO_SMALL = 11, | ||
52 | CCERR_PD_IN_USE = 12, | ||
53 | CCERR_INVALID_PD = 13, | ||
54 | CCERR_INVALID_SRQ = 14, | ||
55 | CCERR_INVALID_ADDRESS = 15, | ||
56 | CCERR_INVALID_NETMASK = 16, | ||
57 | CCERR_INVALID_QP = 17, | ||
58 | CCERR_INVALID_QP_STATE = 18, | ||
59 | CCERR_TOO_MANY_WRS_POSTED = 19, | ||
60 | CCERR_INVALID_WR_TYPE = 20, | ||
61 | CCERR_INVALID_SGL_LENGTH = 21, | ||
62 | CCERR_INVALID_SQ_DEPTH = 22, | ||
63 | CCERR_INVALID_RQ_DEPTH = 23, | ||
64 | CCERR_INVALID_ORD = 24, | ||
65 | CCERR_INVALID_IRD = 25, | ||
66 | CCERR_QP_ATTR_CANNOT_CHANGE = 26, | ||
67 | CCERR_INVALID_STAG = 27, | ||
68 | CCERR_QP_IN_USE = 28, | ||
69 | CCERR_OUTSTANDING_WRS = 29, | ||
70 | CCERR_STAG_IN_USE = 30, | ||
71 | CCERR_INVALID_STAG_INDEX = 31, | ||
72 | CCERR_INVALID_SGL_FORMAT = 32, | ||
73 | CCERR_ADAPTER_TIMEOUT = 33, | ||
74 | CCERR_INVALID_CQ_DEPTH = 34, | ||
75 | CCERR_INVALID_PRIVATE_DATA_LENGTH = 35, | ||
76 | CCERR_INVALID_EP = 36, | ||
77 | CCERR_MR_IN_USE = CCERR_STAG_IN_USE, | ||
78 | CCERR_FLUSHED = 38, | ||
79 | CCERR_INVALID_WQE = 39, | ||
80 | CCERR_LOCAL_QP_CATASTROPHIC_ERROR = 40, | ||
81 | CCERR_REMOTE_TERMINATION_ERROR = 41, | ||
82 | CCERR_BASE_AND_BOUNDS_VIOLATION = 42, | ||
83 | CCERR_ACCESS_VIOLATION = 43, | ||
84 | CCERR_INVALID_PD_ID = 44, | ||
85 | CCERR_WRAP_ERROR = 45, | ||
86 | CCERR_INV_STAG_ACCESS_ERROR = 46, | ||
87 | CCERR_ZERO_RDMA_READ_RESOURCES = 47, | ||
88 | CCERR_QP_NOT_PRIVILEGED = 48, | ||
89 | CCERR_STAG_STATE_NOT_INVALID = 49, | ||
90 | CCERR_INVALID_PAGE_SIZE = 50, | ||
91 | CCERR_INVALID_BUFFER_SIZE = 51, | ||
92 | CCERR_INVALID_PBE = 52, | ||
93 | CCERR_INVALID_FBO = 53, | ||
94 | CCERR_INVALID_LENGTH = 54, | ||
95 | CCERR_INVALID_ACCESS_RIGHTS = 55, | ||
96 | CCERR_PBL_TOO_BIG = 56, | ||
97 | CCERR_INVALID_VA = 57, | ||
98 | CCERR_INVALID_REGION = 58, | ||
99 | CCERR_INVALID_WINDOW = 59, | ||
100 | CCERR_TOTAL_LENGTH_TOO_BIG = 60, | ||
101 | CCERR_INVALID_QP_ID = 61, | ||
102 | CCERR_ADDR_IN_USE = 62, | ||
103 | CCERR_ADDR_NOT_AVAIL = 63, | ||
104 | CCERR_NET_DOWN = 64, | ||
105 | CCERR_NET_UNREACHABLE = 65, | ||
106 | CCERR_CONN_ABORTED = 66, | ||
107 | CCERR_CONN_RESET = 67, | ||
108 | CCERR_NO_BUFS = 68, | ||
109 | CCERR_CONN_TIMEDOUT = 69, | ||
110 | CCERR_CONN_REFUSED = 70, | ||
111 | CCERR_HOST_UNREACHABLE = 71, | ||
112 | CCERR_INVALID_SEND_SGL_DEPTH = 72, | ||
113 | CCERR_INVALID_RECV_SGL_DEPTH = 73, | ||
114 | CCERR_INVALID_RDMA_WRITE_SGL_DEPTH = 74, | ||
115 | CCERR_INSUFFICIENT_PRIVILEGES = 75, | ||
116 | CCERR_STACK_ERROR = 76, | ||
117 | CCERR_INVALID_VERSION = 77, | ||
118 | CCERR_INVALID_MTU = 78, | ||
119 | CCERR_INVALID_IMAGE = 79, | ||
120 | CCERR_PENDING = 98, /* not an error; user internally by adapter */ | ||
121 | CCERR_DEFER = 99, /* not an error; used internally by adapter */ | ||
122 | CCERR_FAILED_WRITE = 100, | ||
123 | CCERR_FAILED_ERASE = 101, | ||
124 | CCERR_FAILED_VERIFICATION = 102, | ||
125 | CCERR_NOT_FOUND = 103, | ||
126 | |||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * CCAE_ACTIVE_CONNECT_RESULTS status result codes. | ||
131 | */ | ||
132 | enum c2_connect_status { | ||
133 | C2_CONN_STATUS_SUCCESS = C2_OK, | ||
134 | C2_CONN_STATUS_NO_MEM = CCERR_INSUFFICIENT_RESOURCES, | ||
135 | C2_CONN_STATUS_TIMEDOUT = CCERR_CONN_TIMEDOUT, | ||
136 | C2_CONN_STATUS_REFUSED = CCERR_CONN_REFUSED, | ||
137 | C2_CONN_STATUS_NETUNREACH = CCERR_NET_UNREACHABLE, | ||
138 | C2_CONN_STATUS_HOSTUNREACH = CCERR_HOST_UNREACHABLE, | ||
139 | C2_CONN_STATUS_INVALID_RNIC = CCERR_INVALID_RNIC, | ||
140 | C2_CONN_STATUS_INVALID_QP = CCERR_INVALID_QP, | ||
141 | C2_CONN_STATUS_INVALID_QP_STATE = CCERR_INVALID_QP_STATE, | ||
142 | C2_CONN_STATUS_REJECTED = CCERR_CONN_RESET, | ||
143 | C2_CONN_STATUS_ADDR_NOT_AVAIL = CCERR_ADDR_NOT_AVAIL, | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * Flash programming status codes. | ||
148 | */ | ||
149 | enum c2_flash_status { | ||
150 | C2_FLASH_STATUS_SUCCESS = 0x0000, | ||
151 | C2_FLASH_STATUS_VERIFY_ERR = 0x0002, | ||
152 | C2_FLASH_STATUS_IMAGE_ERR = 0x0004, | ||
153 | C2_FLASH_STATUS_ECLBS = 0x0400, | ||
154 | C2_FLASH_STATUS_PSLBS = 0x0800, | ||
155 | C2_FLASH_STATUS_VPENS = 0x1000, | ||
156 | }; | ||
157 | |||
158 | #endif /* _C2_STATUS_H_ */ | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_user.h b/drivers/infiniband/hw/amso1100/c2_user.h new file mode 100644 index 000000000000..7e9e7ad65467 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_user.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Topspin Communications. All rights reserved. | ||
3 | * Copyright (c) 2005 Cisco Systems. All rights reserved. | ||
4 | * Copyright (c) 2005 Open Grid Computing, 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 | |||
36 | #ifndef C2_USER_H | ||
37 | #define C2_USER_H | ||
38 | |||
39 | #include <linux/types.h> | ||
40 | |||
41 | /* | ||
42 | * Make sure that all structs defined in this file remain laid out so | ||
43 | * that they pack the same way on 32-bit and 64-bit architectures (to | ||
44 | * avoid incompatibility between 32-bit userspace and 64-bit kernels). | ||
45 | * In particular do not use pointer types -- pass pointers in __u64 | ||
46 | * instead. | ||
47 | */ | ||
48 | |||
49 | struct c2_alloc_ucontext_resp { | ||
50 | __u32 qp_tab_size; | ||
51 | __u32 uarc_size; | ||
52 | }; | ||
53 | |||
54 | struct c2_alloc_pd_resp { | ||
55 | __u32 pdn; | ||
56 | __u32 reserved; | ||
57 | }; | ||
58 | |||
59 | struct c2_create_cq { | ||
60 | __u32 lkey; | ||
61 | __u32 pdn; | ||
62 | __u64 arm_db_page; | ||
63 | __u64 set_db_page; | ||
64 | __u32 arm_db_index; | ||
65 | __u32 set_db_index; | ||
66 | }; | ||
67 | |||
68 | struct c2_create_cq_resp { | ||
69 | __u32 cqn; | ||
70 | __u32 reserved; | ||
71 | }; | ||
72 | |||
73 | struct c2_create_qp { | ||
74 | __u32 lkey; | ||
75 | __u32 reserved; | ||
76 | __u64 sq_db_page; | ||
77 | __u64 rq_db_page; | ||
78 | __u32 sq_db_index; | ||
79 | __u32 rq_db_index; | ||
80 | }; | ||
81 | |||
82 | #endif /* C2_USER_H */ | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c new file mode 100644 index 000000000000..40caeb5f41b4 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_vq.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/spinlock.h> | ||
35 | |||
36 | #include "c2_vq.h" | ||
37 | #include "c2_provider.h" | ||
38 | |||
39 | /* | ||
40 | * Verbs Request Objects: | ||
41 | * | ||
42 | * VQ Request Objects are allocated by the kernel verbs handlers. | ||
43 | * They contain a wait object, a refcnt, an atomic bool indicating that the | ||
44 | * adapter has replied, and a copy of the verb reply work request. | ||
45 | * A pointer to the VQ Request Object is passed down in the context | ||
46 | * field of the work request message, and reflected back by the adapter | ||
47 | * in the verbs reply message. The function handle_vq() in the interrupt | ||
48 | * path will use this pointer to: | ||
49 | * 1) append a copy of the verbs reply message | ||
50 | * 2) mark that the reply is ready | ||
51 | * 3) wake up the kernel verbs handler blocked awaiting the reply. | ||
52 | * | ||
53 | * | ||
54 | * The kernel verbs handlers do a "get" to put a 2nd reference on the | ||
55 | * VQ Request object. If the kernel verbs handler exits before the adapter | ||
56 | * can respond, this extra reference will keep the VQ Request object around | ||
57 | * until the adapter's reply can be processed. The reason we need this is | ||
58 | * because a pointer to this object is stuffed into the context field of | ||
59 | * the verbs work request message, and reflected back in the reply message. | ||
60 | * It is used in the interrupt handler (handle_vq()) to wake up the appropriate | ||
61 | * kernel verb handler that is blocked awaiting the verb reply. | ||
62 | * So handle_vq() will do a "put" on the object when it's done accessing it. | ||
63 | * NOTE: If we guarantee that the kernel verb handler will never bail before | ||
64 | * getting the reply, then we don't need these refcnts. | ||
65 | * | ||
66 | * | ||
67 | * VQ Request objects are freed by the kernel verbs handlers only | ||
68 | * after the verb has been processed, or when the adapter fails and | ||
69 | * does not reply. | ||
70 | * | ||
71 | * | ||
72 | * Verbs Reply Buffers: | ||
73 | * | ||
74 | * VQ Reply bufs are local host memory copies of a | ||
75 | * outstanding Verb Request reply | ||
76 | * message. The are always allocated by the kernel verbs handlers, and _may_ be | ||
77 | * freed by either the kernel verbs handler -or- the interrupt handler. The | ||
78 | * kernel verbs handler _must_ free the repbuf, then free the vq request object | ||
79 | * in that order. | ||
80 | */ | ||
81 | |||
82 | int vq_init(struct c2_dev *c2dev) | ||
83 | { | ||
84 | sprintf(c2dev->vq_cache_name, "c2-vq:dev%c", | ||
85 | (char) ('0' + c2dev->devnum)); | ||
86 | c2dev->host_msg_cache = | ||
87 | kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0, | ||
88 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
89 | if (c2dev->host_msg_cache == NULL) { | ||
90 | return -ENOMEM; | ||
91 | } | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | void vq_term(struct c2_dev *c2dev) | ||
96 | { | ||
97 | kmem_cache_destroy(c2dev->host_msg_cache); | ||
98 | } | ||
99 | |||
100 | /* vq_req_alloc - allocate a VQ Request Object and initialize it. | ||
101 | * The refcnt is set to 1. | ||
102 | */ | ||
103 | struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev) | ||
104 | { | ||
105 | struct c2_vq_req *r; | ||
106 | |||
107 | r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL); | ||
108 | if (r) { | ||
109 | init_waitqueue_head(&r->wait_object); | ||
110 | r->reply_msg = (u64) NULL; | ||
111 | r->event = 0; | ||
112 | r->cm_id = NULL; | ||
113 | r->qp = NULL; | ||
114 | atomic_set(&r->refcnt, 1); | ||
115 | atomic_set(&r->reply_ready, 0); | ||
116 | } | ||
117 | return r; | ||
118 | } | ||
119 | |||
120 | |||
121 | /* vq_req_free - free the VQ Request Object. It is assumed the verbs handler | ||
122 | * has already free the VQ Reply Buffer if it existed. | ||
123 | */ | ||
124 | void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r) | ||
125 | { | ||
126 | r->reply_msg = (u64) NULL; | ||
127 | if (atomic_dec_and_test(&r->refcnt)) { | ||
128 | kfree(r); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* vq_req_get - reference a VQ Request Object. Done | ||
133 | * only in the kernel verbs handlers. | ||
134 | */ | ||
135 | void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r) | ||
136 | { | ||
137 | atomic_inc(&r->refcnt); | ||
138 | } | ||
139 | |||
140 | |||
141 | /* vq_req_put - dereference and potentially free a VQ Request Object. | ||
142 | * | ||
143 | * This is only called by handle_vq() on the | ||
144 | * interrupt when it is done processing | ||
145 | * a verb reply message. If the associated | ||
146 | * kernel verbs handler has already bailed, | ||
147 | * then this put will actually free the VQ | ||
148 | * Request object _and_ the VQ Reply Buffer | ||
149 | * if it exists. | ||
150 | */ | ||
151 | void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r) | ||
152 | { | ||
153 | if (atomic_dec_and_test(&r->refcnt)) { | ||
154 | if (r->reply_msg != (u64) NULL) | ||
155 | vq_repbuf_free(c2dev, | ||
156 | (void *) (unsigned long) r->reply_msg); | ||
157 | kfree(r); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | |||
162 | /* | ||
163 | * vq_repbuf_alloc - allocate a VQ Reply Buffer. | ||
164 | */ | ||
165 | void *vq_repbuf_alloc(struct c2_dev *c2dev) | ||
166 | { | ||
167 | return kmem_cache_alloc(c2dev->host_msg_cache, SLAB_ATOMIC); | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * vq_send_wr - post a verbs request message to the Verbs Request Queue. | ||
172 | * If a message is not available in the MQ, then block until one is available. | ||
173 | * NOTE: handle_mq() on the interrupt context will wake up threads blocked here. | ||
174 | * When the adapter drains the Verbs Request Queue, | ||
175 | * it inserts MQ index 0 in to the | ||
176 | * adapter->host activity fifo and interrupts the host. | ||
177 | */ | ||
178 | int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr) | ||
179 | { | ||
180 | void *msg; | ||
181 | wait_queue_t __wait; | ||
182 | |||
183 | /* | ||
184 | * grab adapter vq lock | ||
185 | */ | ||
186 | spin_lock(&c2dev->vqlock); | ||
187 | |||
188 | /* | ||
189 | * allocate msg | ||
190 | */ | ||
191 | msg = c2_mq_alloc(&c2dev->req_vq); | ||
192 | |||
193 | /* | ||
194 | * If we cannot get a msg, then we'll wait | ||
195 | * When a messages are available, the int handler will wake_up() | ||
196 | * any waiters. | ||
197 | */ | ||
198 | while (msg == NULL) { | ||
199 | pr_debug("%s:%d no available msg in VQ, waiting...\n", | ||
200 | __FUNCTION__, __LINE__); | ||
201 | init_waitqueue_entry(&__wait, current); | ||
202 | add_wait_queue(&c2dev->req_vq_wo, &__wait); | ||
203 | spin_unlock(&c2dev->vqlock); | ||
204 | for (;;) { | ||
205 | set_current_state(TASK_INTERRUPTIBLE); | ||
206 | if (!c2_mq_full(&c2dev->req_vq)) { | ||
207 | break; | ||
208 | } | ||
209 | if (!signal_pending(current)) { | ||
210 | schedule_timeout(1 * HZ); /* 1 second... */ | ||
211 | continue; | ||
212 | } | ||
213 | set_current_state(TASK_RUNNING); | ||
214 | remove_wait_queue(&c2dev->req_vq_wo, &__wait); | ||
215 | return -EINTR; | ||
216 | } | ||
217 | set_current_state(TASK_RUNNING); | ||
218 | remove_wait_queue(&c2dev->req_vq_wo, &__wait); | ||
219 | spin_lock(&c2dev->vqlock); | ||
220 | msg = c2_mq_alloc(&c2dev->req_vq); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * copy wr into adapter msg | ||
225 | */ | ||
226 | memcpy(msg, wr, c2dev->req_vq.msg_size); | ||
227 | |||
228 | /* | ||
229 | * post msg | ||
230 | */ | ||
231 | c2_mq_produce(&c2dev->req_vq); | ||
232 | |||
233 | /* | ||
234 | * release adapter vq lock | ||
235 | */ | ||
236 | spin_unlock(&c2dev->vqlock); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | |||
241 | /* | ||
242 | * vq_wait_for_reply - block until the adapter posts a Verb Reply Message. | ||
243 | */ | ||
244 | int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req) | ||
245 | { | ||
246 | if (!wait_event_timeout(req->wait_object, | ||
247 | atomic_read(&req->reply_ready), | ||
248 | 60*HZ)) | ||
249 | return -ETIMEDOUT; | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * vq_repbuf_free - Free a Verbs Reply Buffer. | ||
256 | */ | ||
257 | void vq_repbuf_free(struct c2_dev *c2dev, void *reply) | ||
258 | { | ||
259 | kmem_cache_free(c2dev->host_msg_cache, reply); | ||
260 | } | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.h b/drivers/infiniband/hw/amso1100/c2_vq.h new file mode 100644 index 000000000000..33805627a607 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_vq.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #ifndef _C2_VQ_H_ | ||
34 | #define _C2_VQ_H_ | ||
35 | #include <linux/sched.h> | ||
36 | #include "c2.h" | ||
37 | #include "c2_wr.h" | ||
38 | #include "c2_provider.h" | ||
39 | |||
40 | struct c2_vq_req { | ||
41 | u64 reply_msg; /* ptr to reply msg */ | ||
42 | wait_queue_head_t wait_object; /* wait object for vq reqs */ | ||
43 | atomic_t reply_ready; /* set when reply is ready */ | ||
44 | atomic_t refcnt; /* used to cancel WRs... */ | ||
45 | int event; | ||
46 | struct iw_cm_id *cm_id; | ||
47 | struct c2_qp *qp; | ||
48 | }; | ||
49 | |||
50 | extern int vq_init(struct c2_dev *c2dev); | ||
51 | extern void vq_term(struct c2_dev *c2dev); | ||
52 | |||
53 | extern struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev); | ||
54 | extern void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *req); | ||
55 | extern void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *req); | ||
56 | extern void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *req); | ||
57 | extern int vq_send_wr(struct c2_dev *c2dev, union c2wr * wr); | ||
58 | |||
59 | extern void *vq_repbuf_alloc(struct c2_dev *c2dev); | ||
60 | extern void vq_repbuf_free(struct c2_dev *c2dev, void *reply); | ||
61 | |||
62 | extern int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req); | ||
63 | #endif /* _C2_VQ_H_ */ | ||
diff --git a/drivers/infiniband/hw/amso1100/c2_wr.h b/drivers/infiniband/hw/amso1100/c2_wr.h new file mode 100644 index 000000000000..3ec6c43bb0ef --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_wr.h | |||
@@ -0,0 +1,1520 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | #ifndef _C2_WR_H_ | ||
34 | #define _C2_WR_H_ | ||
35 | |||
36 | #ifdef CCDEBUG | ||
37 | #define CCWR_MAGIC 0xb07700b0 | ||
38 | #endif | ||
39 | |||
40 | #define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF | ||
41 | |||
42 | /* Maximum allowed size in bytes of private_data exchange | ||
43 | * on connect. | ||
44 | */ | ||
45 | #define C2_MAX_PRIVATE_DATA_SIZE 200 | ||
46 | |||
47 | /* | ||
48 | * These types are shared among the adapter, host, and CCIL consumer. | ||
49 | */ | ||
50 | enum c2_cq_notification_type { | ||
51 | C2_CQ_NOTIFICATION_TYPE_NONE = 1, | ||
52 | C2_CQ_NOTIFICATION_TYPE_NEXT, | ||
53 | C2_CQ_NOTIFICATION_TYPE_NEXT_SE | ||
54 | }; | ||
55 | |||
56 | enum c2_setconfig_cmd { | ||
57 | C2_CFG_ADD_ADDR = 1, | ||
58 | C2_CFG_DEL_ADDR = 2, | ||
59 | C2_CFG_ADD_ROUTE = 3, | ||
60 | C2_CFG_DEL_ROUTE = 4 | ||
61 | }; | ||
62 | |||
63 | enum c2_getconfig_cmd { | ||
64 | C2_GETCONFIG_ROUTES = 1, | ||
65 | C2_GETCONFIG_ADDRS | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * CCIL Work Request Identifiers | ||
70 | */ | ||
71 | enum c2wr_ids { | ||
72 | CCWR_RNIC_OPEN = 1, | ||
73 | CCWR_RNIC_QUERY, | ||
74 | CCWR_RNIC_SETCONFIG, | ||
75 | CCWR_RNIC_GETCONFIG, | ||
76 | CCWR_RNIC_CLOSE, | ||
77 | CCWR_CQ_CREATE, | ||
78 | CCWR_CQ_QUERY, | ||
79 | CCWR_CQ_MODIFY, | ||
80 | CCWR_CQ_DESTROY, | ||
81 | CCWR_QP_CONNECT, | ||
82 | CCWR_PD_ALLOC, | ||
83 | CCWR_PD_DEALLOC, | ||
84 | CCWR_SRQ_CREATE, | ||
85 | CCWR_SRQ_QUERY, | ||
86 | CCWR_SRQ_MODIFY, | ||
87 | CCWR_SRQ_DESTROY, | ||
88 | CCWR_QP_CREATE, | ||
89 | CCWR_QP_QUERY, | ||
90 | CCWR_QP_MODIFY, | ||
91 | CCWR_QP_DESTROY, | ||
92 | CCWR_NSMR_STAG_ALLOC, | ||
93 | CCWR_NSMR_REGISTER, | ||
94 | CCWR_NSMR_PBL, | ||
95 | CCWR_STAG_DEALLOC, | ||
96 | CCWR_NSMR_REREGISTER, | ||
97 | CCWR_SMR_REGISTER, | ||
98 | CCWR_MR_QUERY, | ||
99 | CCWR_MW_ALLOC, | ||
100 | CCWR_MW_QUERY, | ||
101 | CCWR_EP_CREATE, | ||
102 | CCWR_EP_GETOPT, | ||
103 | CCWR_EP_SETOPT, | ||
104 | CCWR_EP_DESTROY, | ||
105 | CCWR_EP_BIND, | ||
106 | CCWR_EP_CONNECT, | ||
107 | CCWR_EP_LISTEN, | ||
108 | CCWR_EP_SHUTDOWN, | ||
109 | CCWR_EP_LISTEN_CREATE, | ||
110 | CCWR_EP_LISTEN_DESTROY, | ||
111 | CCWR_EP_QUERY, | ||
112 | CCWR_CR_ACCEPT, | ||
113 | CCWR_CR_REJECT, | ||
114 | CCWR_CONSOLE, | ||
115 | CCWR_TERM, | ||
116 | CCWR_FLASH_INIT, | ||
117 | CCWR_FLASH, | ||
118 | CCWR_BUF_ALLOC, | ||
119 | CCWR_BUF_FREE, | ||
120 | CCWR_FLASH_WRITE, | ||
121 | CCWR_INIT, /* WARNING: Don't move this ever again! */ | ||
122 | |||
123 | |||
124 | |||
125 | /* Add new IDs here */ | ||
126 | |||
127 | |||
128 | |||
129 | /* | ||
130 | * WARNING: CCWR_LAST must always be the last verbs id defined! | ||
131 | * All the preceding IDs are fixed, and must not change. | ||
132 | * You can add new IDs, but must not remove or reorder | ||
133 | * any IDs. If you do, YOU will ruin any hope of | ||
134 | * compatability between versions. | ||
135 | */ | ||
136 | CCWR_LAST, | ||
137 | |||
138 | /* | ||
139 | * Start over at 1 so that arrays indexed by user wr id's | ||
140 | * begin at 1. This is OK since the verbs and user wr id's | ||
141 | * are always used on disjoint sets of queues. | ||
142 | */ | ||
143 | /* | ||
144 | * The order of the CCWR_SEND_XX verbs must | ||
145 | * match the order of the RDMA_OPs | ||
146 | */ | ||
147 | CCWR_SEND = 1, | ||
148 | CCWR_SEND_INV, | ||
149 | CCWR_SEND_SE, | ||
150 | CCWR_SEND_SE_INV, | ||
151 | CCWR_RDMA_WRITE, | ||
152 | CCWR_RDMA_READ, | ||
153 | CCWR_RDMA_READ_INV, | ||
154 | CCWR_MW_BIND, | ||
155 | CCWR_NSMR_FASTREG, | ||
156 | CCWR_STAG_INVALIDATE, | ||
157 | CCWR_RECV, | ||
158 | CCWR_NOP, | ||
159 | CCWR_UNIMPL, | ||
160 | /* WARNING: This must always be the last user wr id defined! */ | ||
161 | }; | ||
162 | #define RDMA_SEND_OPCODE_FROM_WR_ID(x) (x+2) | ||
163 | |||
164 | /* | ||
165 | * SQ/RQ Work Request Types | ||
166 | */ | ||
167 | enum c2_wr_type { | ||
168 | C2_WR_TYPE_SEND = CCWR_SEND, | ||
169 | C2_WR_TYPE_SEND_SE = CCWR_SEND_SE, | ||
170 | C2_WR_TYPE_SEND_INV = CCWR_SEND_INV, | ||
171 | C2_WR_TYPE_SEND_SE_INV = CCWR_SEND_SE_INV, | ||
172 | C2_WR_TYPE_RDMA_WRITE = CCWR_RDMA_WRITE, | ||
173 | C2_WR_TYPE_RDMA_READ = CCWR_RDMA_READ, | ||
174 | C2_WR_TYPE_RDMA_READ_INV_STAG = CCWR_RDMA_READ_INV, | ||
175 | C2_WR_TYPE_BIND_MW = CCWR_MW_BIND, | ||
176 | C2_WR_TYPE_FASTREG_NSMR = CCWR_NSMR_FASTREG, | ||
177 | C2_WR_TYPE_INV_STAG = CCWR_STAG_INVALIDATE, | ||
178 | C2_WR_TYPE_RECV = CCWR_RECV, | ||
179 | C2_WR_TYPE_NOP = CCWR_NOP, | ||
180 | }; | ||
181 | |||
182 | struct c2_netaddr { | ||
183 | u32 ip_addr; | ||
184 | u32 netmask; | ||
185 | u32 mtu; | ||
186 | }; | ||
187 | |||
188 | struct c2_route { | ||
189 | u32 ip_addr; /* 0 indicates the default route */ | ||
190 | u32 netmask; /* netmask associated with dst */ | ||
191 | u32 flags; | ||
192 | union { | ||
193 | u32 ipaddr; /* address of the nexthop interface */ | ||
194 | u8 enaddr[6]; | ||
195 | } nexthop; | ||
196 | }; | ||
197 | |||
198 | /* | ||
199 | * A Scatter Gather Entry. | ||
200 | */ | ||
201 | struct c2_data_addr { | ||
202 | u32 stag; | ||
203 | u32 length; | ||
204 | u64 to; | ||
205 | }; | ||
206 | |||
207 | /* | ||
208 | * MR and MW flags used by the consumer, RI, and RNIC. | ||
209 | */ | ||
210 | enum c2_mm_flags { | ||
211 | MEM_REMOTE = 0x0001, /* allow mw binds with remote access. */ | ||
212 | MEM_VA_BASED = 0x0002, /* Not Zero-based */ | ||
213 | MEM_PBL_COMPLETE = 0x0004, /* PBL array is complete in this msg */ | ||
214 | MEM_LOCAL_READ = 0x0008, /* allow local reads */ | ||
215 | MEM_LOCAL_WRITE = 0x0010, /* allow local writes */ | ||
216 | MEM_REMOTE_READ = 0x0020, /* allow remote reads */ | ||
217 | MEM_REMOTE_WRITE = 0x0040, /* allow remote writes */ | ||
218 | MEM_WINDOW_BIND = 0x0080, /* binds allowed */ | ||
219 | MEM_SHARED = 0x0100, /* set if MR is shared */ | ||
220 | MEM_STAG_VALID = 0x0200 /* set if STAG is in valid state */ | ||
221 | }; | ||
222 | |||
223 | /* | ||
224 | * CCIL API ACF flags defined in terms of the low level mem flags. | ||
225 | * This minimizes translation needed in the user API | ||
226 | */ | ||
227 | enum c2_acf { | ||
228 | C2_ACF_LOCAL_READ = MEM_LOCAL_READ, | ||
229 | C2_ACF_LOCAL_WRITE = MEM_LOCAL_WRITE, | ||
230 | C2_ACF_REMOTE_READ = MEM_REMOTE_READ, | ||
231 | C2_ACF_REMOTE_WRITE = MEM_REMOTE_WRITE, | ||
232 | C2_ACF_WINDOW_BIND = MEM_WINDOW_BIND | ||
233 | }; | ||
234 | |||
235 | /* | ||
236 | * Image types of objects written to flash | ||
237 | */ | ||
238 | #define C2_FLASH_IMG_BITFILE 1 | ||
239 | #define C2_FLASH_IMG_OPTION_ROM 2 | ||
240 | #define C2_FLASH_IMG_VPD 3 | ||
241 | |||
242 | /* | ||
243 | * to fix bug 1815 we define the max size allowable of the | ||
244 | * terminate message (per the IETF spec).Refer to the IETF | ||
245 | * protocal specification, section 12.1.6, page 64) | ||
246 | * The message is prefixed by 20 types of DDP info. | ||
247 | * | ||
248 | * Then the message has 6 bytes for the terminate control | ||
249 | * and DDP segment length info plus a DDP header (either | ||
250 | * 14 or 18 byts) plus 28 bytes for the RDMA header. | ||
251 | * Thus the max size in: | ||
252 | * 20 + (6 + 18 + 28) = 72 | ||
253 | */ | ||
254 | #define C2_MAX_TERMINATE_MESSAGE_SIZE (72) | ||
255 | |||
256 | /* | ||
257 | * Build String Length. It must be the same as C2_BUILD_STR_LEN in ccil_api.h | ||
258 | */ | ||
259 | #define WR_BUILD_STR_LEN 64 | ||
260 | |||
261 | /* | ||
262 | * WARNING: All of these structs need to align any 64bit types on | ||
263 | * 64 bit boundaries! 64bit types include u64 and u64. | ||
264 | */ | ||
265 | |||
266 | /* | ||
267 | * Clustercore Work Request Header. Be sensitive to field layout | ||
268 | * and alignment. | ||
269 | */ | ||
270 | struct c2wr_hdr { | ||
271 | /* wqe_count is part of the cqe. It is put here so the | ||
272 | * adapter can write to it while the wr is pending without | ||
273 | * clobbering part of the wr. This word need not be dma'd | ||
274 | * from the host to adapter by libccil, but we copy it anyway | ||
275 | * to make the memcpy to the adapter better aligned. | ||
276 | */ | ||
277 | u32 wqe_count; | ||
278 | |||
279 | /* Put these fields next so that later 32- and 64-bit | ||
280 | * quantities are naturally aligned. | ||
281 | */ | ||
282 | u8 id; | ||
283 | u8 result; /* adapter -> host */ | ||
284 | u8 sge_count; /* host -> adapter */ | ||
285 | u8 flags; /* host -> adapter */ | ||
286 | |||
287 | u64 context; | ||
288 | #ifdef CCMSGMAGIC | ||
289 | u32 magic; | ||
290 | u32 pad; | ||
291 | #endif | ||
292 | } __attribute__((packed)); | ||
293 | |||
294 | /* | ||
295 | *------------------------ RNIC ------------------------ | ||
296 | */ | ||
297 | |||
298 | /* | ||
299 | * WR_RNIC_OPEN | ||
300 | */ | ||
301 | |||
302 | /* | ||
303 | * Flags for the RNIC WRs | ||
304 | */ | ||
305 | enum c2_rnic_flags { | ||
306 | RNIC_IRD_STATIC = 0x0001, | ||
307 | RNIC_ORD_STATIC = 0x0002, | ||
308 | RNIC_QP_STATIC = 0x0004, | ||
309 | RNIC_SRQ_SUPPORTED = 0x0008, | ||
310 | RNIC_PBL_BLOCK_MODE = 0x0010, | ||
311 | RNIC_SRQ_MODEL_ARRIVAL = 0x0020, | ||
312 | RNIC_CQ_OVF_DETECTED = 0x0040, | ||
313 | RNIC_PRIV_MODE = 0x0080 | ||
314 | }; | ||
315 | |||
316 | struct c2wr_rnic_open_req { | ||
317 | struct c2wr_hdr hdr; | ||
318 | u64 user_context; | ||
319 | u16 flags; /* See enum c2_rnic_flags */ | ||
320 | u16 port_num; | ||
321 | } __attribute__((packed)); | ||
322 | |||
323 | struct c2wr_rnic_open_rep { | ||
324 | struct c2wr_hdr hdr; | ||
325 | u32 rnic_handle; | ||
326 | } __attribute__((packed)); | ||
327 | |||
328 | union c2wr_rnic_open { | ||
329 | struct c2wr_rnic_open_req req; | ||
330 | struct c2wr_rnic_open_rep rep; | ||
331 | } __attribute__((packed)); | ||
332 | |||
333 | struct c2wr_rnic_query_req { | ||
334 | struct c2wr_hdr hdr; | ||
335 | u32 rnic_handle; | ||
336 | } __attribute__((packed)); | ||
337 | |||
338 | /* | ||
339 | * WR_RNIC_QUERY | ||
340 | */ | ||
341 | struct c2wr_rnic_query_rep { | ||
342 | struct c2wr_hdr hdr; | ||
343 | u64 user_context; | ||
344 | u32 vendor_id; | ||
345 | u32 part_number; | ||
346 | u32 hw_version; | ||
347 | u32 fw_ver_major; | ||
348 | u32 fw_ver_minor; | ||
349 | u32 fw_ver_patch; | ||
350 | char fw_ver_build_str[WR_BUILD_STR_LEN]; | ||
351 | u32 max_qps; | ||
352 | u32 max_qp_depth; | ||
353 | u32 max_srq_depth; | ||
354 | u32 max_send_sgl_depth; | ||
355 | u32 max_rdma_sgl_depth; | ||
356 | u32 max_cqs; | ||
357 | u32 max_cq_depth; | ||
358 | u32 max_cq_event_handlers; | ||
359 | u32 max_mrs; | ||
360 | u32 max_pbl_depth; | ||
361 | u32 max_pds; | ||
362 | u32 max_global_ird; | ||
363 | u32 max_global_ord; | ||
364 | u32 max_qp_ird; | ||
365 | u32 max_qp_ord; | ||
366 | u32 flags; | ||
367 | u32 max_mws; | ||
368 | u32 pbe_range_low; | ||
369 | u32 pbe_range_high; | ||
370 | u32 max_srqs; | ||
371 | u32 page_size; | ||
372 | } __attribute__((packed)); | ||
373 | |||
374 | union c2wr_rnic_query { | ||
375 | struct c2wr_rnic_query_req req; | ||
376 | struct c2wr_rnic_query_rep rep; | ||
377 | } __attribute__((packed)); | ||
378 | |||
379 | /* | ||
380 | * WR_RNIC_GETCONFIG | ||
381 | */ | ||
382 | |||
383 | struct c2wr_rnic_getconfig_req { | ||
384 | struct c2wr_hdr hdr; | ||
385 | u32 rnic_handle; | ||
386 | u32 option; /* see c2_getconfig_cmd_t */ | ||
387 | u64 reply_buf; | ||
388 | u32 reply_buf_len; | ||
389 | } __attribute__((packed)) ; | ||
390 | |||
391 | struct c2wr_rnic_getconfig_rep { | ||
392 | struct c2wr_hdr hdr; | ||
393 | u32 option; /* see c2_getconfig_cmd_t */ | ||
394 | u32 count_len; /* length of the number of addresses configured */ | ||
395 | } __attribute__((packed)) ; | ||
396 | |||
397 | union c2wr_rnic_getconfig { | ||
398 | struct c2wr_rnic_getconfig_req req; | ||
399 | struct c2wr_rnic_getconfig_rep rep; | ||
400 | } __attribute__((packed)) ; | ||
401 | |||
402 | /* | ||
403 | * WR_RNIC_SETCONFIG | ||
404 | */ | ||
405 | struct c2wr_rnic_setconfig_req { | ||
406 | struct c2wr_hdr hdr; | ||
407 | u32 rnic_handle; | ||
408 | u32 option; /* See c2_setconfig_cmd_t */ | ||
409 | /* variable data and pad. See c2_netaddr and c2_route */ | ||
410 | u8 data[0]; | ||
411 | } __attribute__((packed)) ; | ||
412 | |||
413 | struct c2wr_rnic_setconfig_rep { | ||
414 | struct c2wr_hdr hdr; | ||
415 | } __attribute__((packed)) ; | ||
416 | |||
417 | union c2wr_rnic_setconfig { | ||
418 | struct c2wr_rnic_setconfig_req req; | ||
419 | struct c2wr_rnic_setconfig_rep rep; | ||
420 | } __attribute__((packed)) ; | ||
421 | |||
422 | /* | ||
423 | * WR_RNIC_CLOSE | ||
424 | */ | ||
425 | struct c2wr_rnic_close_req { | ||
426 | struct c2wr_hdr hdr; | ||
427 | u32 rnic_handle; | ||
428 | } __attribute__((packed)) ; | ||
429 | |||
430 | struct c2wr_rnic_close_rep { | ||
431 | struct c2wr_hdr hdr; | ||
432 | } __attribute__((packed)) ; | ||
433 | |||
434 | union c2wr_rnic_close { | ||
435 | struct c2wr_rnic_close_req req; | ||
436 | struct c2wr_rnic_close_rep rep; | ||
437 | } __attribute__((packed)) ; | ||
438 | |||
439 | /* | ||
440 | *------------------------ CQ ------------------------ | ||
441 | */ | ||
442 | struct c2wr_cq_create_req { | ||
443 | struct c2wr_hdr hdr; | ||
444 | u64 shared_ht; | ||
445 | u64 user_context; | ||
446 | u64 msg_pool; | ||
447 | u32 rnic_handle; | ||
448 | u32 msg_size; | ||
449 | u32 depth; | ||
450 | } __attribute__((packed)) ; | ||
451 | |||
452 | struct c2wr_cq_create_rep { | ||
453 | struct c2wr_hdr hdr; | ||
454 | u32 mq_index; | ||
455 | u32 adapter_shared; | ||
456 | u32 cq_handle; | ||
457 | } __attribute__((packed)) ; | ||
458 | |||
459 | union c2wr_cq_create { | ||
460 | struct c2wr_cq_create_req req; | ||
461 | struct c2wr_cq_create_rep rep; | ||
462 | } __attribute__((packed)) ; | ||
463 | |||
464 | struct c2wr_cq_modify_req { | ||
465 | struct c2wr_hdr hdr; | ||
466 | u32 rnic_handle; | ||
467 | u32 cq_handle; | ||
468 | u32 new_depth; | ||
469 | u64 new_msg_pool; | ||
470 | } __attribute__((packed)) ; | ||
471 | |||
472 | struct c2wr_cq_modify_rep { | ||
473 | struct c2wr_hdr hdr; | ||
474 | } __attribute__((packed)) ; | ||
475 | |||
476 | union c2wr_cq_modify { | ||
477 | struct c2wr_cq_modify_req req; | ||
478 | struct c2wr_cq_modify_rep rep; | ||
479 | } __attribute__((packed)) ; | ||
480 | |||
481 | struct c2wr_cq_destroy_req { | ||
482 | struct c2wr_hdr hdr; | ||
483 | u32 rnic_handle; | ||
484 | u32 cq_handle; | ||
485 | } __attribute__((packed)) ; | ||
486 | |||
487 | struct c2wr_cq_destroy_rep { | ||
488 | struct c2wr_hdr hdr; | ||
489 | } __attribute__((packed)) ; | ||
490 | |||
491 | union c2wr_cq_destroy { | ||
492 | struct c2wr_cq_destroy_req req; | ||
493 | struct c2wr_cq_destroy_rep rep; | ||
494 | } __attribute__((packed)) ; | ||
495 | |||
496 | /* | ||
497 | *------------------------ PD ------------------------ | ||
498 | */ | ||
499 | struct c2wr_pd_alloc_req { | ||
500 | struct c2wr_hdr hdr; | ||
501 | u32 rnic_handle; | ||
502 | u32 pd_id; | ||
503 | } __attribute__((packed)) ; | ||
504 | |||
505 | struct c2wr_pd_alloc_rep { | ||
506 | struct c2wr_hdr hdr; | ||
507 | } __attribute__((packed)) ; | ||
508 | |||
509 | union c2wr_pd_alloc { | ||
510 | struct c2wr_pd_alloc_req req; | ||
511 | struct c2wr_pd_alloc_rep rep; | ||
512 | } __attribute__((packed)) ; | ||
513 | |||
514 | struct c2wr_pd_dealloc_req { | ||
515 | struct c2wr_hdr hdr; | ||
516 | u32 rnic_handle; | ||
517 | u32 pd_id; | ||
518 | } __attribute__((packed)) ; | ||
519 | |||
520 | struct c2wr_pd_dealloc_rep { | ||
521 | struct c2wr_hdr hdr; | ||
522 | } __attribute__((packed)) ; | ||
523 | |||
524 | union c2wr_pd_dealloc { | ||
525 | struct c2wr_pd_dealloc_req req; | ||
526 | struct c2wr_pd_dealloc_rep rep; | ||
527 | } __attribute__((packed)) ; | ||
528 | |||
529 | /* | ||
530 | *------------------------ SRQ ------------------------ | ||
531 | */ | ||
532 | struct c2wr_srq_create_req { | ||
533 | struct c2wr_hdr hdr; | ||
534 | u64 shared_ht; | ||
535 | u64 user_context; | ||
536 | u32 rnic_handle; | ||
537 | u32 srq_depth; | ||
538 | u32 srq_limit; | ||
539 | u32 sgl_depth; | ||
540 | u32 pd_id; | ||
541 | } __attribute__((packed)) ; | ||
542 | |||
543 | struct c2wr_srq_create_rep { | ||
544 | struct c2wr_hdr hdr; | ||
545 | u32 srq_depth; | ||
546 | u32 sgl_depth; | ||
547 | u32 msg_size; | ||
548 | u32 mq_index; | ||
549 | u32 mq_start; | ||
550 | u32 srq_handle; | ||
551 | } __attribute__((packed)) ; | ||
552 | |||
553 | union c2wr_srq_create { | ||
554 | struct c2wr_srq_create_req req; | ||
555 | struct c2wr_srq_create_rep rep; | ||
556 | } __attribute__((packed)) ; | ||
557 | |||
558 | struct c2wr_srq_destroy_req { | ||
559 | struct c2wr_hdr hdr; | ||
560 | u32 rnic_handle; | ||
561 | u32 srq_handle; | ||
562 | } __attribute__((packed)) ; | ||
563 | |||
564 | struct c2wr_srq_destroy_rep { | ||
565 | struct c2wr_hdr hdr; | ||
566 | } __attribute__((packed)) ; | ||
567 | |||
568 | union c2wr_srq_destroy { | ||
569 | struct c2wr_srq_destroy_req req; | ||
570 | struct c2wr_srq_destroy_rep rep; | ||
571 | } __attribute__((packed)) ; | ||
572 | |||
573 | /* | ||
574 | *------------------------ QP ------------------------ | ||
575 | */ | ||
576 | enum c2wr_qp_flags { | ||
577 | QP_RDMA_READ = 0x00000001, /* RDMA read enabled? */ | ||
578 | QP_RDMA_WRITE = 0x00000002, /* RDMA write enabled? */ | ||
579 | QP_MW_BIND = 0x00000004, /* MWs enabled */ | ||
580 | QP_ZERO_STAG = 0x00000008, /* enabled? */ | ||
581 | QP_REMOTE_TERMINATION = 0x00000010, /* remote end terminated */ | ||
582 | QP_RDMA_READ_RESPONSE = 0x00000020 /* Remote RDMA read */ | ||
583 | /* enabled? */ | ||
584 | }; | ||
585 | |||
586 | struct c2wr_qp_create_req { | ||
587 | struct c2wr_hdr hdr; | ||
588 | u64 shared_sq_ht; | ||
589 | u64 shared_rq_ht; | ||
590 | u64 user_context; | ||
591 | u32 rnic_handle; | ||
592 | u32 sq_cq_handle; | ||
593 | u32 rq_cq_handle; | ||
594 | u32 sq_depth; | ||
595 | u32 rq_depth; | ||
596 | u32 srq_handle; | ||
597 | u32 srq_limit; | ||
598 | u32 flags; /* see enum c2wr_qp_flags */ | ||
599 | u32 send_sgl_depth; | ||
600 | u32 recv_sgl_depth; | ||
601 | u32 rdma_write_sgl_depth; | ||
602 | u32 ord; | ||
603 | u32 ird; | ||
604 | u32 pd_id; | ||
605 | } __attribute__((packed)) ; | ||
606 | |||
607 | struct c2wr_qp_create_rep { | ||
608 | struct c2wr_hdr hdr; | ||
609 | u32 sq_depth; | ||
610 | u32 rq_depth; | ||
611 | u32 send_sgl_depth; | ||
612 | u32 recv_sgl_depth; | ||
613 | u32 rdma_write_sgl_depth; | ||
614 | u32 ord; | ||
615 | u32 ird; | ||
616 | u32 sq_msg_size; | ||
617 | u32 sq_mq_index; | ||
618 | u32 sq_mq_start; | ||
619 | u32 rq_msg_size; | ||
620 | u32 rq_mq_index; | ||
621 | u32 rq_mq_start; | ||
622 | u32 qp_handle; | ||
623 | } __attribute__((packed)) ; | ||
624 | |||
625 | union c2wr_qp_create { | ||
626 | struct c2wr_qp_create_req req; | ||
627 | struct c2wr_qp_create_rep rep; | ||
628 | } __attribute__((packed)) ; | ||
629 | |||
630 | struct c2wr_qp_query_req { | ||
631 | struct c2wr_hdr hdr; | ||
632 | u32 rnic_handle; | ||
633 | u32 qp_handle; | ||
634 | } __attribute__((packed)) ; | ||
635 | |||
636 | struct c2wr_qp_query_rep { | ||
637 | struct c2wr_hdr hdr; | ||
638 | u64 user_context; | ||
639 | u32 rnic_handle; | ||
640 | u32 sq_depth; | ||
641 | u32 rq_depth; | ||
642 | u32 send_sgl_depth; | ||
643 | u32 rdma_write_sgl_depth; | ||
644 | u32 recv_sgl_depth; | ||
645 | u32 ord; | ||
646 | u32 ird; | ||
647 | u16 qp_state; | ||
648 | u16 flags; /* see c2wr_qp_flags_t */ | ||
649 | u32 qp_id; | ||
650 | u32 local_addr; | ||
651 | u32 remote_addr; | ||
652 | u16 local_port; | ||
653 | u16 remote_port; | ||
654 | u32 terminate_msg_length; /* 0 if not present */ | ||
655 | u8 data[0]; | ||
656 | /* Terminate Message in-line here. */ | ||
657 | } __attribute__((packed)) ; | ||
658 | |||
659 | union c2wr_qp_query { | ||
660 | struct c2wr_qp_query_req req; | ||
661 | struct c2wr_qp_query_rep rep; | ||
662 | } __attribute__((packed)) ; | ||
663 | |||
664 | struct c2wr_qp_modify_req { | ||
665 | struct c2wr_hdr hdr; | ||
666 | u64 stream_msg; | ||
667 | u32 stream_msg_length; | ||
668 | u32 rnic_handle; | ||
669 | u32 qp_handle; | ||
670 | u32 next_qp_state; | ||
671 | u32 ord; | ||
672 | u32 ird; | ||
673 | u32 sq_depth; | ||
674 | u32 rq_depth; | ||
675 | u32 llp_ep_handle; | ||
676 | } __attribute__((packed)) ; | ||
677 | |||
678 | struct c2wr_qp_modify_rep { | ||
679 | struct c2wr_hdr hdr; | ||
680 | u32 ord; | ||
681 | u32 ird; | ||
682 | u32 sq_depth; | ||
683 | u32 rq_depth; | ||
684 | u32 sq_msg_size; | ||
685 | u32 sq_mq_index; | ||
686 | u32 sq_mq_start; | ||
687 | u32 rq_msg_size; | ||
688 | u32 rq_mq_index; | ||
689 | u32 rq_mq_start; | ||
690 | } __attribute__((packed)) ; | ||
691 | |||
692 | union c2wr_qp_modify { | ||
693 | struct c2wr_qp_modify_req req; | ||
694 | struct c2wr_qp_modify_rep rep; | ||
695 | } __attribute__((packed)) ; | ||
696 | |||
697 | struct c2wr_qp_destroy_req { | ||
698 | struct c2wr_hdr hdr; | ||
699 | u32 rnic_handle; | ||
700 | u32 qp_handle; | ||
701 | } __attribute__((packed)) ; | ||
702 | |||
703 | struct c2wr_qp_destroy_rep { | ||
704 | struct c2wr_hdr hdr; | ||
705 | } __attribute__((packed)) ; | ||
706 | |||
707 | union c2wr_qp_destroy { | ||
708 | struct c2wr_qp_destroy_req req; | ||
709 | struct c2wr_qp_destroy_rep rep; | ||
710 | } __attribute__((packed)) ; | ||
711 | |||
712 | /* | ||
713 | * The CCWR_QP_CONNECT msg is posted on the verbs request queue. It can | ||
714 | * only be posted when a QP is in IDLE state. After the connect request is | ||
715 | * submitted to the LLP, the adapter moves the QP to CONNECT_PENDING state. | ||
716 | * No synchronous reply from adapter to this WR. The results of | ||
717 | * connection are passed back in an async event CCAE_ACTIVE_CONNECT_RESULTS | ||
718 | * See c2wr_ae_active_connect_results_t | ||
719 | */ | ||
720 | struct c2wr_qp_connect_req { | ||
721 | struct c2wr_hdr hdr; | ||
722 | u32 rnic_handle; | ||
723 | u32 qp_handle; | ||
724 | u32 remote_addr; | ||
725 | u16 remote_port; | ||
726 | u16 pad; | ||
727 | u32 private_data_length; | ||
728 | u8 private_data[0]; /* Private data in-line. */ | ||
729 | } __attribute__((packed)) ; | ||
730 | |||
731 | struct c2wr_qp_connect { | ||
732 | struct c2wr_qp_connect_req req; | ||
733 | /* no synchronous reply. */ | ||
734 | } __attribute__((packed)) ; | ||
735 | |||
736 | |||
737 | /* | ||
738 | *------------------------ MM ------------------------ | ||
739 | */ | ||
740 | |||
741 | struct c2wr_nsmr_stag_alloc_req { | ||
742 | struct c2wr_hdr hdr; | ||
743 | u32 rnic_handle; | ||
744 | u32 pbl_depth; | ||
745 | u32 pd_id; | ||
746 | u32 flags; | ||
747 | } __attribute__((packed)) ; | ||
748 | |||
749 | struct c2wr_nsmr_stag_alloc_rep { | ||
750 | struct c2wr_hdr hdr; | ||
751 | u32 pbl_depth; | ||
752 | u32 stag_index; | ||
753 | } __attribute__((packed)) ; | ||
754 | |||
755 | union c2wr_nsmr_stag_alloc { | ||
756 | struct c2wr_nsmr_stag_alloc_req req; | ||
757 | struct c2wr_nsmr_stag_alloc_rep rep; | ||
758 | } __attribute__((packed)) ; | ||
759 | |||
760 | struct c2wr_nsmr_register_req { | ||
761 | struct c2wr_hdr hdr; | ||
762 | u64 va; | ||
763 | u32 rnic_handle; | ||
764 | u16 flags; | ||
765 | u8 stag_key; | ||
766 | u8 pad; | ||
767 | u32 pd_id; | ||
768 | u32 pbl_depth; | ||
769 | u32 pbe_size; | ||
770 | u32 fbo; | ||
771 | u32 length; | ||
772 | u32 addrs_length; | ||
773 | /* array of paddrs (must be aligned on a 64bit boundary) */ | ||
774 | u64 paddrs[0]; | ||
775 | } __attribute__((packed)) ; | ||
776 | |||
777 | struct c2wr_nsmr_register_rep { | ||
778 | struct c2wr_hdr hdr; | ||
779 | u32 pbl_depth; | ||
780 | u32 stag_index; | ||
781 | } __attribute__((packed)) ; | ||
782 | |||
783 | union c2wr_nsmr_register { | ||
784 | struct c2wr_nsmr_register_req req; | ||
785 | struct c2wr_nsmr_register_rep rep; | ||
786 | } __attribute__((packed)) ; | ||
787 | |||
788 | struct c2wr_nsmr_pbl_req { | ||
789 | struct c2wr_hdr hdr; | ||
790 | u32 rnic_handle; | ||
791 | u32 flags; | ||
792 | u32 stag_index; | ||
793 | u32 addrs_length; | ||
794 | /* array of paddrs (must be aligned on a 64bit boundary) */ | ||
795 | u64 paddrs[0]; | ||
796 | } __attribute__((packed)) ; | ||
797 | |||
798 | struct c2wr_nsmr_pbl_rep { | ||
799 | struct c2wr_hdr hdr; | ||
800 | } __attribute__((packed)) ; | ||
801 | |||
802 | union c2wr_nsmr_pbl { | ||
803 | struct c2wr_nsmr_pbl_req req; | ||
804 | struct c2wr_nsmr_pbl_rep rep; | ||
805 | } __attribute__((packed)) ; | ||
806 | |||
807 | struct c2wr_mr_query_req { | ||
808 | struct c2wr_hdr hdr; | ||
809 | u32 rnic_handle; | ||
810 | u32 stag_index; | ||
811 | } __attribute__((packed)) ; | ||
812 | |||
813 | struct c2wr_mr_query_rep { | ||
814 | struct c2wr_hdr hdr; | ||
815 | u8 stag_key; | ||
816 | u8 pad[3]; | ||
817 | u32 pd_id; | ||
818 | u32 flags; | ||
819 | u32 pbl_depth; | ||
820 | } __attribute__((packed)) ; | ||
821 | |||
822 | union c2wr_mr_query { | ||
823 | struct c2wr_mr_query_req req; | ||
824 | struct c2wr_mr_query_rep rep; | ||
825 | } __attribute__((packed)) ; | ||
826 | |||
827 | struct c2wr_mw_query_req { | ||
828 | struct c2wr_hdr hdr; | ||
829 | u32 rnic_handle; | ||
830 | u32 stag_index; | ||
831 | } __attribute__((packed)) ; | ||
832 | |||
833 | struct c2wr_mw_query_rep { | ||
834 | struct c2wr_hdr hdr; | ||
835 | u8 stag_key; | ||
836 | u8 pad[3]; | ||
837 | u32 pd_id; | ||
838 | u32 flags; | ||
839 | } __attribute__((packed)) ; | ||
840 | |||
841 | union c2wr_mw_query { | ||
842 | struct c2wr_mw_query_req req; | ||
843 | struct c2wr_mw_query_rep rep; | ||
844 | } __attribute__((packed)) ; | ||
845 | |||
846 | |||
847 | struct c2wr_stag_dealloc_req { | ||
848 | struct c2wr_hdr hdr; | ||
849 | u32 rnic_handle; | ||
850 | u32 stag_index; | ||
851 | } __attribute__((packed)) ; | ||
852 | |||
853 | struct c2wr_stag_dealloc_rep { | ||
854 | struct c2wr_hdr hdr; | ||
855 | } __attribute__((packed)) ; | ||
856 | |||
857 | union c2wr_stag_dealloc { | ||
858 | struct c2wr_stag_dealloc_req req; | ||
859 | struct c2wr_stag_dealloc_rep rep; | ||
860 | } __attribute__((packed)) ; | ||
861 | |||
862 | struct c2wr_nsmr_reregister_req { | ||
863 | struct c2wr_hdr hdr; | ||
864 | u64 va; | ||
865 | u32 rnic_handle; | ||
866 | u16 flags; | ||
867 | u8 stag_key; | ||
868 | u8 pad; | ||
869 | u32 stag_index; | ||
870 | u32 pd_id; | ||
871 | u32 pbl_depth; | ||
872 | u32 pbe_size; | ||
873 | u32 fbo; | ||
874 | u32 length; | ||
875 | u32 addrs_length; | ||
876 | u32 pad1; | ||
877 | /* array of paddrs (must be aligned on a 64bit boundary) */ | ||
878 | u64 paddrs[0]; | ||
879 | } __attribute__((packed)) ; | ||
880 | |||
881 | struct c2wr_nsmr_reregister_rep { | ||
882 | struct c2wr_hdr hdr; | ||
883 | u32 pbl_depth; | ||
884 | u32 stag_index; | ||
885 | } __attribute__((packed)) ; | ||
886 | |||
887 | union c2wr_nsmr_reregister { | ||
888 | struct c2wr_nsmr_reregister_req req; | ||
889 | struct c2wr_nsmr_reregister_rep rep; | ||
890 | } __attribute__((packed)) ; | ||
891 | |||
892 | struct c2wr_smr_register_req { | ||
893 | struct c2wr_hdr hdr; | ||
894 | u64 va; | ||
895 | u32 rnic_handle; | ||
896 | u16 flags; | ||
897 | u8 stag_key; | ||
898 | u8 pad; | ||
899 | u32 stag_index; | ||
900 | u32 pd_id; | ||
901 | } __attribute__((packed)) ; | ||
902 | |||
903 | struct c2wr_smr_register_rep { | ||
904 | struct c2wr_hdr hdr; | ||
905 | u32 stag_index; | ||
906 | } __attribute__((packed)) ; | ||
907 | |||
908 | union c2wr_smr_register { | ||
909 | struct c2wr_smr_register_req req; | ||
910 | struct c2wr_smr_register_rep rep; | ||
911 | } __attribute__((packed)) ; | ||
912 | |||
913 | struct c2wr_mw_alloc_req { | ||
914 | struct c2wr_hdr hdr; | ||
915 | u32 rnic_handle; | ||
916 | u32 pd_id; | ||
917 | } __attribute__((packed)) ; | ||
918 | |||
919 | struct c2wr_mw_alloc_rep { | ||
920 | struct c2wr_hdr hdr; | ||
921 | u32 stag_index; | ||
922 | } __attribute__((packed)) ; | ||
923 | |||
924 | union c2wr_mw_alloc { | ||
925 | struct c2wr_mw_alloc_req req; | ||
926 | struct c2wr_mw_alloc_rep rep; | ||
927 | } __attribute__((packed)) ; | ||
928 | |||
929 | /* | ||
930 | *------------------------ WRs ----------------------- | ||
931 | */ | ||
932 | |||
933 | struct c2wr_user_hdr { | ||
934 | struct c2wr_hdr hdr; /* Has status and WR Type */ | ||
935 | } __attribute__((packed)) ; | ||
936 | |||
937 | enum c2_qp_state { | ||
938 | C2_QP_STATE_IDLE = 0x01, | ||
939 | C2_QP_STATE_CONNECTING = 0x02, | ||
940 | C2_QP_STATE_RTS = 0x04, | ||
941 | C2_QP_STATE_CLOSING = 0x08, | ||
942 | C2_QP_STATE_TERMINATE = 0x10, | ||
943 | C2_QP_STATE_ERROR = 0x20, | ||
944 | }; | ||
945 | |||
946 | /* Completion queue entry. */ | ||
947 | struct c2wr_ce { | ||
948 | struct c2wr_hdr hdr; /* Has status and WR Type */ | ||
949 | u64 qp_user_context; /* c2_user_qp_t * */ | ||
950 | u32 qp_state; /* Current QP State */ | ||
951 | u32 handle; /* QPID or EP Handle */ | ||
952 | u32 bytes_rcvd; /* valid for RECV WCs */ | ||
953 | u32 stag; | ||
954 | } __attribute__((packed)) ; | ||
955 | |||
956 | |||
957 | /* | ||
958 | * Flags used for all post-sq WRs. These must fit in the flags | ||
959 | * field of the struct c2wr_hdr (eight bits). | ||
960 | */ | ||
961 | enum { | ||
962 | SQ_SIGNALED = 0x01, | ||
963 | SQ_READ_FENCE = 0x02, | ||
964 | SQ_FENCE = 0x04, | ||
965 | }; | ||
966 | |||
967 | /* | ||
968 | * Common fields for all post-sq WRs. Namely the standard header and a | ||
969 | * secondary header with fields common to all post-sq WRs. | ||
970 | */ | ||
971 | struct c2_sq_hdr { | ||
972 | struct c2wr_user_hdr user_hdr; | ||
973 | } __attribute__((packed)); | ||
974 | |||
975 | /* | ||
976 | * Same as above but for post-rq WRs. | ||
977 | */ | ||
978 | struct c2_rq_hdr { | ||
979 | struct c2wr_user_hdr user_hdr; | ||
980 | } __attribute__((packed)); | ||
981 | |||
982 | /* | ||
983 | * use the same struct for all sends. | ||
984 | */ | ||
985 | struct c2wr_send_req { | ||
986 | struct c2_sq_hdr sq_hdr; | ||
987 | u32 sge_len; | ||
988 | u32 remote_stag; | ||
989 | u8 data[0]; /* SGE array */ | ||
990 | } __attribute__((packed)); | ||
991 | |||
992 | union c2wr_send { | ||
993 | struct c2wr_send_req req; | ||
994 | struct c2wr_ce rep; | ||
995 | } __attribute__((packed)); | ||
996 | |||
997 | struct c2wr_rdma_write_req { | ||
998 | struct c2_sq_hdr sq_hdr; | ||
999 | u64 remote_to; | ||
1000 | u32 remote_stag; | ||
1001 | u32 sge_len; | ||
1002 | u8 data[0]; /* SGE array */ | ||
1003 | } __attribute__((packed)); | ||
1004 | |||
1005 | union c2wr_rdma_write { | ||
1006 | struct c2wr_rdma_write_req req; | ||
1007 | struct c2wr_ce rep; | ||
1008 | } __attribute__((packed)); | ||
1009 | |||
1010 | struct c2wr_rdma_read_req { | ||
1011 | struct c2_sq_hdr sq_hdr; | ||
1012 | u64 local_to; | ||
1013 | u64 remote_to; | ||
1014 | u32 local_stag; | ||
1015 | u32 remote_stag; | ||
1016 | u32 length; | ||
1017 | } __attribute__((packed)); | ||
1018 | |||
1019 | union c2wr_rdma_read { | ||
1020 | struct c2wr_rdma_read_req req; | ||
1021 | struct c2wr_ce rep; | ||
1022 | } __attribute__((packed)); | ||
1023 | |||
1024 | struct c2wr_mw_bind_req { | ||
1025 | struct c2_sq_hdr sq_hdr; | ||
1026 | u64 va; | ||
1027 | u8 stag_key; | ||
1028 | u8 pad[3]; | ||
1029 | u32 mw_stag_index; | ||
1030 | u32 mr_stag_index; | ||
1031 | u32 length; | ||
1032 | u32 flags; | ||
1033 | } __attribute__((packed)); | ||
1034 | |||
1035 | union c2wr_mw_bind { | ||
1036 | struct c2wr_mw_bind_req req; | ||
1037 | struct c2wr_ce rep; | ||
1038 | } __attribute__((packed)); | ||
1039 | |||
1040 | struct c2wr_nsmr_fastreg_req { | ||
1041 | struct c2_sq_hdr sq_hdr; | ||
1042 | u64 va; | ||
1043 | u8 stag_key; | ||
1044 | u8 pad[3]; | ||
1045 | u32 stag_index; | ||
1046 | u32 pbe_size; | ||
1047 | u32 fbo; | ||
1048 | u32 length; | ||
1049 | u32 addrs_length; | ||
1050 | /* array of paddrs (must be aligned on a 64bit boundary) */ | ||
1051 | u64 paddrs[0]; | ||
1052 | } __attribute__((packed)); | ||
1053 | |||
1054 | union c2wr_nsmr_fastreg { | ||
1055 | struct c2wr_nsmr_fastreg_req req; | ||
1056 | struct c2wr_ce rep; | ||
1057 | } __attribute__((packed)); | ||
1058 | |||
1059 | struct c2wr_stag_invalidate_req { | ||
1060 | struct c2_sq_hdr sq_hdr; | ||
1061 | u8 stag_key; | ||
1062 | u8 pad[3]; | ||
1063 | u32 stag_index; | ||
1064 | } __attribute__((packed)); | ||
1065 | |||
1066 | union c2wr_stag_invalidate { | ||
1067 | struct c2wr_stag_invalidate_req req; | ||
1068 | struct c2wr_ce rep; | ||
1069 | } __attribute__((packed)); | ||
1070 | |||
1071 | union c2wr_sqwr { | ||
1072 | struct c2_sq_hdr sq_hdr; | ||
1073 | struct c2wr_send_req send; | ||
1074 | struct c2wr_send_req send_se; | ||
1075 | struct c2wr_send_req send_inv; | ||
1076 | struct c2wr_send_req send_se_inv; | ||
1077 | struct c2wr_rdma_write_req rdma_write; | ||
1078 | struct c2wr_rdma_read_req rdma_read; | ||
1079 | struct c2wr_mw_bind_req mw_bind; | ||
1080 | struct c2wr_nsmr_fastreg_req nsmr_fastreg; | ||
1081 | struct c2wr_stag_invalidate_req stag_inv; | ||
1082 | } __attribute__((packed)); | ||
1083 | |||
1084 | |||
1085 | /* | ||
1086 | * RQ WRs | ||
1087 | */ | ||
1088 | struct c2wr_rqwr { | ||
1089 | struct c2_rq_hdr rq_hdr; | ||
1090 | u8 data[0]; /* array of SGEs */ | ||
1091 | } __attribute__((packed)); | ||
1092 | |||
1093 | union c2wr_recv { | ||
1094 | struct c2wr_rqwr req; | ||
1095 | struct c2wr_ce rep; | ||
1096 | } __attribute__((packed)); | ||
1097 | |||
1098 | /* | ||
1099 | * All AEs start with this header. Most AEs only need to convey the | ||
1100 | * information in the header. Some, like LLP connection events, need | ||
1101 | * more info. The union typdef c2wr_ae_t has all the possible AEs. | ||
1102 | * | ||
1103 | * hdr.context is the user_context from the rnic_open WR. NULL If this | ||
1104 | * is not affiliated with an rnic | ||
1105 | * | ||
1106 | * hdr.id is the AE identifier (eg; CCAE_REMOTE_SHUTDOWN, | ||
1107 | * CCAE_LLP_CLOSE_COMPLETE) | ||
1108 | * | ||
1109 | * resource_type is one of: C2_RES_IND_QP, C2_RES_IND_CQ, C2_RES_IND_SRQ | ||
1110 | * | ||
1111 | * user_context is the context passed down when the host created the resource. | ||
1112 | */ | ||
1113 | struct c2wr_ae_hdr { | ||
1114 | struct c2wr_hdr hdr; | ||
1115 | u64 user_context; /* user context for this res. */ | ||
1116 | u32 resource_type; /* see enum c2_resource_indicator */ | ||
1117 | u32 resource; /* handle for resource */ | ||
1118 | u32 qp_state; /* current QP State */ | ||
1119 | } __attribute__((packed)); | ||
1120 | |||
1121 | /* | ||
1122 | * After submitting the CCAE_ACTIVE_CONNECT_RESULTS message on the AEQ, | ||
1123 | * the adapter moves the QP into RTS state | ||
1124 | */ | ||
1125 | struct c2wr_ae_active_connect_results { | ||
1126 | struct c2wr_ae_hdr ae_hdr; | ||
1127 | u32 laddr; | ||
1128 | u32 raddr; | ||
1129 | u16 lport; | ||
1130 | u16 rport; | ||
1131 | u32 private_data_length; | ||
1132 | u8 private_data[0]; /* data is in-line in the msg. */ | ||
1133 | } __attribute__((packed)); | ||
1134 | |||
1135 | /* | ||
1136 | * When connections are established by the stack (and the private data | ||
1137 | * MPA frame is received), the adapter will generate an event to the host. | ||
1138 | * The details of the connection, any private data, and the new connection | ||
1139 | * request handle is passed up via the CCAE_CONNECTION_REQUEST msg on the | ||
1140 | * AE queue: | ||
1141 | */ | ||
1142 | struct c2wr_ae_connection_request { | ||
1143 | struct c2wr_ae_hdr ae_hdr; | ||
1144 | u32 cr_handle; /* connreq handle (sock ptr) */ | ||
1145 | u32 laddr; | ||
1146 | u32 raddr; | ||
1147 | u16 lport; | ||
1148 | u16 rport; | ||
1149 | u32 private_data_length; | ||
1150 | u8 private_data[0]; /* data is in-line in the msg. */ | ||
1151 | } __attribute__((packed)); | ||
1152 | |||
1153 | union c2wr_ae { | ||
1154 | struct c2wr_ae_hdr ae_generic; | ||
1155 | struct c2wr_ae_active_connect_results ae_active_connect_results; | ||
1156 | struct c2wr_ae_connection_request ae_connection_request; | ||
1157 | } __attribute__((packed)); | ||
1158 | |||
1159 | struct c2wr_init_req { | ||
1160 | struct c2wr_hdr hdr; | ||
1161 | u64 hint_count; | ||
1162 | u64 q0_host_shared; | ||
1163 | u64 q1_host_shared; | ||
1164 | u64 q1_host_msg_pool; | ||
1165 | u64 q2_host_shared; | ||
1166 | u64 q2_host_msg_pool; | ||
1167 | } __attribute__((packed)); | ||
1168 | |||
1169 | struct c2wr_init_rep { | ||
1170 | struct c2wr_hdr hdr; | ||
1171 | } __attribute__((packed)); | ||
1172 | |||
1173 | union c2wr_init { | ||
1174 | struct c2wr_init_req req; | ||
1175 | struct c2wr_init_rep rep; | ||
1176 | } __attribute__((packed)); | ||
1177 | |||
1178 | /* | ||
1179 | * For upgrading flash. | ||
1180 | */ | ||
1181 | |||
1182 | struct c2wr_flash_init_req { | ||
1183 | struct c2wr_hdr hdr; | ||
1184 | u32 rnic_handle; | ||
1185 | } __attribute__((packed)); | ||
1186 | |||
1187 | struct c2wr_flash_init_rep { | ||
1188 | struct c2wr_hdr hdr; | ||
1189 | u32 adapter_flash_buf_offset; | ||
1190 | u32 adapter_flash_len; | ||
1191 | } __attribute__((packed)); | ||
1192 | |||
1193 | union c2wr_flash_init { | ||
1194 | struct c2wr_flash_init_req req; | ||
1195 | struct c2wr_flash_init_rep rep; | ||
1196 | } __attribute__((packed)); | ||
1197 | |||
1198 | struct c2wr_flash_req { | ||
1199 | struct c2wr_hdr hdr; | ||
1200 | u32 rnic_handle; | ||
1201 | u32 len; | ||
1202 | } __attribute__((packed)); | ||
1203 | |||
1204 | struct c2wr_flash_rep { | ||
1205 | struct c2wr_hdr hdr; | ||
1206 | u32 status; | ||
1207 | } __attribute__((packed)); | ||
1208 | |||
1209 | union c2wr_flash { | ||
1210 | struct c2wr_flash_req req; | ||
1211 | struct c2wr_flash_rep rep; | ||
1212 | } __attribute__((packed)); | ||
1213 | |||
1214 | struct c2wr_buf_alloc_req { | ||
1215 | struct c2wr_hdr hdr; | ||
1216 | u32 rnic_handle; | ||
1217 | u32 size; | ||
1218 | } __attribute__((packed)); | ||
1219 | |||
1220 | struct c2wr_buf_alloc_rep { | ||
1221 | struct c2wr_hdr hdr; | ||
1222 | u32 offset; /* 0 if mem not available */ | ||
1223 | u32 size; /* 0 if mem not available */ | ||
1224 | } __attribute__((packed)); | ||
1225 | |||
1226 | union c2wr_buf_alloc { | ||
1227 | struct c2wr_buf_alloc_req req; | ||
1228 | struct c2wr_buf_alloc_rep rep; | ||
1229 | } __attribute__((packed)); | ||
1230 | |||
1231 | struct c2wr_buf_free_req { | ||
1232 | struct c2wr_hdr hdr; | ||
1233 | u32 rnic_handle; | ||
1234 | u32 offset; /* Must match value from alloc */ | ||
1235 | u32 size; /* Must match value from alloc */ | ||
1236 | } __attribute__((packed)); | ||
1237 | |||
1238 | struct c2wr_buf_free_rep { | ||
1239 | struct c2wr_hdr hdr; | ||
1240 | } __attribute__((packed)); | ||
1241 | |||
1242 | union c2wr_buf_free { | ||
1243 | struct c2wr_buf_free_req req; | ||
1244 | struct c2wr_ce rep; | ||
1245 | } __attribute__((packed)); | ||
1246 | |||
1247 | struct c2wr_flash_write_req { | ||
1248 | struct c2wr_hdr hdr; | ||
1249 | u32 rnic_handle; | ||
1250 | u32 offset; | ||
1251 | u32 size; | ||
1252 | u32 type; | ||
1253 | u32 flags; | ||
1254 | } __attribute__((packed)); | ||
1255 | |||
1256 | struct c2wr_flash_write_rep { | ||
1257 | struct c2wr_hdr hdr; | ||
1258 | u32 status; | ||
1259 | } __attribute__((packed)); | ||
1260 | |||
1261 | union c2wr_flash_write { | ||
1262 | struct c2wr_flash_write_req req; | ||
1263 | struct c2wr_flash_write_rep rep; | ||
1264 | } __attribute__((packed)); | ||
1265 | |||
1266 | /* | ||
1267 | * Messages for LLP connection setup. | ||
1268 | */ | ||
1269 | |||
1270 | /* | ||
1271 | * Listen Request. This allocates a listening endpoint to allow passive | ||
1272 | * connection setup. Newly established LLP connections are passed up | ||
1273 | * via an AE. See c2wr_ae_connection_request_t | ||
1274 | */ | ||
1275 | struct c2wr_ep_listen_create_req { | ||
1276 | struct c2wr_hdr hdr; | ||
1277 | u64 user_context; /* returned in AEs. */ | ||
1278 | u32 rnic_handle; | ||
1279 | u32 local_addr; /* local addr, or 0 */ | ||
1280 | u16 local_port; /* 0 means "pick one" */ | ||
1281 | u16 pad; | ||
1282 | u32 backlog; /* tradional tcp listen bl */ | ||
1283 | } __attribute__((packed)); | ||
1284 | |||
1285 | struct c2wr_ep_listen_create_rep { | ||
1286 | struct c2wr_hdr hdr; | ||
1287 | u32 ep_handle; /* handle to new listening ep */ | ||
1288 | u16 local_port; /* resulting port... */ | ||
1289 | u16 pad; | ||
1290 | } __attribute__((packed)); | ||
1291 | |||
1292 | union c2wr_ep_listen_create { | ||
1293 | struct c2wr_ep_listen_create_req req; | ||
1294 | struct c2wr_ep_listen_create_rep rep; | ||
1295 | } __attribute__((packed)); | ||
1296 | |||
1297 | struct c2wr_ep_listen_destroy_req { | ||
1298 | struct c2wr_hdr hdr; | ||
1299 | u32 rnic_handle; | ||
1300 | u32 ep_handle; | ||
1301 | } __attribute__((packed)); | ||
1302 | |||
1303 | struct c2wr_ep_listen_destroy_rep { | ||
1304 | struct c2wr_hdr hdr; | ||
1305 | } __attribute__((packed)); | ||
1306 | |||
1307 | union c2wr_ep_listen_destroy { | ||
1308 | struct c2wr_ep_listen_destroy_req req; | ||
1309 | struct c2wr_ep_listen_destroy_rep rep; | ||
1310 | } __attribute__((packed)); | ||
1311 | |||
1312 | struct c2wr_ep_query_req { | ||
1313 | struct c2wr_hdr hdr; | ||
1314 | u32 rnic_handle; | ||
1315 | u32 ep_handle; | ||
1316 | } __attribute__((packed)); | ||
1317 | |||
1318 | struct c2wr_ep_query_rep { | ||
1319 | struct c2wr_hdr hdr; | ||
1320 | u32 rnic_handle; | ||
1321 | u32 local_addr; | ||
1322 | u32 remote_addr; | ||
1323 | u16 local_port; | ||
1324 | u16 remote_port; | ||
1325 | } __attribute__((packed)); | ||
1326 | |||
1327 | union c2wr_ep_query { | ||
1328 | struct c2wr_ep_query_req req; | ||
1329 | struct c2wr_ep_query_rep rep; | ||
1330 | } __attribute__((packed)); | ||
1331 | |||
1332 | |||
1333 | /* | ||
1334 | * The host passes this down to indicate acceptance of a pending iWARP | ||
1335 | * connection. The cr_handle was obtained from the CONNECTION_REQUEST | ||
1336 | * AE passed up by the adapter. See c2wr_ae_connection_request_t. | ||
1337 | */ | ||
1338 | struct c2wr_cr_accept_req { | ||
1339 | struct c2wr_hdr hdr; | ||
1340 | u32 rnic_handle; | ||
1341 | u32 qp_handle; /* QP to bind to this LLP conn */ | ||
1342 | u32 ep_handle; /* LLP handle to accept */ | ||
1343 | u32 private_data_length; | ||
1344 | u8 private_data[0]; /* data in-line in msg. */ | ||
1345 | } __attribute__((packed)); | ||
1346 | |||
1347 | /* | ||
1348 | * adapter sends reply when private data is successfully submitted to | ||
1349 | * the LLP. | ||
1350 | */ | ||
1351 | struct c2wr_cr_accept_rep { | ||
1352 | struct c2wr_hdr hdr; | ||
1353 | } __attribute__((packed)); | ||
1354 | |||
1355 | union c2wr_cr_accept { | ||
1356 | struct c2wr_cr_accept_req req; | ||
1357 | struct c2wr_cr_accept_rep rep; | ||
1358 | } __attribute__((packed)); | ||
1359 | |||
1360 | /* | ||
1361 | * The host sends this down if a given iWARP connection request was | ||
1362 | * rejected by the consumer. The cr_handle was obtained from a | ||
1363 | * previous c2wr_ae_connection_request_t AE sent by the adapter. | ||
1364 | */ | ||
1365 | struct c2wr_cr_reject_req { | ||
1366 | struct c2wr_hdr hdr; | ||
1367 | u32 rnic_handle; | ||
1368 | u32 ep_handle; /* LLP handle to reject */ | ||
1369 | } __attribute__((packed)); | ||
1370 | |||
1371 | /* | ||
1372 | * Dunno if this is needed, but we'll add it for now. The adapter will | ||
1373 | * send the reject_reply after the LLP endpoint has been destroyed. | ||
1374 | */ | ||
1375 | struct c2wr_cr_reject_rep { | ||
1376 | struct c2wr_hdr hdr; | ||
1377 | } __attribute__((packed)); | ||
1378 | |||
1379 | union c2wr_cr_reject { | ||
1380 | struct c2wr_cr_reject_req req; | ||
1381 | struct c2wr_cr_reject_rep rep; | ||
1382 | } __attribute__((packed)); | ||
1383 | |||
1384 | /* | ||
1385 | * console command. Used to implement a debug console over the verbs | ||
1386 | * request and reply queues. | ||
1387 | */ | ||
1388 | |||
1389 | /* | ||
1390 | * Console request message. It contains: | ||
1391 | * - message hdr with id = CCWR_CONSOLE | ||
1392 | * - the physaddr/len of host memory to be used for the reply. | ||
1393 | * - the command string. eg: "netstat -s" or "zoneinfo" | ||
1394 | */ | ||
1395 | struct c2wr_console_req { | ||
1396 | struct c2wr_hdr hdr; /* id = CCWR_CONSOLE */ | ||
1397 | u64 reply_buf; /* pinned host buf for reply */ | ||
1398 | u32 reply_buf_len; /* length of reply buffer */ | ||
1399 | u8 command[0]; /* NUL terminated ascii string */ | ||
1400 | /* containing the command req */ | ||
1401 | } __attribute__((packed)); | ||
1402 | |||
1403 | /* | ||
1404 | * flags used in the console reply. | ||
1405 | */ | ||
1406 | enum c2_console_flags { | ||
1407 | CONS_REPLY_TRUNCATED = 0x00000001 /* reply was truncated */ | ||
1408 | } __attribute__((packed)); | ||
1409 | |||
1410 | /* | ||
1411 | * Console reply message. | ||
1412 | * hdr.result contains the c2_status_t error if the reply was _not_ generated, | ||
1413 | * or C2_OK if the reply was generated. | ||
1414 | */ | ||
1415 | struct c2wr_console_rep { | ||
1416 | struct c2wr_hdr hdr; /* id = CCWR_CONSOLE */ | ||
1417 | u32 flags; | ||
1418 | } __attribute__((packed)); | ||
1419 | |||
1420 | union c2wr_console { | ||
1421 | struct c2wr_console_req req; | ||
1422 | struct c2wr_console_rep rep; | ||
1423 | } __attribute__((packed)); | ||
1424 | |||
1425 | |||
1426 | /* | ||
1427 | * Giant union with all WRs. Makes life easier... | ||
1428 | */ | ||
1429 | union c2wr { | ||
1430 | struct c2wr_hdr hdr; | ||
1431 | struct c2wr_user_hdr user_hdr; | ||
1432 | union c2wr_rnic_open rnic_open; | ||
1433 | union c2wr_rnic_query rnic_query; | ||
1434 | union c2wr_rnic_getconfig rnic_getconfig; | ||
1435 | union c2wr_rnic_setconfig rnic_setconfig; | ||
1436 | union c2wr_rnic_close rnic_close; | ||
1437 | union c2wr_cq_create cq_create; | ||
1438 | union c2wr_cq_modify cq_modify; | ||
1439 | union c2wr_cq_destroy cq_destroy; | ||
1440 | union c2wr_pd_alloc pd_alloc; | ||
1441 | union c2wr_pd_dealloc pd_dealloc; | ||
1442 | union c2wr_srq_create srq_create; | ||
1443 | union c2wr_srq_destroy srq_destroy; | ||
1444 | union c2wr_qp_create qp_create; | ||
1445 | union c2wr_qp_query qp_query; | ||
1446 | union c2wr_qp_modify qp_modify; | ||
1447 | union c2wr_qp_destroy qp_destroy; | ||
1448 | struct c2wr_qp_connect qp_connect; | ||
1449 | union c2wr_nsmr_stag_alloc nsmr_stag_alloc; | ||
1450 | union c2wr_nsmr_register nsmr_register; | ||
1451 | union c2wr_nsmr_pbl nsmr_pbl; | ||
1452 | union c2wr_mr_query mr_query; | ||
1453 | union c2wr_mw_query mw_query; | ||
1454 | union c2wr_stag_dealloc stag_dealloc; | ||
1455 | union c2wr_sqwr sqwr; | ||
1456 | struct c2wr_rqwr rqwr; | ||
1457 | struct c2wr_ce ce; | ||
1458 | union c2wr_ae ae; | ||
1459 | union c2wr_init init; | ||
1460 | union c2wr_ep_listen_create ep_listen_create; | ||
1461 | union c2wr_ep_listen_destroy ep_listen_destroy; | ||
1462 | union c2wr_cr_accept cr_accept; | ||
1463 | union c2wr_cr_reject cr_reject; | ||
1464 | union c2wr_console console; | ||
1465 | union c2wr_flash_init flash_init; | ||
1466 | union c2wr_flash flash; | ||
1467 | union c2wr_buf_alloc buf_alloc; | ||
1468 | union c2wr_buf_free buf_free; | ||
1469 | union c2wr_flash_write flash_write; | ||
1470 | } __attribute__((packed)); | ||
1471 | |||
1472 | |||
1473 | /* | ||
1474 | * Accessors for the wr fields that are packed together tightly to | ||
1475 | * reduce the wr message size. The wr arguments are void* so that | ||
1476 | * either a struct c2wr*, a struct c2wr_hdr*, or a pointer to any of the types | ||
1477 | * in the struct c2wr union can be passed in. | ||
1478 | */ | ||
1479 | static __inline__ u8 c2_wr_get_id(void *wr) | ||
1480 | { | ||
1481 | return ((struct c2wr_hdr *) wr)->id; | ||
1482 | } | ||
1483 | static __inline__ void c2_wr_set_id(void *wr, u8 id) | ||
1484 | { | ||
1485 | ((struct c2wr_hdr *) wr)->id = id; | ||
1486 | } | ||
1487 | static __inline__ u8 c2_wr_get_result(void *wr) | ||
1488 | { | ||
1489 | return ((struct c2wr_hdr *) wr)->result; | ||
1490 | } | ||
1491 | static __inline__ void c2_wr_set_result(void *wr, u8 result) | ||
1492 | { | ||
1493 | ((struct c2wr_hdr *) wr)->result = result; | ||
1494 | } | ||
1495 | static __inline__ u8 c2_wr_get_flags(void *wr) | ||
1496 | { | ||
1497 | return ((struct c2wr_hdr *) wr)->flags; | ||
1498 | } | ||
1499 | static __inline__ void c2_wr_set_flags(void *wr, u8 flags) | ||
1500 | { | ||
1501 | ((struct c2wr_hdr *) wr)->flags = flags; | ||
1502 | } | ||
1503 | static __inline__ u8 c2_wr_get_sge_count(void *wr) | ||
1504 | { | ||
1505 | return ((struct c2wr_hdr *) wr)->sge_count; | ||
1506 | } | ||
1507 | static __inline__ void c2_wr_set_sge_count(void *wr, u8 sge_count) | ||
1508 | { | ||
1509 | ((struct c2wr_hdr *) wr)->sge_count = sge_count; | ||
1510 | } | ||
1511 | static __inline__ u32 c2_wr_get_wqe_count(void *wr) | ||
1512 | { | ||
1513 | return ((struct c2wr_hdr *) wr)->wqe_count; | ||
1514 | } | ||
1515 | static __inline__ void c2_wr_set_wqe_count(void *wr, u32 wqe_count) | ||
1516 | { | ||
1517 | ((struct c2wr_hdr *) wr)->wqe_count = wqe_count; | ||
1518 | } | ||
1519 | |||
1520 | #endif /* _C2_WR_H_ */ | ||
diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig new file mode 100644 index 000000000000..922389b64394 --- /dev/null +++ b/drivers/infiniband/hw/ehca/Kconfig | |||
@@ -0,0 +1,16 @@ | |||
1 | config INFINIBAND_EHCA | ||
2 | tristate "eHCA support" | ||
3 | depends on IBMEBUS && INFINIBAND | ||
4 | ---help--- | ||
5 | This driver supports the IBM pSeries eHCA InfiniBand adapter. | ||
6 | |||
7 | To compile the driver as a module, choose M here. The module | ||
8 | will be called ib_ehca. | ||
9 | |||
10 | config INFINIBAND_EHCA_SCALING | ||
11 | bool "Scaling support (EXPERIMENTAL)" | ||
12 | depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL | ||
13 | ---help--- | ||
14 | eHCA scaling support schedules the CQ callbacks to different CPUs. | ||
15 | |||
16 | To enable this feature choose Y here. | ||
diff --git a/drivers/infiniband/hw/ehca/Makefile b/drivers/infiniband/hw/ehca/Makefile new file mode 100644 index 000000000000..74d284e46a40 --- /dev/null +++ b/drivers/infiniband/hw/ehca/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | # Authors: Heiko J Schick <schickhj@de.ibm.com> | ||
2 | # Christoph Raisch <raisch@de.ibm.com> | ||
3 | # Joachim Fenkes <fenkes@de.ibm.com> | ||
4 | # | ||
5 | # Copyright (c) 2005 IBM Corporation | ||
6 | # | ||
7 | # All rights reserved. | ||
8 | # | ||
9 | # This source code is distributed under a dual license of GPL v2.0 and OpenIB BSD. | ||
10 | |||
11 | obj-$(CONFIG_INFINIBAND_EHCA) += ib_ehca.o | ||
12 | |||
13 | ib_ehca-objs = ehca_main.o ehca_hca.o ehca_mcast.o ehca_pd.o ehca_av.o ehca_eq.o \ | ||
14 | ehca_cq.o ehca_qp.o ehca_sqp.o ehca_mrmw.o ehca_reqs.o ehca_irq.o \ | ||
15 | ehca_uverbs.o ipz_pt_fn.o hcp_if.o hcp_phyp.o | ||
16 | |||
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c new file mode 100644 index 000000000000..3bac197f9014 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_av.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * adress vector functions | ||
5 | * | ||
6 | * Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
7 | * Khadija Souissi <souissik@de.ibm.com> | ||
8 | * Reinhard Ernst <rernst@de.ibm.com> | ||
9 | * Christoph Raisch <raisch@de.ibm.com> | ||
10 | * | ||
11 | * Copyright (c) 2005 IBM Corporation | ||
12 | * | ||
13 | * All rights reserved. | ||
14 | * | ||
15 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
16 | * BSD. | ||
17 | * | ||
18 | * OpenIB BSD License | ||
19 | * | ||
20 | * Redistribution and use in source and binary forms, with or without | ||
21 | * modification, are permitted provided that the following conditions are met: | ||
22 | * | ||
23 | * Redistributions of source code must retain the above copyright notice, this | ||
24 | * list of conditions and the following disclaimer. | ||
25 | * | ||
26 | * Redistributions in binary form must reproduce the above copyright notice, | ||
27 | * this list of conditions and the following disclaimer in the documentation | ||
28 | * and/or other materials | ||
29 | * provided with the distribution. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
32 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
34 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
35 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
36 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
37 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
38 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
39 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | */ | ||
43 | |||
44 | |||
45 | #include <asm/current.h> | ||
46 | |||
47 | #include "ehca_tools.h" | ||
48 | #include "ehca_iverbs.h" | ||
49 | #include "hcp_if.h" | ||
50 | |||
51 | static struct kmem_cache *av_cache; | ||
52 | |||
53 | struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | ||
54 | { | ||
55 | int ret; | ||
56 | struct ehca_av *av; | ||
57 | struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, | ||
58 | ib_device); | ||
59 | |||
60 | av = kmem_cache_alloc(av_cache, SLAB_KERNEL); | ||
61 | if (!av) { | ||
62 | ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p", | ||
63 | pd, ah_attr); | ||
64 | return ERR_PTR(-ENOMEM); | ||
65 | } | ||
66 | |||
67 | av->av.sl = ah_attr->sl; | ||
68 | av->av.dlid = ah_attr->dlid; | ||
69 | av->av.slid_path_bits = ah_attr->src_path_bits; | ||
70 | |||
71 | if (ehca_static_rate < 0) { | ||
72 | int ah_mult = ib_rate_to_mult(ah_attr->static_rate); | ||
73 | int ehca_mult = | ||
74 | ib_rate_to_mult(shca->sport[ah_attr->port_num].rate ); | ||
75 | |||
76 | if (ah_mult >= ehca_mult) | ||
77 | av->av.ipd = 0; | ||
78 | else | ||
79 | av->av.ipd = (ah_mult > 0) ? | ||
80 | ((ehca_mult - 1) / ah_mult) : 0; | ||
81 | } else | ||
82 | av->av.ipd = ehca_static_rate; | ||
83 | |||
84 | av->av.lnh = ah_attr->ah_flags; | ||
85 | av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6); | ||
86 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_TCLASS_MASK, | ||
87 | ah_attr->grh.traffic_class); | ||
88 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK, | ||
89 | ah_attr->grh.flow_label); | ||
90 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK, | ||
91 | ah_attr->grh.hop_limit); | ||
92 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1B); | ||
93 | /* set sgid in grh.word_1 */ | ||
94 | if (ah_attr->ah_flags & IB_AH_GRH) { | ||
95 | int rc; | ||
96 | struct ib_port_attr port_attr; | ||
97 | union ib_gid gid; | ||
98 | memset(&port_attr, 0, sizeof(port_attr)); | ||
99 | rc = ehca_query_port(pd->device, ah_attr->port_num, | ||
100 | &port_attr); | ||
101 | if (rc) { /* invalid port number */ | ||
102 | ret = -EINVAL; | ||
103 | ehca_err(pd->device, "Invalid port number " | ||
104 | "ehca_query_port() returned %x " | ||
105 | "pd=%p ah_attr=%p", rc, pd, ah_attr); | ||
106 | goto create_ah_exit1; | ||
107 | } | ||
108 | memset(&gid, 0, sizeof(gid)); | ||
109 | rc = ehca_query_gid(pd->device, | ||
110 | ah_attr->port_num, | ||
111 | ah_attr->grh.sgid_index, &gid); | ||
112 | if (rc) { | ||
113 | ret = -EINVAL; | ||
114 | ehca_err(pd->device, "Failed to retrieve sgid " | ||
115 | "ehca_query_gid() returned %x " | ||
116 | "pd=%p ah_attr=%p", rc, pd, ah_attr); | ||
117 | goto create_ah_exit1; | ||
118 | } | ||
119 | memcpy(&av->av.grh.word_1, &gid, sizeof(gid)); | ||
120 | } | ||
121 | /* for the time being we use a hard coded PMTU of 2048 Bytes */ | ||
122 | av->av.pmtu = 4; | ||
123 | |||
124 | /* dgid comes in grh.word_3 */ | ||
125 | memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid, | ||
126 | sizeof(ah_attr->grh.dgid)); | ||
127 | |||
128 | return &av->ib_ah; | ||
129 | |||
130 | create_ah_exit1: | ||
131 | kmem_cache_free(av_cache, av); | ||
132 | |||
133 | return ERR_PTR(ret); | ||
134 | } | ||
135 | |||
136 | int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) | ||
137 | { | ||
138 | struct ehca_av *av; | ||
139 | struct ehca_ud_av new_ehca_av; | ||
140 | struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd); | ||
141 | u32 cur_pid = current->tgid; | ||
142 | |||
143 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
144 | my_pd->ownpid != cur_pid) { | ||
145 | ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x", | ||
146 | cur_pid, my_pd->ownpid); | ||
147 | return -EINVAL; | ||
148 | } | ||
149 | |||
150 | memset(&new_ehca_av, 0, sizeof(new_ehca_av)); | ||
151 | new_ehca_av.sl = ah_attr->sl; | ||
152 | new_ehca_av.dlid = ah_attr->dlid; | ||
153 | new_ehca_av.slid_path_bits = ah_attr->src_path_bits; | ||
154 | new_ehca_av.ipd = ah_attr->static_rate; | ||
155 | new_ehca_av.lnh = EHCA_BMASK_SET(GRH_FLAG_MASK, | ||
156 | (ah_attr->ah_flags & IB_AH_GRH) > 0); | ||
157 | new_ehca_av.grh.word_0 = EHCA_BMASK_SET(GRH_TCLASS_MASK, | ||
158 | ah_attr->grh.traffic_class); | ||
159 | new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK, | ||
160 | ah_attr->grh.flow_label); | ||
161 | new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK, | ||
162 | ah_attr->grh.hop_limit); | ||
163 | new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1b); | ||
164 | |||
165 | /* set sgid in grh.word_1 */ | ||
166 | if (ah_attr->ah_flags & IB_AH_GRH) { | ||
167 | int rc; | ||
168 | struct ib_port_attr port_attr; | ||
169 | union ib_gid gid; | ||
170 | memset(&port_attr, 0, sizeof(port_attr)); | ||
171 | rc = ehca_query_port(ah->device, ah_attr->port_num, | ||
172 | &port_attr); | ||
173 | if (rc) { /* invalid port number */ | ||
174 | ehca_err(ah->device, "Invalid port number " | ||
175 | "ehca_query_port() returned %x " | ||
176 | "ah=%p ah_attr=%p port_num=%x", | ||
177 | rc, ah, ah_attr, ah_attr->port_num); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | memset(&gid, 0, sizeof(gid)); | ||
181 | rc = ehca_query_gid(ah->device, | ||
182 | ah_attr->port_num, | ||
183 | ah_attr->grh.sgid_index, &gid); | ||
184 | if (rc) { | ||
185 | ehca_err(ah->device, "Failed to retrieve sgid " | ||
186 | "ehca_query_gid() returned %x " | ||
187 | "ah=%p ah_attr=%p port_num=%x " | ||
188 | "sgid_index=%x", | ||
189 | rc, ah, ah_attr, ah_attr->port_num, | ||
190 | ah_attr->grh.sgid_index); | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid)); | ||
194 | } | ||
195 | |||
196 | new_ehca_av.pmtu = 4; /* see also comment in create_ah() */ | ||
197 | |||
198 | memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid, | ||
199 | sizeof(ah_attr->grh.dgid)); | ||
200 | |||
201 | av = container_of(ah, struct ehca_av, ib_ah); | ||
202 | av->av = new_ehca_av; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) | ||
208 | { | ||
209 | struct ehca_av *av = container_of(ah, struct ehca_av, ib_ah); | ||
210 | struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd); | ||
211 | u32 cur_pid = current->tgid; | ||
212 | |||
213 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
214 | my_pd->ownpid != cur_pid) { | ||
215 | ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x", | ||
216 | cur_pid, my_pd->ownpid); | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | memcpy(&ah_attr->grh.dgid, &av->av.grh.word_3, | ||
221 | sizeof(ah_attr->grh.dgid)); | ||
222 | ah_attr->sl = av->av.sl; | ||
223 | |||
224 | ah_attr->dlid = av->av.dlid; | ||
225 | |||
226 | ah_attr->src_path_bits = av->av.slid_path_bits; | ||
227 | ah_attr->static_rate = av->av.ipd; | ||
228 | ah_attr->ah_flags = EHCA_BMASK_GET(GRH_FLAG_MASK, av->av.lnh); | ||
229 | ah_attr->grh.traffic_class = EHCA_BMASK_GET(GRH_TCLASS_MASK, | ||
230 | av->av.grh.word_0); | ||
231 | ah_attr->grh.hop_limit = EHCA_BMASK_GET(GRH_HOPLIMIT_MASK, | ||
232 | av->av.grh.word_0); | ||
233 | ah_attr->grh.flow_label = EHCA_BMASK_GET(GRH_FLOWLABEL_MASK, | ||
234 | av->av.grh.word_0); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | int ehca_destroy_ah(struct ib_ah *ah) | ||
240 | { | ||
241 | struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd); | ||
242 | u32 cur_pid = current->tgid; | ||
243 | |||
244 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
245 | my_pd->ownpid != cur_pid) { | ||
246 | ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x", | ||
247 | cur_pid, my_pd->ownpid); | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | |||
251 | kmem_cache_free(av_cache, container_of(ah, struct ehca_av, ib_ah)); | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | int ehca_init_av_cache(void) | ||
257 | { | ||
258 | av_cache = kmem_cache_create("ehca_cache_av", | ||
259 | sizeof(struct ehca_av), 0, | ||
260 | SLAB_HWCACHE_ALIGN, | ||
261 | NULL, NULL); | ||
262 | if (!av_cache) | ||
263 | return -ENOMEM; | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | void ehca_cleanup_av_cache(void) | ||
268 | { | ||
269 | if (av_cache) | ||
270 | kmem_cache_destroy(av_cache); | ||
271 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h new file mode 100644 index 000000000000..1c722032319c --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_classes.h | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Struct definition for eHCA internal structures | ||
5 | * | ||
6 | * Authors: Heiko J Schick <schickhj@de.ibm.com> | ||
7 | * Christoph Raisch <raisch@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #ifndef __EHCA_CLASSES_H__ | ||
43 | #define __EHCA_CLASSES_H__ | ||
44 | |||
45 | #include "ehca_classes.h" | ||
46 | #include "ipz_pt_fn.h" | ||
47 | |||
48 | struct ehca_module; | ||
49 | struct ehca_qp; | ||
50 | struct ehca_cq; | ||
51 | struct ehca_eq; | ||
52 | struct ehca_mr; | ||
53 | struct ehca_mw; | ||
54 | struct ehca_pd; | ||
55 | struct ehca_av; | ||
56 | |||
57 | #ifdef CONFIG_PPC64 | ||
58 | #include "ehca_classes_pSeries.h" | ||
59 | #endif | ||
60 | |||
61 | #include <rdma/ib_verbs.h> | ||
62 | #include <rdma/ib_user_verbs.h> | ||
63 | |||
64 | #include "ehca_irq.h" | ||
65 | |||
66 | struct ehca_eq { | ||
67 | u32 length; | ||
68 | struct ipz_queue ipz_queue; | ||
69 | struct ipz_eq_handle ipz_eq_handle; | ||
70 | struct work_struct work; | ||
71 | struct h_galpas galpas; | ||
72 | int is_initialized; | ||
73 | struct ehca_pfeq pf; | ||
74 | spinlock_t spinlock; | ||
75 | struct tasklet_struct interrupt_task; | ||
76 | u32 ist; | ||
77 | }; | ||
78 | |||
79 | struct ehca_sport { | ||
80 | struct ib_cq *ibcq_aqp1; | ||
81 | struct ib_qp *ibqp_aqp1; | ||
82 | enum ib_rate rate; | ||
83 | enum ib_port_state port_state; | ||
84 | }; | ||
85 | |||
86 | struct ehca_shca { | ||
87 | struct ib_device ib_device; | ||
88 | struct ibmebus_dev *ibmebus_dev; | ||
89 | u8 num_ports; | ||
90 | int hw_level; | ||
91 | struct list_head shca_list; | ||
92 | struct ipz_adapter_handle ipz_hca_handle; | ||
93 | struct ehca_sport sport[2]; | ||
94 | struct ehca_eq eq; | ||
95 | struct ehca_eq neq; | ||
96 | struct ehca_mr *maxmr; | ||
97 | struct ehca_pd *pd; | ||
98 | struct h_galpas galpas; | ||
99 | }; | ||
100 | |||
101 | struct ehca_pd { | ||
102 | struct ib_pd ib_pd; | ||
103 | struct ipz_pd fw_pd; | ||
104 | u32 ownpid; | ||
105 | }; | ||
106 | |||
107 | struct ehca_qp { | ||
108 | struct ib_qp ib_qp; | ||
109 | u32 qp_type; | ||
110 | struct ipz_queue ipz_squeue; | ||
111 | struct ipz_queue ipz_rqueue; | ||
112 | struct h_galpas galpas; | ||
113 | u32 qkey; | ||
114 | u32 real_qp_num; | ||
115 | u32 token; | ||
116 | spinlock_t spinlock_s; | ||
117 | spinlock_t spinlock_r; | ||
118 | u32 sq_max_inline_data_size; | ||
119 | struct ipz_qp_handle ipz_qp_handle; | ||
120 | struct ehca_pfqp pf; | ||
121 | struct ib_qp_init_attr init_attr; | ||
122 | u64 uspace_squeue; | ||
123 | u64 uspace_rqueue; | ||
124 | u64 uspace_fwh; | ||
125 | struct ehca_cq *send_cq; | ||
126 | struct ehca_cq *recv_cq; | ||
127 | unsigned int sqerr_purgeflag; | ||
128 | struct hlist_node list_entries; | ||
129 | }; | ||
130 | |||
131 | /* must be power of 2 */ | ||
132 | #define QP_HASHTAB_LEN 8 | ||
133 | |||
134 | struct ehca_cq { | ||
135 | struct ib_cq ib_cq; | ||
136 | struct ipz_queue ipz_queue; | ||
137 | struct h_galpas galpas; | ||
138 | spinlock_t spinlock; | ||
139 | u32 cq_number; | ||
140 | u32 token; | ||
141 | u32 nr_of_entries; | ||
142 | struct ipz_cq_handle ipz_cq_handle; | ||
143 | struct ehca_pfcq pf; | ||
144 | spinlock_t cb_lock; | ||
145 | u64 uspace_queue; | ||
146 | u64 uspace_fwh; | ||
147 | struct hlist_head qp_hashtab[QP_HASHTAB_LEN]; | ||
148 | struct list_head entry; | ||
149 | u32 nr_callbacks; | ||
150 | spinlock_t task_lock; | ||
151 | u32 ownpid; | ||
152 | }; | ||
153 | |||
154 | enum ehca_mr_flag { | ||
155 | EHCA_MR_FLAG_FMR = 0x80000000, /* FMR, created with ehca_alloc_fmr */ | ||
156 | EHCA_MR_FLAG_MAXMR = 0x40000000, /* max-MR */ | ||
157 | }; | ||
158 | |||
159 | struct ehca_mr { | ||
160 | union { | ||
161 | struct ib_mr ib_mr; /* must always be first in ehca_mr */ | ||
162 | struct ib_fmr ib_fmr; /* must always be first in ehca_mr */ | ||
163 | } ib; | ||
164 | spinlock_t mrlock; | ||
165 | |||
166 | enum ehca_mr_flag flags; | ||
167 | u32 num_pages; /* number of MR pages */ | ||
168 | u32 num_4k; /* number of 4k "page" portions to form MR */ | ||
169 | int acl; /* ACL (stored here for usage in reregister) */ | ||
170 | u64 *start; /* virtual start address (stored here for */ | ||
171 | /* usage in reregister) */ | ||
172 | u64 size; /* size (stored here for usage in reregister) */ | ||
173 | u32 fmr_page_size; /* page size for FMR */ | ||
174 | u32 fmr_max_pages; /* max pages for FMR */ | ||
175 | u32 fmr_max_maps; /* max outstanding maps for FMR */ | ||
176 | u32 fmr_map_cnt; /* map counter for FMR */ | ||
177 | /* fw specific data */ | ||
178 | struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */ | ||
179 | struct h_galpas galpas; | ||
180 | /* data for userspace bridge */ | ||
181 | u32 nr_of_pages; | ||
182 | void *pagearray; | ||
183 | }; | ||
184 | |||
185 | struct ehca_mw { | ||
186 | struct ib_mw ib_mw; /* gen2 mw, must always be first in ehca_mw */ | ||
187 | spinlock_t mwlock; | ||
188 | |||
189 | u8 never_bound; /* indication MW was never bound */ | ||
190 | struct ipz_mrmw_handle ipz_mw_handle; /* MW handle for h-calls */ | ||
191 | struct h_galpas galpas; | ||
192 | }; | ||
193 | |||
194 | enum ehca_mr_pgi_type { | ||
195 | EHCA_MR_PGI_PHYS = 1, /* type of ehca_reg_phys_mr, | ||
196 | * ehca_rereg_phys_mr, | ||
197 | * ehca_reg_internal_maxmr */ | ||
198 | EHCA_MR_PGI_USER = 2, /* type of ehca_reg_user_mr */ | ||
199 | EHCA_MR_PGI_FMR = 3 /* type of ehca_map_phys_fmr */ | ||
200 | }; | ||
201 | |||
202 | struct ehca_mr_pginfo { | ||
203 | enum ehca_mr_pgi_type type; | ||
204 | u64 num_pages; | ||
205 | u64 page_cnt; | ||
206 | u64 num_4k; /* number of 4k "page" portions */ | ||
207 | u64 page_4k_cnt; /* counter for 4k "page" portions */ | ||
208 | u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */ | ||
209 | |||
210 | /* type EHCA_MR_PGI_PHYS section */ | ||
211 | int num_phys_buf; | ||
212 | struct ib_phys_buf *phys_buf_array; | ||
213 | u64 next_buf; | ||
214 | |||
215 | /* type EHCA_MR_PGI_USER section */ | ||
216 | struct ib_umem *region; | ||
217 | struct ib_umem_chunk *next_chunk; | ||
218 | u64 next_nmap; | ||
219 | |||
220 | /* type EHCA_MR_PGI_FMR section */ | ||
221 | u64 *page_list; | ||
222 | u64 next_listelem; | ||
223 | /* next_4k also used within EHCA_MR_PGI_FMR */ | ||
224 | }; | ||
225 | |||
226 | /* output parameters for MR/FMR hipz calls */ | ||
227 | struct ehca_mr_hipzout_parms { | ||
228 | struct ipz_mrmw_handle handle; | ||
229 | u32 lkey; | ||
230 | u32 rkey; | ||
231 | u64 len; | ||
232 | u64 vaddr; | ||
233 | u32 acl; | ||
234 | }; | ||
235 | |||
236 | /* output parameters for MW hipz calls */ | ||
237 | struct ehca_mw_hipzout_parms { | ||
238 | struct ipz_mrmw_handle handle; | ||
239 | u32 rkey; | ||
240 | }; | ||
241 | |||
242 | struct ehca_av { | ||
243 | struct ib_ah ib_ah; | ||
244 | struct ehca_ud_av av; | ||
245 | }; | ||
246 | |||
247 | struct ehca_ucontext { | ||
248 | struct ib_ucontext ib_ucontext; | ||
249 | }; | ||
250 | |||
251 | struct ehca_module *ehca_module_new(void); | ||
252 | |||
253 | int ehca_module_delete(struct ehca_module *me); | ||
254 | |||
255 | int ehca_eq_ctor(struct ehca_eq *eq); | ||
256 | |||
257 | int ehca_eq_dtor(struct ehca_eq *eq); | ||
258 | |||
259 | struct ehca_shca *ehca_shca_new(void); | ||
260 | |||
261 | int ehca_shca_delete(struct ehca_shca *me); | ||
262 | |||
263 | struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor); | ||
264 | |||
265 | int ehca_init_pd_cache(void); | ||
266 | void ehca_cleanup_pd_cache(void); | ||
267 | int ehca_init_cq_cache(void); | ||
268 | void ehca_cleanup_cq_cache(void); | ||
269 | int ehca_init_qp_cache(void); | ||
270 | void ehca_cleanup_qp_cache(void); | ||
271 | int ehca_init_av_cache(void); | ||
272 | void ehca_cleanup_av_cache(void); | ||
273 | int ehca_init_mrmw_cache(void); | ||
274 | void ehca_cleanup_mrmw_cache(void); | ||
275 | |||
276 | extern spinlock_t ehca_qp_idr_lock; | ||
277 | extern spinlock_t ehca_cq_idr_lock; | ||
278 | extern struct idr ehca_qp_idr; | ||
279 | extern struct idr ehca_cq_idr; | ||
280 | |||
281 | extern int ehca_static_rate; | ||
282 | extern int ehca_port_act_time; | ||
283 | extern int ehca_use_hp_mr; | ||
284 | |||
285 | struct ipzu_queue_resp { | ||
286 | u64 queue; /* points to first queue entry */ | ||
287 | u32 qe_size; /* queue entry size */ | ||
288 | u32 act_nr_of_sg; | ||
289 | u32 queue_length; /* queue length allocated in bytes */ | ||
290 | u32 pagesize; | ||
291 | u32 toggle_state; | ||
292 | u32 dummy; /* padding for 8 byte alignment */ | ||
293 | }; | ||
294 | |||
295 | struct ehca_create_cq_resp { | ||
296 | u32 cq_number; | ||
297 | u32 token; | ||
298 | struct ipzu_queue_resp ipz_queue; | ||
299 | struct h_galpas galpas; | ||
300 | }; | ||
301 | |||
302 | struct ehca_create_qp_resp { | ||
303 | u32 qp_num; | ||
304 | u32 token; | ||
305 | u32 qp_type; | ||
306 | u32 qkey; | ||
307 | /* qp_num assigned by ehca: sqp0/1 may have got different numbers */ | ||
308 | u32 real_qp_num; | ||
309 | u32 dummy; /* padding for 8 byte alignment */ | ||
310 | struct ipzu_queue_resp ipz_squeue; | ||
311 | struct ipzu_queue_resp ipz_rqueue; | ||
312 | struct h_galpas galpas; | ||
313 | }; | ||
314 | |||
315 | struct ehca_alloc_cq_parms { | ||
316 | u32 nr_cqe; | ||
317 | u32 act_nr_of_entries; | ||
318 | u32 act_pages; | ||
319 | struct ipz_eq_handle eq_handle; | ||
320 | }; | ||
321 | |||
322 | struct ehca_alloc_qp_parms { | ||
323 | int servicetype; | ||
324 | int sigtype; | ||
325 | int daqp_ctrl; | ||
326 | int max_send_sge; | ||
327 | int max_recv_sge; | ||
328 | int ud_av_l_key_ctl; | ||
329 | |||
330 | u16 act_nr_send_wqes; | ||
331 | u16 act_nr_recv_wqes; | ||
332 | u8 act_nr_recv_sges; | ||
333 | u8 act_nr_send_sges; | ||
334 | |||
335 | u32 nr_rq_pages; | ||
336 | u32 nr_sq_pages; | ||
337 | |||
338 | struct ipz_eq_handle ipz_eq_handle; | ||
339 | struct ipz_pd pd; | ||
340 | }; | ||
341 | |||
342 | int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp); | ||
343 | int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num); | ||
344 | struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num); | ||
345 | |||
346 | #endif | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h new file mode 100644 index 000000000000..5665f213b81a --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * pSeries interface definitions | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Christoph Raisch <raisch@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #ifndef __EHCA_CLASSES_PSERIES_H__ | ||
43 | #define __EHCA_CLASSES_PSERIES_H__ | ||
44 | |||
45 | #include "hcp_phyp.h" | ||
46 | #include "ipz_pt_fn.h" | ||
47 | |||
48 | |||
49 | struct ehca_pfqp { | ||
50 | struct ipz_qpt sqpt; | ||
51 | struct ipz_qpt rqpt; | ||
52 | }; | ||
53 | |||
54 | struct ehca_pfcq { | ||
55 | struct ipz_qpt qpt; | ||
56 | u32 cqnr; | ||
57 | }; | ||
58 | |||
59 | struct ehca_pfeq { | ||
60 | struct ipz_qpt qpt; | ||
61 | struct h_galpa galpa; | ||
62 | u32 eqnr; | ||
63 | }; | ||
64 | |||
65 | struct ipz_adapter_handle { | ||
66 | u64 handle; | ||
67 | }; | ||
68 | |||
69 | struct ipz_cq_handle { | ||
70 | u64 handle; | ||
71 | }; | ||
72 | |||
73 | struct ipz_eq_handle { | ||
74 | u64 handle; | ||
75 | }; | ||
76 | |||
77 | struct ipz_qp_handle { | ||
78 | u64 handle; | ||
79 | }; | ||
80 | struct ipz_mrmw_handle { | ||
81 | u64 handle; | ||
82 | }; | ||
83 | |||
84 | struct ipz_pd { | ||
85 | u32 value; | ||
86 | }; | ||
87 | |||
88 | struct hcp_modify_qp_control_block { | ||
89 | u32 qkey; /* 00 */ | ||
90 | u32 rdd; /* reliable datagram domain */ | ||
91 | u32 send_psn; /* 02 */ | ||
92 | u32 receive_psn; /* 03 */ | ||
93 | u32 prim_phys_port; /* 04 */ | ||
94 | u32 alt_phys_port; /* 05 */ | ||
95 | u32 prim_p_key_idx; /* 06 */ | ||
96 | u32 alt_p_key_idx; /* 07 */ | ||
97 | u32 rdma_atomic_ctrl; /* 08 */ | ||
98 | u32 qp_state; /* 09 */ | ||
99 | u32 reserved_10; /* 10 */ | ||
100 | u32 rdma_nr_atomic_resp_res; /* 11 */ | ||
101 | u32 path_migration_state; /* 12 */ | ||
102 | u32 rdma_atomic_outst_dest_qp; /* 13 */ | ||
103 | u32 dest_qp_nr; /* 14 */ | ||
104 | u32 min_rnr_nak_timer_field; /* 15 */ | ||
105 | u32 service_level; /* 16 */ | ||
106 | u32 send_grh_flag; /* 17 */ | ||
107 | u32 retry_count; /* 18 */ | ||
108 | u32 timeout; /* 19 */ | ||
109 | u32 path_mtu; /* 20 */ | ||
110 | u32 max_static_rate; /* 21 */ | ||
111 | u32 dlid; /* 22 */ | ||
112 | u32 rnr_retry_count; /* 23 */ | ||
113 | u32 source_path_bits; /* 24 */ | ||
114 | u32 traffic_class; /* 25 */ | ||
115 | u32 hop_limit; /* 26 */ | ||
116 | u32 source_gid_idx; /* 27 */ | ||
117 | u32 flow_label; /* 28 */ | ||
118 | u32 reserved_29; /* 29 */ | ||
119 | union { /* 30 */ | ||
120 | u64 dw[2]; | ||
121 | u8 byte[16]; | ||
122 | } dest_gid; | ||
123 | u32 service_level_al; /* 34 */ | ||
124 | u32 send_grh_flag_al; /* 35 */ | ||
125 | u32 retry_count_al; /* 36 */ | ||
126 | u32 timeout_al; /* 37 */ | ||
127 | u32 max_static_rate_al; /* 38 */ | ||
128 | u32 dlid_al; /* 39 */ | ||
129 | u32 rnr_retry_count_al; /* 40 */ | ||
130 | u32 source_path_bits_al; /* 41 */ | ||
131 | u32 traffic_class_al; /* 42 */ | ||
132 | u32 hop_limit_al; /* 43 */ | ||
133 | u32 source_gid_idx_al; /* 44 */ | ||
134 | u32 flow_label_al; /* 45 */ | ||
135 | u32 reserved_46; /* 46 */ | ||
136 | u32 reserved_47; /* 47 */ | ||
137 | union { /* 48 */ | ||
138 | u64 dw[2]; | ||
139 | u8 byte[16]; | ||
140 | } dest_gid_al; | ||
141 | u32 max_nr_outst_send_wr; /* 52 */ | ||
142 | u32 max_nr_outst_recv_wr; /* 53 */ | ||
143 | u32 disable_ete_credit_check; /* 54 */ | ||
144 | u32 qp_number; /* 55 */ | ||
145 | u64 send_queue_handle; /* 56 */ | ||
146 | u64 recv_queue_handle; /* 58 */ | ||
147 | u32 actual_nr_sges_in_sq_wqe; /* 60 */ | ||
148 | u32 actual_nr_sges_in_rq_wqe; /* 61 */ | ||
149 | u32 qp_enable; /* 62 */ | ||
150 | u32 curr_srq_limit; /* 63 */ | ||
151 | u64 qp_aff_asyn_ev_log_reg; /* 64 */ | ||
152 | u64 shared_rq_hndl; /* 66 */ | ||
153 | u64 trigg_doorbell_qp_hndl; /* 68 */ | ||
154 | u32 reserved_70_127[58]; /* 70 */ | ||
155 | }; | ||
156 | |||
157 | #define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0) | ||
158 | #define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2) | ||
159 | #define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3) | ||
160 | #define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4) | ||
161 | #define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31) | ||
162 | #define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5) | ||
163 | #define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6) | ||
164 | #define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31) | ||
165 | #define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7) | ||
166 | #define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8) | ||
167 | #define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9) | ||
168 | #define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31) | ||
169 | #define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11) | ||
170 | #define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12) | ||
171 | #define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13) | ||
172 | #define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14) | ||
173 | #define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15) | ||
174 | #define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16) | ||
175 | #define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17) | ||
176 | #define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18) | ||
177 | #define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19) | ||
178 | #define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20) | ||
179 | #define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31) | ||
180 | #define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21) | ||
181 | #define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31) | ||
182 | #define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22) | ||
183 | #define MQPCB_DLID EHCA_BMASK_IBM(16,31) | ||
184 | #define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23) | ||
185 | #define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31) | ||
186 | #define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24) | ||
187 | #define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31) | ||
188 | #define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25) | ||
189 | #define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31) | ||
190 | #define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26) | ||
191 | #define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31) | ||
192 | #define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27) | ||
193 | #define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31) | ||
194 | #define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28) | ||
195 | #define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31) | ||
196 | #define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30) | ||
197 | #define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31) | ||
198 | #define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31) | ||
199 | #define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32) | ||
200 | #define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31) | ||
201 | #define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33) | ||
202 | #define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31) | ||
203 | #define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34) | ||
204 | #define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31) | ||
205 | #define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35) | ||
206 | #define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31) | ||
207 | #define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36) | ||
208 | #define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31) | ||
209 | #define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37) | ||
210 | #define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31) | ||
211 | #define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38) | ||
212 | #define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31) | ||
213 | #define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39) | ||
214 | #define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31) | ||
215 | #define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40) | ||
216 | #define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31) | ||
217 | #define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41) | ||
218 | #define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31) | ||
219 | #define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42) | ||
220 | #define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31) | ||
221 | #define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44) | ||
222 | #define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45) | ||
223 | #define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31) | ||
224 | #define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46) | ||
225 | #define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31) | ||
226 | #define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47) | ||
227 | #define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31) | ||
228 | #define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31) | ||
229 | #define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48) | ||
230 | #define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31) | ||
231 | #define MQPCB_MASK_CURR_SQR_LIMIT EHCA_BMASK_IBM(49,49) | ||
232 | #define MQPCB_CURR_SQR_LIMIT EHCA_BMASK_IBM(15,31) | ||
233 | #define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50) | ||
234 | #define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51) | ||
235 | |||
236 | #endif /* __EHCA_CLASSES_PSERIES_H__ */ | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c new file mode 100644 index 000000000000..458fe19648a1 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_cq.c | |||
@@ -0,0 +1,427 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Completion queue handling | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Khadija Souissi <souissi@de.ibm.com> | ||
8 | * Reinhard Ernst <rernst@de.ibm.com> | ||
9 | * Heiko J Schick <schickhj@de.ibm.com> | ||
10 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
11 | * | ||
12 | * | ||
13 | * Copyright (c) 2005 IBM Corporation | ||
14 | * | ||
15 | * All rights reserved. | ||
16 | * | ||
17 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
18 | * BSD. | ||
19 | * | ||
20 | * OpenIB BSD License | ||
21 | * | ||
22 | * Redistribution and use in source and binary forms, with or without | ||
23 | * modification, are permitted provided that the following conditions are met: | ||
24 | * | ||
25 | * Redistributions of source code must retain the above copyright notice, this | ||
26 | * list of conditions and the following disclaimer. | ||
27 | * | ||
28 | * Redistributions in binary form must reproduce the above copyright notice, | ||
29 | * this list of conditions and the following disclaimer in the documentation | ||
30 | * and/or other materials | ||
31 | * provided with the distribution. | ||
32 | * | ||
33 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
34 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
35 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
36 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
37 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
38 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
39 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
40 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
41 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
42 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
43 | * POSSIBILITY OF SUCH DAMAGE. | ||
44 | */ | ||
45 | |||
46 | #include <asm/current.h> | ||
47 | |||
48 | #include "ehca_iverbs.h" | ||
49 | #include "ehca_classes.h" | ||
50 | #include "ehca_irq.h" | ||
51 | #include "hcp_if.h" | ||
52 | |||
53 | static struct kmem_cache *cq_cache; | ||
54 | |||
55 | int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp) | ||
56 | { | ||
57 | unsigned int qp_num = qp->real_qp_num; | ||
58 | unsigned int key = qp_num & (QP_HASHTAB_LEN-1); | ||
59 | unsigned long spl_flags; | ||
60 | |||
61 | spin_lock_irqsave(&cq->spinlock, spl_flags); | ||
62 | hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]); | ||
63 | spin_unlock_irqrestore(&cq->spinlock, spl_flags); | ||
64 | |||
65 | ehca_dbg(cq->ib_cq.device, "cq_num=%x real_qp_num=%x", | ||
66 | cq->cq_number, qp_num); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num) | ||
72 | { | ||
73 | int ret = -EINVAL; | ||
74 | unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1); | ||
75 | struct hlist_node *iter; | ||
76 | struct ehca_qp *qp; | ||
77 | unsigned long spl_flags; | ||
78 | |||
79 | spin_lock_irqsave(&cq->spinlock, spl_flags); | ||
80 | hlist_for_each(iter, &cq->qp_hashtab[key]) { | ||
81 | qp = hlist_entry(iter, struct ehca_qp, list_entries); | ||
82 | if (qp->real_qp_num == real_qp_num) { | ||
83 | hlist_del(iter); | ||
84 | ehca_dbg(cq->ib_cq.device, | ||
85 | "removed qp from cq .cq_num=%x real_qp_num=%x", | ||
86 | cq->cq_number, real_qp_num); | ||
87 | ret = 0; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | spin_unlock_irqrestore(&cq->spinlock, spl_flags); | ||
92 | if (ret) | ||
93 | ehca_err(cq->ib_cq.device, | ||
94 | "qp not found cq_num=%x real_qp_num=%x", | ||
95 | cq->cq_number, real_qp_num); | ||
96 | |||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num) | ||
101 | { | ||
102 | struct ehca_qp *ret = NULL; | ||
103 | unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1); | ||
104 | struct hlist_node *iter; | ||
105 | struct ehca_qp *qp; | ||
106 | hlist_for_each(iter, &cq->qp_hashtab[key]) { | ||
107 | qp = hlist_entry(iter, struct ehca_qp, list_entries); | ||
108 | if (qp->real_qp_num == real_qp_num) { | ||
109 | ret = qp; | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, | ||
117 | struct ib_ucontext *context, | ||
118 | struct ib_udata *udata) | ||
119 | { | ||
120 | static const u32 additional_cqe = 20; | ||
121 | struct ib_cq *cq; | ||
122 | struct ehca_cq *my_cq; | ||
123 | struct ehca_shca *shca = | ||
124 | container_of(device, struct ehca_shca, ib_device); | ||
125 | struct ipz_adapter_handle adapter_handle; | ||
126 | struct ehca_alloc_cq_parms param; /* h_call's out parameters */ | ||
127 | struct h_galpa gal; | ||
128 | void *vpage; | ||
129 | u32 counter; | ||
130 | u64 rpage, cqx_fec, h_ret; | ||
131 | int ipz_rc, ret, i; | ||
132 | unsigned long flags; | ||
133 | |||
134 | if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) | ||
135 | return ERR_PTR(-EINVAL); | ||
136 | |||
137 | my_cq = kmem_cache_alloc(cq_cache, SLAB_KERNEL); | ||
138 | if (!my_cq) { | ||
139 | ehca_err(device, "Out of memory for ehca_cq struct device=%p", | ||
140 | device); | ||
141 | return ERR_PTR(-ENOMEM); | ||
142 | } | ||
143 | |||
144 | memset(my_cq, 0, sizeof(struct ehca_cq)); | ||
145 | memset(¶m, 0, sizeof(struct ehca_alloc_cq_parms)); | ||
146 | |||
147 | spin_lock_init(&my_cq->spinlock); | ||
148 | spin_lock_init(&my_cq->cb_lock); | ||
149 | spin_lock_init(&my_cq->task_lock); | ||
150 | my_cq->ownpid = current->tgid; | ||
151 | |||
152 | cq = &my_cq->ib_cq; | ||
153 | |||
154 | adapter_handle = shca->ipz_hca_handle; | ||
155 | param.eq_handle = shca->eq.ipz_eq_handle; | ||
156 | |||
157 | do { | ||
158 | if (!idr_pre_get(&ehca_cq_idr, GFP_KERNEL)) { | ||
159 | cq = ERR_PTR(-ENOMEM); | ||
160 | ehca_err(device, "Can't reserve idr nr. device=%p", | ||
161 | device); | ||
162 | goto create_cq_exit1; | ||
163 | } | ||
164 | |||
165 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | ||
166 | ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token); | ||
167 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | ||
168 | |||
169 | } while (ret == -EAGAIN); | ||
170 | |||
171 | if (ret) { | ||
172 | cq = ERR_PTR(-ENOMEM); | ||
173 | ehca_err(device, "Can't allocate new idr entry. device=%p", | ||
174 | device); | ||
175 | goto create_cq_exit1; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * CQs maximum depth is 4GB-64, but we need additional 20 as buffer | ||
180 | * for receiving errors CQEs. | ||
181 | */ | ||
182 | param.nr_cqe = cqe + additional_cqe; | ||
183 | h_ret = hipz_h_alloc_resource_cq(adapter_handle, my_cq, ¶m); | ||
184 | |||
185 | if (h_ret != H_SUCCESS) { | ||
186 | ehca_err(device, "hipz_h_alloc_resource_cq() failed " | ||
187 | "h_ret=%lx device=%p", h_ret, device); | ||
188 | cq = ERR_PTR(ehca2ib_return_code(h_ret)); | ||
189 | goto create_cq_exit2; | ||
190 | } | ||
191 | |||
192 | ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages, | ||
193 | EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0); | ||
194 | if (!ipz_rc) { | ||
195 | ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p", | ||
196 | ipz_rc, device); | ||
197 | cq = ERR_PTR(-EINVAL); | ||
198 | goto create_cq_exit3; | ||
199 | } | ||
200 | |||
201 | for (counter = 0; counter < param.act_pages; counter++) { | ||
202 | vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue); | ||
203 | if (!vpage) { | ||
204 | ehca_err(device, "ipz_qpageit_get_inc() " | ||
205 | "returns NULL device=%p", device); | ||
206 | cq = ERR_PTR(-EAGAIN); | ||
207 | goto create_cq_exit4; | ||
208 | } | ||
209 | rpage = virt_to_abs(vpage); | ||
210 | |||
211 | h_ret = hipz_h_register_rpage_cq(adapter_handle, | ||
212 | my_cq->ipz_cq_handle, | ||
213 | &my_cq->pf, | ||
214 | 0, | ||
215 | 0, | ||
216 | rpage, | ||
217 | 1, | ||
218 | my_cq->galpas. | ||
219 | kernel); | ||
220 | |||
221 | if (h_ret < H_SUCCESS) { | ||
222 | ehca_err(device, "hipz_h_register_rpage_cq() failed " | ||
223 | "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i " | ||
224 | "act_pages=%i", my_cq, my_cq->cq_number, | ||
225 | h_ret, counter, param.act_pages); | ||
226 | cq = ERR_PTR(-EINVAL); | ||
227 | goto create_cq_exit4; | ||
228 | } | ||
229 | |||
230 | if (counter == (param.act_pages - 1)) { | ||
231 | vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue); | ||
232 | if ((h_ret != H_SUCCESS) || vpage) { | ||
233 | ehca_err(device, "Registration of pages not " | ||
234 | "complete ehca_cq=%p cq_num=%x " | ||
235 | "h_ret=%lx", my_cq, my_cq->cq_number, | ||
236 | h_ret); | ||
237 | cq = ERR_PTR(-EAGAIN); | ||
238 | goto create_cq_exit4; | ||
239 | } | ||
240 | } else { | ||
241 | if (h_ret != H_PAGE_REGISTERED) { | ||
242 | ehca_err(device, "Registration of page failed " | ||
243 | "ehca_cq=%p cq_num=%x h_ret=%lx" | ||
244 | "counter=%i act_pages=%i", | ||
245 | my_cq, my_cq->cq_number, | ||
246 | h_ret, counter, param.act_pages); | ||
247 | cq = ERR_PTR(-ENOMEM); | ||
248 | goto create_cq_exit4; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | |||
253 | ipz_qeit_reset(&my_cq->ipz_queue); | ||
254 | |||
255 | gal = my_cq->galpas.kernel; | ||
256 | cqx_fec = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_fec)); | ||
257 | ehca_dbg(device, "ehca_cq=%p cq_num=%x CQX_FEC=%lx", | ||
258 | my_cq, my_cq->cq_number, cqx_fec); | ||
259 | |||
260 | my_cq->ib_cq.cqe = my_cq->nr_of_entries = | ||
261 | param.act_nr_of_entries - additional_cqe; | ||
262 | my_cq->cq_number = (my_cq->ipz_cq_handle.handle) & 0xffff; | ||
263 | |||
264 | for (i = 0; i < QP_HASHTAB_LEN; i++) | ||
265 | INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]); | ||
266 | |||
267 | if (context) { | ||
268 | struct ipz_queue *ipz_queue = &my_cq->ipz_queue; | ||
269 | struct ehca_create_cq_resp resp; | ||
270 | struct vm_area_struct *vma; | ||
271 | memset(&resp, 0, sizeof(resp)); | ||
272 | resp.cq_number = my_cq->cq_number; | ||
273 | resp.token = my_cq->token; | ||
274 | resp.ipz_queue.qe_size = ipz_queue->qe_size; | ||
275 | resp.ipz_queue.act_nr_of_sg = ipz_queue->act_nr_of_sg; | ||
276 | resp.ipz_queue.queue_length = ipz_queue->queue_length; | ||
277 | resp.ipz_queue.pagesize = ipz_queue->pagesize; | ||
278 | resp.ipz_queue.toggle_state = ipz_queue->toggle_state; | ||
279 | ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000, | ||
280 | ipz_queue->queue_length, | ||
281 | (void**)&resp.ipz_queue.queue, | ||
282 | &vma); | ||
283 | if (ret) { | ||
284 | ehca_err(device, "Could not mmap queue pages"); | ||
285 | cq = ERR_PTR(ret); | ||
286 | goto create_cq_exit4; | ||
287 | } | ||
288 | my_cq->uspace_queue = resp.ipz_queue.queue; | ||
289 | resp.galpas = my_cq->galpas; | ||
290 | ret = ehca_mmap_register(my_cq->galpas.user.fw_handle, | ||
291 | (void**)&resp.galpas.kernel.fw_handle, | ||
292 | &vma); | ||
293 | if (ret) { | ||
294 | ehca_err(device, "Could not mmap fw_handle"); | ||
295 | cq = ERR_PTR(ret); | ||
296 | goto create_cq_exit5; | ||
297 | } | ||
298 | my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle; | ||
299 | if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { | ||
300 | ehca_err(device, "Copy to udata failed."); | ||
301 | goto create_cq_exit6; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | return cq; | ||
306 | |||
307 | create_cq_exit6: | ||
308 | ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE); | ||
309 | |||
310 | create_cq_exit5: | ||
311 | ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length); | ||
312 | |||
313 | create_cq_exit4: | ||
314 | ipz_queue_dtor(&my_cq->ipz_queue); | ||
315 | |||
316 | create_cq_exit3: | ||
317 | h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1); | ||
318 | if (h_ret != H_SUCCESS) | ||
319 | ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p " | ||
320 | "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret); | ||
321 | |||
322 | create_cq_exit2: | ||
323 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | ||
324 | idr_remove(&ehca_cq_idr, my_cq->token); | ||
325 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | ||
326 | |||
327 | create_cq_exit1: | ||
328 | kmem_cache_free(cq_cache, my_cq); | ||
329 | |||
330 | return cq; | ||
331 | } | ||
332 | |||
333 | int ehca_destroy_cq(struct ib_cq *cq) | ||
334 | { | ||
335 | u64 h_ret; | ||
336 | int ret; | ||
337 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); | ||
338 | int cq_num = my_cq->cq_number; | ||
339 | struct ib_device *device = cq->device; | ||
340 | struct ehca_shca *shca = container_of(device, struct ehca_shca, | ||
341 | ib_device); | ||
342 | struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle; | ||
343 | u32 cur_pid = current->tgid; | ||
344 | unsigned long flags; | ||
345 | |||
346 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | ||
347 | while (my_cq->nr_callbacks) | ||
348 | yield(); | ||
349 | |||
350 | idr_remove(&ehca_cq_idr, my_cq->token); | ||
351 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | ||
352 | |||
353 | if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) { | ||
354 | ehca_err(device, "Invalid caller pid=%x ownpid=%x", | ||
355 | cur_pid, my_cq->ownpid); | ||
356 | return -EINVAL; | ||
357 | } | ||
358 | |||
359 | /* un-mmap if vma alloc */ | ||
360 | if (my_cq->uspace_queue ) { | ||
361 | ret = ehca_munmap(my_cq->uspace_queue, | ||
362 | my_cq->ipz_queue.queue_length); | ||
363 | if (ret) | ||
364 | ehca_err(device, "Could not munmap queue ehca_cq=%p " | ||
365 | "cq_num=%x", my_cq, cq_num); | ||
366 | ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE); | ||
367 | if (ret) | ||
368 | ehca_err(device, "Could not munmap fwh ehca_cq=%p " | ||
369 | "cq_num=%x", my_cq, cq_num); | ||
370 | } | ||
371 | |||
372 | h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0); | ||
373 | if (h_ret == H_R_STATE) { | ||
374 | /* cq in err: read err data and destroy it forcibly */ | ||
375 | ehca_dbg(device, "ehca_cq=%p cq_num=%x ressource=%lx in err " | ||
376 | "state. Try to delete it forcibly.", | ||
377 | my_cq, cq_num, my_cq->ipz_cq_handle.handle); | ||
378 | ehca_error_data(shca, my_cq, my_cq->ipz_cq_handle.handle); | ||
379 | h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1); | ||
380 | if (h_ret == H_SUCCESS) | ||
381 | ehca_dbg(device, "cq_num=%x deleted successfully.", | ||
382 | cq_num); | ||
383 | } | ||
384 | if (h_ret != H_SUCCESS) { | ||
385 | ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx " | ||
386 | "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num); | ||
387 | return ehca2ib_return_code(h_ret); | ||
388 | } | ||
389 | ipz_queue_dtor(&my_cq->ipz_queue); | ||
390 | kmem_cache_free(cq_cache, my_cq); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata) | ||
396 | { | ||
397 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); | ||
398 | u32 cur_pid = current->tgid; | ||
399 | |||
400 | if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) { | ||
401 | ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x", | ||
402 | cur_pid, my_cq->ownpid); | ||
403 | return -EINVAL; | ||
404 | } | ||
405 | |||
406 | /* TODO: proper resize needs to be done */ | ||
407 | ehca_err(cq->device, "not implemented yet"); | ||
408 | |||
409 | return -EFAULT; | ||
410 | } | ||
411 | |||
412 | int ehca_init_cq_cache(void) | ||
413 | { | ||
414 | cq_cache = kmem_cache_create("ehca_cache_cq", | ||
415 | sizeof(struct ehca_cq), 0, | ||
416 | SLAB_HWCACHE_ALIGN, | ||
417 | NULL, NULL); | ||
418 | if (!cq_cache) | ||
419 | return -ENOMEM; | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | void ehca_cleanup_cq_cache(void) | ||
424 | { | ||
425 | if (cq_cache) | ||
426 | kmem_cache_destroy(cq_cache); | ||
427 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c new file mode 100644 index 000000000000..5281dec66f12 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_eq.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Event queue handling | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Khadija Souissi <souissi@de.ibm.com> | ||
8 | * Reinhard Ernst <rernst@de.ibm.com> | ||
9 | * Heiko J Schick <schickhj@de.ibm.com> | ||
10 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
11 | * | ||
12 | * | ||
13 | * Copyright (c) 2005 IBM Corporation | ||
14 | * | ||
15 | * All rights reserved. | ||
16 | * | ||
17 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
18 | * BSD. | ||
19 | * | ||
20 | * OpenIB BSD License | ||
21 | * | ||
22 | * Redistribution and use in source and binary forms, with or without | ||
23 | * modification, are permitted provided that the following conditions are met: | ||
24 | * | ||
25 | * Redistributions of source code must retain the above copyright notice, this | ||
26 | * list of conditions and the following disclaimer. | ||
27 | * | ||
28 | * Redistributions in binary form must reproduce the above copyright notice, | ||
29 | * this list of conditions and the following disclaimer in the documentation | ||
30 | * and/or other materials | ||
31 | * provided with the distribution. | ||
32 | * | ||
33 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
34 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
35 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
36 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
37 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
38 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
39 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
40 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
41 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
42 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
43 | * POSSIBILITY OF SUCH DAMAGE. | ||
44 | */ | ||
45 | |||
46 | #include "ehca_classes.h" | ||
47 | #include "ehca_irq.h" | ||
48 | #include "ehca_iverbs.h" | ||
49 | #include "ehca_qes.h" | ||
50 | #include "hcp_if.h" | ||
51 | #include "ipz_pt_fn.h" | ||
52 | |||
53 | int ehca_create_eq(struct ehca_shca *shca, | ||
54 | struct ehca_eq *eq, | ||
55 | const enum ehca_eq_type type, const u32 length) | ||
56 | { | ||
57 | u64 ret; | ||
58 | u32 nr_pages; | ||
59 | u32 i; | ||
60 | void *vpage; | ||
61 | struct ib_device *ib_dev = &shca->ib_device; | ||
62 | |||
63 | spin_lock_init(&eq->spinlock); | ||
64 | eq->is_initialized = 0; | ||
65 | |||
66 | if (type != EHCA_EQ && type != EHCA_NEQ) { | ||
67 | ehca_err(ib_dev, "Invalid EQ type %x. eq=%p", type, eq); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | if (!length) { | ||
71 | ehca_err(ib_dev, "EQ length must not be zero. eq=%p", eq); | ||
72 | return -EINVAL; | ||
73 | } | ||
74 | |||
75 | ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle, | ||
76 | &eq->pf, | ||
77 | type, | ||
78 | length, | ||
79 | &eq->ipz_eq_handle, | ||
80 | &eq->length, | ||
81 | &nr_pages, &eq->ist); | ||
82 | |||
83 | if (ret != H_SUCCESS) { | ||
84 | ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | |||
88 | ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages, | ||
89 | EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0); | ||
90 | if (!ret) { | ||
91 | ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq); | ||
92 | goto create_eq_exit1; | ||
93 | } | ||
94 | |||
95 | for (i = 0; i < nr_pages; i++) { | ||
96 | u64 rpage; | ||
97 | |||
98 | if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) { | ||
99 | ret = H_RESOURCE; | ||
100 | goto create_eq_exit2; | ||
101 | } | ||
102 | |||
103 | rpage = virt_to_abs(vpage); | ||
104 | ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, | ||
105 | eq->ipz_eq_handle, | ||
106 | &eq->pf, | ||
107 | 0, 0, rpage, 1); | ||
108 | |||
109 | if (i == (nr_pages - 1)) { | ||
110 | /* last page */ | ||
111 | vpage = ipz_qpageit_get_inc(&eq->ipz_queue); | ||
112 | if (ret != H_SUCCESS || vpage) | ||
113 | goto create_eq_exit2; | ||
114 | } else { | ||
115 | if (ret != H_PAGE_REGISTERED || !vpage) | ||
116 | goto create_eq_exit2; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | ipz_qeit_reset(&eq->ipz_queue); | ||
121 | |||
122 | /* register interrupt handlers and initialize work queues */ | ||
123 | if (type == EHCA_EQ) { | ||
124 | ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_eq, | ||
125 | SA_INTERRUPT, "ehca_eq", | ||
126 | (void *)shca); | ||
127 | if (ret < 0) | ||
128 | ehca_err(ib_dev, "Can't map interrupt handler."); | ||
129 | |||
130 | tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca); | ||
131 | } else if (type == EHCA_NEQ) { | ||
132 | ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_neq, | ||
133 | SA_INTERRUPT, "ehca_neq", | ||
134 | (void *)shca); | ||
135 | if (ret < 0) | ||
136 | ehca_err(ib_dev, "Can't map interrupt handler."); | ||
137 | |||
138 | tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca); | ||
139 | } | ||
140 | |||
141 | eq->is_initialized = 1; | ||
142 | |||
143 | return 0; | ||
144 | |||
145 | create_eq_exit2: | ||
146 | ipz_queue_dtor(&eq->ipz_queue); | ||
147 | |||
148 | create_eq_exit1: | ||
149 | hipz_h_destroy_eq(shca->ipz_hca_handle, eq); | ||
150 | |||
151 | return -EINVAL; | ||
152 | } | ||
153 | |||
154 | void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq) | ||
155 | { | ||
156 | unsigned long flags; | ||
157 | void *eqe; | ||
158 | |||
159 | spin_lock_irqsave(&eq->spinlock, flags); | ||
160 | eqe = ipz_eqit_eq_get_inc_valid(&eq->ipz_queue); | ||
161 | spin_unlock_irqrestore(&eq->spinlock, flags); | ||
162 | |||
163 | return eqe; | ||
164 | } | ||
165 | |||
166 | int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq) | ||
167 | { | ||
168 | unsigned long flags; | ||
169 | u64 h_ret; | ||
170 | |||
171 | spin_lock_irqsave(&eq->spinlock, flags); | ||
172 | ibmebus_free_irq(NULL, eq->ist, (void *)shca); | ||
173 | |||
174 | h_ret = hipz_h_destroy_eq(shca->ipz_hca_handle, eq); | ||
175 | |||
176 | spin_unlock_irqrestore(&eq->spinlock, flags); | ||
177 | |||
178 | if (h_ret != H_SUCCESS) { | ||
179 | ehca_err(&shca->ib_device, "Can't free EQ resources."); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | ipz_queue_dtor(&eq->ipz_queue); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c new file mode 100644 index 000000000000..5eae6ac48425 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_hca.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * HCA query functions | ||
5 | * | ||
6 | * Authors: Heiko J Schick <schickhj@de.ibm.com> | ||
7 | * Christoph Raisch <raisch@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #include "ehca_tools.h" | ||
43 | #include "hcp_if.h" | ||
44 | |||
45 | int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) | ||
46 | { | ||
47 | int ret = 0; | ||
48 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, | ||
49 | ib_device); | ||
50 | struct hipz_query_hca *rblock; | ||
51 | |||
52 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
53 | if (!rblock) { | ||
54 | ehca_err(&shca->ib_device, "Can't allocate rblock memory."); | ||
55 | return -ENOMEM; | ||
56 | } | ||
57 | |||
58 | if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { | ||
59 | ehca_err(&shca->ib_device, "Can't query device properties"); | ||
60 | ret = -EINVAL; | ||
61 | goto query_device1; | ||
62 | } | ||
63 | |||
64 | memset(props, 0, sizeof(struct ib_device_attr)); | ||
65 | props->fw_ver = rblock->hw_ver; | ||
66 | props->max_mr_size = rblock->max_mr_size; | ||
67 | props->vendor_id = rblock->vendor_id >> 8; | ||
68 | props->vendor_part_id = rblock->vendor_part_id >> 16; | ||
69 | props->hw_ver = rblock->hw_ver; | ||
70 | props->max_qp = min_t(int, rblock->max_qp, INT_MAX); | ||
71 | props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX); | ||
72 | props->max_sge = min_t(int, rblock->max_sge, INT_MAX); | ||
73 | props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX); | ||
74 | props->max_cq = min_t(int, rblock->max_cq, INT_MAX); | ||
75 | props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX); | ||
76 | props->max_mr = min_t(int, rblock->max_mr, INT_MAX); | ||
77 | props->max_mw = min_t(int, rblock->max_mw, INT_MAX); | ||
78 | props->max_pd = min_t(int, rblock->max_pd, INT_MAX); | ||
79 | props->max_ah = min_t(int, rblock->max_ah, INT_MAX); | ||
80 | props->max_fmr = min_t(int, rblock->max_mr, INT_MAX); | ||
81 | props->max_srq = 0; | ||
82 | props->max_srq_wr = 0; | ||
83 | props->max_srq_sge = 0; | ||
84 | props->max_pkeys = 16; | ||
85 | props->local_ca_ack_delay | ||
86 | = rblock->local_ca_ack_delay; | ||
87 | props->max_raw_ipv6_qp | ||
88 | = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX); | ||
89 | props->max_raw_ethy_qp | ||
90 | = min_t(int, rblock->max_raw_ethy_qp, INT_MAX); | ||
91 | props->max_mcast_grp | ||
92 | = min_t(int, rblock->max_mcast_grp, INT_MAX); | ||
93 | props->max_mcast_qp_attach | ||
94 | = min_t(int, rblock->max_mcast_qp_attach, INT_MAX); | ||
95 | props->max_total_mcast_qp_attach | ||
96 | = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX); | ||
97 | |||
98 | query_device1: | ||
99 | kfree(rblock); | ||
100 | |||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | int ehca_query_port(struct ib_device *ibdev, | ||
105 | u8 port, struct ib_port_attr *props) | ||
106 | { | ||
107 | int ret = 0; | ||
108 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, | ||
109 | ib_device); | ||
110 | struct hipz_query_port *rblock; | ||
111 | |||
112 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
113 | if (!rblock) { | ||
114 | ehca_err(&shca->ib_device, "Can't allocate rblock memory."); | ||
115 | return -ENOMEM; | ||
116 | } | ||
117 | |||
118 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | ||
119 | ehca_err(&shca->ib_device, "Can't query port properties"); | ||
120 | ret = -EINVAL; | ||
121 | goto query_port1; | ||
122 | } | ||
123 | |||
124 | memset(props, 0, sizeof(struct ib_port_attr)); | ||
125 | props->state = rblock->state; | ||
126 | |||
127 | switch (rblock->max_mtu) { | ||
128 | case 0x1: | ||
129 | props->active_mtu = props->max_mtu = IB_MTU_256; | ||
130 | break; | ||
131 | case 0x2: | ||
132 | props->active_mtu = props->max_mtu = IB_MTU_512; | ||
133 | break; | ||
134 | case 0x3: | ||
135 | props->active_mtu = props->max_mtu = IB_MTU_1024; | ||
136 | break; | ||
137 | case 0x4: | ||
138 | props->active_mtu = props->max_mtu = IB_MTU_2048; | ||
139 | break; | ||
140 | case 0x5: | ||
141 | props->active_mtu = props->max_mtu = IB_MTU_4096; | ||
142 | break; | ||
143 | default: | ||
144 | ehca_err(&shca->ib_device, "Unknown MTU size: %x.", | ||
145 | rblock->max_mtu); | ||
146 | break; | ||
147 | } | ||
148 | |||
149 | props->gid_tbl_len = rblock->gid_tbl_len; | ||
150 | props->max_msg_sz = rblock->max_msg_sz; | ||
151 | props->bad_pkey_cntr = rblock->bad_pkey_cntr; | ||
152 | props->qkey_viol_cntr = rblock->qkey_viol_cntr; | ||
153 | props->pkey_tbl_len = rblock->pkey_tbl_len; | ||
154 | props->lid = rblock->lid; | ||
155 | props->sm_lid = rblock->sm_lid; | ||
156 | props->lmc = rblock->lmc; | ||
157 | props->sm_sl = rblock->sm_sl; | ||
158 | props->subnet_timeout = rblock->subnet_timeout; | ||
159 | props->init_type_reply = rblock->init_type_reply; | ||
160 | |||
161 | props->active_width = IB_WIDTH_12X; | ||
162 | props->active_speed = 0x1; | ||
163 | |||
164 | query_port1: | ||
165 | kfree(rblock); | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) | ||
171 | { | ||
172 | int ret = 0; | ||
173 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device); | ||
174 | struct hipz_query_port *rblock; | ||
175 | |||
176 | if (index > 16) { | ||
177 | ehca_err(&shca->ib_device, "Invalid index: %x.", index); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | |||
181 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
182 | if (!rblock) { | ||
183 | ehca_err(&shca->ib_device, "Can't allocate rblock memory."); | ||
184 | return -ENOMEM; | ||
185 | } | ||
186 | |||
187 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | ||
188 | ehca_err(&shca->ib_device, "Can't query port properties"); | ||
189 | ret = -EINVAL; | ||
190 | goto query_pkey1; | ||
191 | } | ||
192 | |||
193 | memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16)); | ||
194 | |||
195 | query_pkey1: | ||
196 | kfree(rblock); | ||
197 | |||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | int ehca_query_gid(struct ib_device *ibdev, u8 port, | ||
202 | int index, union ib_gid *gid) | ||
203 | { | ||
204 | int ret = 0; | ||
205 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, | ||
206 | ib_device); | ||
207 | struct hipz_query_port *rblock; | ||
208 | |||
209 | if (index > 255) { | ||
210 | ehca_err(&shca->ib_device, "Invalid index: %x.", index); | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | |||
214 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
215 | if (!rblock) { | ||
216 | ehca_err(&shca->ib_device, "Can't allocate rblock memory."); | ||
217 | return -ENOMEM; | ||
218 | } | ||
219 | |||
220 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | ||
221 | ehca_err(&shca->ib_device, "Can't query port properties"); | ||
222 | ret = -EINVAL; | ||
223 | goto query_gid1; | ||
224 | } | ||
225 | |||
226 | memcpy(&gid->raw[0], &rblock->gid_prefix, sizeof(u64)); | ||
227 | memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64)); | ||
228 | |||
229 | query_gid1: | ||
230 | kfree(rblock); | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | int ehca_modify_port(struct ib_device *ibdev, | ||
236 | u8 port, int port_modify_mask, | ||
237 | struct ib_port_modify *props) | ||
238 | { | ||
239 | /* Not implemented yet */ | ||
240 | return -EFAULT; | ||
241 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c new file mode 100644 index 000000000000..2a65b5be1979 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_irq.c | |||
@@ -0,0 +1,762 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Functions for EQs, NEQs and interrupts | ||
5 | * | ||
6 | * Authors: Heiko J Schick <schickhj@de.ibm.com> | ||
7 | * Khadija Souissi <souissi@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #include "ehca_classes.h" | ||
43 | #include "ehca_irq.h" | ||
44 | #include "ehca_iverbs.h" | ||
45 | #include "ehca_tools.h" | ||
46 | #include "hcp_if.h" | ||
47 | #include "hipz_fns.h" | ||
48 | |||
49 | #define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1) | ||
50 | #define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31) | ||
51 | #define EQE_EE_IDENTIFIER EHCA_BMASK_IBM(2,7) | ||
52 | #define EQE_CQ_NUMBER EHCA_BMASK_IBM(8,31) | ||
53 | #define EQE_QP_NUMBER EHCA_BMASK_IBM(8,31) | ||
54 | #define EQE_QP_TOKEN EHCA_BMASK_IBM(32,63) | ||
55 | #define EQE_CQ_TOKEN EHCA_BMASK_IBM(32,63) | ||
56 | |||
57 | #define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1) | ||
58 | #define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7) | ||
59 | #define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15) | ||
60 | #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16) | ||
61 | |||
62 | #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) | ||
63 | #define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) | ||
64 | |||
65 | #ifdef CONFIG_INFINIBAND_EHCA_SCALING | ||
66 | |||
67 | static void queue_comp_task(struct ehca_cq *__cq); | ||
68 | |||
69 | static struct ehca_comp_pool* pool; | ||
70 | static struct notifier_block comp_pool_callback_nb; | ||
71 | |||
72 | #endif | ||
73 | |||
74 | static inline void comp_event_callback(struct ehca_cq *cq) | ||
75 | { | ||
76 | if (!cq->ib_cq.comp_handler) | ||
77 | return; | ||
78 | |||
79 | spin_lock(&cq->cb_lock); | ||
80 | cq->ib_cq.comp_handler(&cq->ib_cq, cq->ib_cq.cq_context); | ||
81 | spin_unlock(&cq->cb_lock); | ||
82 | |||
83 | return; | ||
84 | } | ||
85 | |||
86 | static void print_error_data(struct ehca_shca * shca, void* data, | ||
87 | u64* rblock, int length) | ||
88 | { | ||
89 | u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]); | ||
90 | u64 resource = rblock[1]; | ||
91 | |||
92 | switch (type) { | ||
93 | case 0x1: /* Queue Pair */ | ||
94 | { | ||
95 | struct ehca_qp *qp = (struct ehca_qp*)data; | ||
96 | |||
97 | /* only print error data if AER is set */ | ||
98 | if (rblock[6] == 0) | ||
99 | return; | ||
100 | |||
101 | ehca_err(&shca->ib_device, | ||
102 | "QP 0x%x (resource=%lx) has errors.", | ||
103 | qp->ib_qp.qp_num, resource); | ||
104 | break; | ||
105 | } | ||
106 | case 0x4: /* Completion Queue */ | ||
107 | { | ||
108 | struct ehca_cq *cq = (struct ehca_cq*)data; | ||
109 | |||
110 | ehca_err(&shca->ib_device, | ||
111 | "CQ 0x%x (resource=%lx) has errors.", | ||
112 | cq->cq_number, resource); | ||
113 | break; | ||
114 | } | ||
115 | default: | ||
116 | ehca_err(&shca->ib_device, | ||
117 | "Unknown errror type: %lx on %s.", | ||
118 | type, shca->ib_device.name); | ||
119 | break; | ||
120 | } | ||
121 | |||
122 | ehca_err(&shca->ib_device, "Error data is available: %lx.", resource); | ||
123 | ehca_err(&shca->ib_device, "EHCA ----- error data begin " | ||
124 | "---------------------------------------------------"); | ||
125 | ehca_dmp(rblock, length, "resource=%lx", resource); | ||
126 | ehca_err(&shca->ib_device, "EHCA ----- error data end " | ||
127 | "----------------------------------------------------"); | ||
128 | |||
129 | return; | ||
130 | } | ||
131 | |||
132 | int ehca_error_data(struct ehca_shca *shca, void *data, | ||
133 | u64 resource) | ||
134 | { | ||
135 | |||
136 | unsigned long ret; | ||
137 | u64 *rblock; | ||
138 | unsigned long block_count; | ||
139 | |||
140 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
141 | if (!rblock) { | ||
142 | ehca_err(&shca->ib_device, "Cannot allocate rblock memory."); | ||
143 | ret = -ENOMEM; | ||
144 | goto error_data1; | ||
145 | } | ||
146 | |||
147 | ret = hipz_h_error_data(shca->ipz_hca_handle, | ||
148 | resource, | ||
149 | rblock, | ||
150 | &block_count); | ||
151 | |||
152 | if (ret == H_R_STATE) { | ||
153 | ehca_err(&shca->ib_device, | ||
154 | "No error data is available: %lx.", resource); | ||
155 | } | ||
156 | else if (ret == H_SUCCESS) { | ||
157 | int length; | ||
158 | |||
159 | length = EHCA_BMASK_GET(ERROR_DATA_LENGTH, rblock[0]); | ||
160 | |||
161 | if (length > PAGE_SIZE) | ||
162 | length = PAGE_SIZE; | ||
163 | |||
164 | print_error_data(shca, data, rblock, length); | ||
165 | } | ||
166 | else { | ||
167 | ehca_err(&shca->ib_device, | ||
168 | "Error data could not be fetched: %lx", resource); | ||
169 | } | ||
170 | |||
171 | kfree(rblock); | ||
172 | |||
173 | error_data1: | ||
174 | return ret; | ||
175 | |||
176 | } | ||
177 | |||
178 | static void qp_event_callback(struct ehca_shca *shca, | ||
179 | u64 eqe, | ||
180 | enum ib_event_type event_type) | ||
181 | { | ||
182 | struct ib_event event; | ||
183 | struct ehca_qp *qp; | ||
184 | unsigned long flags; | ||
185 | u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe); | ||
186 | |||
187 | spin_lock_irqsave(&ehca_qp_idr_lock, flags); | ||
188 | qp = idr_find(&ehca_qp_idr, token); | ||
189 | spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); | ||
190 | |||
191 | |||
192 | if (!qp) | ||
193 | return; | ||
194 | |||
195 | ehca_error_data(shca, qp, qp->ipz_qp_handle.handle); | ||
196 | |||
197 | if (!qp->ib_qp.event_handler) | ||
198 | return; | ||
199 | |||
200 | event.device = &shca->ib_device; | ||
201 | event.event = event_type; | ||
202 | event.element.qp = &qp->ib_qp; | ||
203 | |||
204 | qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context); | ||
205 | |||
206 | return; | ||
207 | } | ||
208 | |||
209 | static void cq_event_callback(struct ehca_shca *shca, | ||
210 | u64 eqe) | ||
211 | { | ||
212 | struct ehca_cq *cq; | ||
213 | unsigned long flags; | ||
214 | u32 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe); | ||
215 | |||
216 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | ||
217 | cq = idr_find(&ehca_cq_idr, token); | ||
218 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | ||
219 | |||
220 | if (!cq) | ||
221 | return; | ||
222 | |||
223 | ehca_error_data(shca, cq, cq->ipz_cq_handle.handle); | ||
224 | |||
225 | return; | ||
226 | } | ||
227 | |||
228 | static void parse_identifier(struct ehca_shca *shca, u64 eqe) | ||
229 | { | ||
230 | u8 identifier = EHCA_BMASK_GET(EQE_EE_IDENTIFIER, eqe); | ||
231 | |||
232 | switch (identifier) { | ||
233 | case 0x02: /* path migrated */ | ||
234 | qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG); | ||
235 | break; | ||
236 | case 0x03: /* communication established */ | ||
237 | qp_event_callback(shca, eqe, IB_EVENT_COMM_EST); | ||
238 | break; | ||
239 | case 0x04: /* send queue drained */ | ||
240 | qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED); | ||
241 | break; | ||
242 | case 0x05: /* QP error */ | ||
243 | case 0x06: /* QP error */ | ||
244 | qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL); | ||
245 | break; | ||
246 | case 0x07: /* CQ error */ | ||
247 | case 0x08: /* CQ error */ | ||
248 | cq_event_callback(shca, eqe); | ||
249 | break; | ||
250 | case 0x09: /* MRMWPTE error */ | ||
251 | ehca_err(&shca->ib_device, "MRMWPTE error."); | ||
252 | break; | ||
253 | case 0x0A: /* port event */ | ||
254 | ehca_err(&shca->ib_device, "Port event."); | ||
255 | break; | ||
256 | case 0x0B: /* MR access error */ | ||
257 | ehca_err(&shca->ib_device, "MR access error."); | ||
258 | break; | ||
259 | case 0x0C: /* EQ error */ | ||
260 | ehca_err(&shca->ib_device, "EQ error."); | ||
261 | break; | ||
262 | case 0x0D: /* P/Q_Key mismatch */ | ||
263 | ehca_err(&shca->ib_device, "P/Q_Key mismatch."); | ||
264 | break; | ||
265 | case 0x10: /* sampling complete */ | ||
266 | ehca_err(&shca->ib_device, "Sampling complete."); | ||
267 | break; | ||
268 | case 0x11: /* unaffiliated access error */ | ||
269 | ehca_err(&shca->ib_device, "Unaffiliated access error."); | ||
270 | break; | ||
271 | case 0x12: /* path migrating error */ | ||
272 | ehca_err(&shca->ib_device, "Path migration error."); | ||
273 | break; | ||
274 | case 0x13: /* interface trace stopped */ | ||
275 | ehca_err(&shca->ib_device, "Interface trace stopped."); | ||
276 | break; | ||
277 | case 0x14: /* first error capture info available */ | ||
278 | default: | ||
279 | ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.", | ||
280 | identifier, shca->ib_device.name); | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | return; | ||
285 | } | ||
286 | |||
287 | static void parse_ec(struct ehca_shca *shca, u64 eqe) | ||
288 | { | ||
289 | struct ib_event event; | ||
290 | u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); | ||
291 | u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); | ||
292 | |||
293 | switch (ec) { | ||
294 | case 0x30: /* port availability change */ | ||
295 | if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { | ||
296 | ehca_info(&shca->ib_device, | ||
297 | "port %x is active.", port); | ||
298 | event.device = &shca->ib_device; | ||
299 | event.event = IB_EVENT_PORT_ACTIVE; | ||
300 | event.element.port_num = port; | ||
301 | shca->sport[port - 1].port_state = IB_PORT_ACTIVE; | ||
302 | ib_dispatch_event(&event); | ||
303 | } else { | ||
304 | ehca_info(&shca->ib_device, | ||
305 | "port %x is inactive.", port); | ||
306 | event.device = &shca->ib_device; | ||
307 | event.event = IB_EVENT_PORT_ERR; | ||
308 | event.element.port_num = port; | ||
309 | shca->sport[port - 1].port_state = IB_PORT_DOWN; | ||
310 | ib_dispatch_event(&event); | ||
311 | } | ||
312 | break; | ||
313 | case 0x31: | ||
314 | /* port configuration change | ||
315 | * disruptive change is caused by | ||
316 | * LID, PKEY or SM change | ||
317 | */ | ||
318 | ehca_warn(&shca->ib_device, | ||
319 | "disruptive port %x configuration change", port); | ||
320 | |||
321 | ehca_info(&shca->ib_device, | ||
322 | "port %x is inactive.", port); | ||
323 | event.device = &shca->ib_device; | ||
324 | event.event = IB_EVENT_PORT_ERR; | ||
325 | event.element.port_num = port; | ||
326 | shca->sport[port - 1].port_state = IB_PORT_DOWN; | ||
327 | ib_dispatch_event(&event); | ||
328 | |||
329 | ehca_info(&shca->ib_device, | ||
330 | "port %x is active.", port); | ||
331 | event.device = &shca->ib_device; | ||
332 | event.event = IB_EVENT_PORT_ACTIVE; | ||
333 | event.element.port_num = port; | ||
334 | shca->sport[port - 1].port_state = IB_PORT_ACTIVE; | ||
335 | ib_dispatch_event(&event); | ||
336 | break; | ||
337 | case 0x32: /* adapter malfunction */ | ||
338 | ehca_err(&shca->ib_device, "Adapter malfunction."); | ||
339 | break; | ||
340 | case 0x33: /* trace stopped */ | ||
341 | ehca_err(&shca->ib_device, "Traced stopped."); | ||
342 | break; | ||
343 | default: | ||
344 | ehca_err(&shca->ib_device, "Unknown event code: %x on %s.", | ||
345 | ec, shca->ib_device.name); | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | return; | ||
350 | } | ||
351 | |||
352 | static inline void reset_eq_pending(struct ehca_cq *cq) | ||
353 | { | ||
354 | u64 CQx_EP; | ||
355 | struct h_galpa gal = cq->galpas.kernel; | ||
356 | |||
357 | hipz_galpa_store_cq(gal, cqx_ep, 0x0); | ||
358 | CQx_EP = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_ep)); | ||
359 | |||
360 | return; | ||
361 | } | ||
362 | |||
363 | irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs) | ||
364 | { | ||
365 | struct ehca_shca *shca = (struct ehca_shca*)dev_id; | ||
366 | |||
367 | tasklet_hi_schedule(&shca->neq.interrupt_task); | ||
368 | |||
369 | return IRQ_HANDLED; | ||
370 | } | ||
371 | |||
372 | void ehca_tasklet_neq(unsigned long data) | ||
373 | { | ||
374 | struct ehca_shca *shca = (struct ehca_shca*)data; | ||
375 | struct ehca_eqe *eqe; | ||
376 | u64 ret; | ||
377 | |||
378 | eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq); | ||
379 | |||
380 | while (eqe) { | ||
381 | if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry)) | ||
382 | parse_ec(shca, eqe->entry); | ||
383 | |||
384 | eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq); | ||
385 | } | ||
386 | |||
387 | ret = hipz_h_reset_event(shca->ipz_hca_handle, | ||
388 | shca->neq.ipz_eq_handle, 0xFFFFFFFFFFFFFFFFL); | ||
389 | |||
390 | if (ret != H_SUCCESS) | ||
391 | ehca_err(&shca->ib_device, "Can't clear notification events."); | ||
392 | |||
393 | return; | ||
394 | } | ||
395 | |||
396 | irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs) | ||
397 | { | ||
398 | struct ehca_shca *shca = (struct ehca_shca*)dev_id; | ||
399 | |||
400 | tasklet_hi_schedule(&shca->eq.interrupt_task); | ||
401 | |||
402 | return IRQ_HANDLED; | ||
403 | } | ||
404 | |||
405 | void ehca_tasklet_eq(unsigned long data) | ||
406 | { | ||
407 | struct ehca_shca *shca = (struct ehca_shca*)data; | ||
408 | struct ehca_eqe *eqe; | ||
409 | int int_state; | ||
410 | int query_cnt = 0; | ||
411 | |||
412 | do { | ||
413 | eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); | ||
414 | |||
415 | if ((shca->hw_level >= 2) && eqe) | ||
416 | int_state = 1; | ||
417 | else | ||
418 | int_state = 0; | ||
419 | |||
420 | while ((int_state == 1) || eqe) { | ||
421 | while (eqe) { | ||
422 | u64 eqe_value = eqe->entry; | ||
423 | |||
424 | ehca_dbg(&shca->ib_device, | ||
425 | "eqe_value=%lx", eqe_value); | ||
426 | |||
427 | /* TODO: better structure */ | ||
428 | if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, | ||
429 | eqe_value)) { | ||
430 | unsigned long flags; | ||
431 | u32 token; | ||
432 | struct ehca_cq *cq; | ||
433 | |||
434 | ehca_dbg(&shca->ib_device, | ||
435 | "... completion event"); | ||
436 | token = | ||
437 | EHCA_BMASK_GET(EQE_CQ_TOKEN, | ||
438 | eqe_value); | ||
439 | spin_lock_irqsave(&ehca_cq_idr_lock, | ||
440 | flags); | ||
441 | cq = idr_find(&ehca_cq_idr, token); | ||
442 | |||
443 | if (cq == NULL) { | ||
444 | spin_unlock(&ehca_cq_idr_lock); | ||
445 | break; | ||
446 | } | ||
447 | |||
448 | reset_eq_pending(cq); | ||
449 | #ifdef CONFIG_INFINIBAND_EHCA_SCALING | ||
450 | queue_comp_task(cq); | ||
451 | spin_unlock_irqrestore(&ehca_cq_idr_lock, | ||
452 | flags); | ||
453 | #else | ||
454 | spin_unlock_irqrestore(&ehca_cq_idr_lock, | ||
455 | flags); | ||
456 | comp_event_callback(cq); | ||
457 | #endif | ||
458 | } else { | ||
459 | ehca_dbg(&shca->ib_device, | ||
460 | "... non completion event"); | ||
461 | parse_identifier(shca, eqe_value); | ||
462 | } | ||
463 | eqe = | ||
464 | (struct ehca_eqe *)ehca_poll_eq(shca, | ||
465 | &shca->eq); | ||
466 | } | ||
467 | |||
468 | if (shca->hw_level >= 2) { | ||
469 | int_state = | ||
470 | hipz_h_query_int_state(shca->ipz_hca_handle, | ||
471 | shca->eq.ist); | ||
472 | query_cnt++; | ||
473 | iosync(); | ||
474 | if (query_cnt >= 100) { | ||
475 | query_cnt = 0; | ||
476 | int_state = 0; | ||
477 | } | ||
478 | } | ||
479 | eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); | ||
480 | |||
481 | } | ||
482 | } while (int_state != 0); | ||
483 | |||
484 | return; | ||
485 | } | ||
486 | |||
487 | #ifdef CONFIG_INFINIBAND_EHCA_SCALING | ||
488 | |||
489 | static inline int find_next_online_cpu(struct ehca_comp_pool* pool) | ||
490 | { | ||
491 | unsigned long flags_last_cpu; | ||
492 | |||
493 | if (ehca_debug_level) | ||
494 | ehca_dmp(&cpu_online_map, sizeof(cpumask_t), ""); | ||
495 | |||
496 | spin_lock_irqsave(&pool->last_cpu_lock, flags_last_cpu); | ||
497 | pool->last_cpu = next_cpu(pool->last_cpu, cpu_online_map); | ||
498 | if (pool->last_cpu == NR_CPUS) | ||
499 | pool->last_cpu = first_cpu(cpu_online_map); | ||
500 | spin_unlock_irqrestore(&pool->last_cpu_lock, flags_last_cpu); | ||
501 | |||
502 | return pool->last_cpu; | ||
503 | } | ||
504 | |||
505 | static void __queue_comp_task(struct ehca_cq *__cq, | ||
506 | struct ehca_cpu_comp_task *cct) | ||
507 | { | ||
508 | unsigned long flags_cct; | ||
509 | unsigned long flags_cq; | ||
510 | |||
511 | spin_lock_irqsave(&cct->task_lock, flags_cct); | ||
512 | spin_lock_irqsave(&__cq->task_lock, flags_cq); | ||
513 | |||
514 | if (__cq->nr_callbacks == 0) { | ||
515 | __cq->nr_callbacks++; | ||
516 | list_add_tail(&__cq->entry, &cct->cq_list); | ||
517 | cct->cq_jobs++; | ||
518 | wake_up(&cct->wait_queue); | ||
519 | } | ||
520 | else | ||
521 | __cq->nr_callbacks++; | ||
522 | |||
523 | spin_unlock_irqrestore(&__cq->task_lock, flags_cq); | ||
524 | spin_unlock_irqrestore(&cct->task_lock, flags_cct); | ||
525 | } | ||
526 | |||
527 | static void queue_comp_task(struct ehca_cq *__cq) | ||
528 | { | ||
529 | int cpu; | ||
530 | int cpu_id; | ||
531 | struct ehca_cpu_comp_task *cct; | ||
532 | |||
533 | cpu = get_cpu(); | ||
534 | cpu_id = find_next_online_cpu(pool); | ||
535 | |||
536 | BUG_ON(!cpu_online(cpu_id)); | ||
537 | |||
538 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); | ||
539 | |||
540 | if (cct->cq_jobs > 0) { | ||
541 | cpu_id = find_next_online_cpu(pool); | ||
542 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); | ||
543 | } | ||
544 | |||
545 | __queue_comp_task(__cq, cct); | ||
546 | |||
547 | put_cpu(); | ||
548 | |||
549 | return; | ||
550 | } | ||
551 | |||
552 | static void run_comp_task(struct ehca_cpu_comp_task* cct) | ||
553 | { | ||
554 | struct ehca_cq *cq; | ||
555 | unsigned long flags_cct; | ||
556 | unsigned long flags_cq; | ||
557 | |||
558 | spin_lock_irqsave(&cct->task_lock, flags_cct); | ||
559 | |||
560 | while (!list_empty(&cct->cq_list)) { | ||
561 | cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); | ||
562 | spin_unlock_irqrestore(&cct->task_lock, flags_cct); | ||
563 | comp_event_callback(cq); | ||
564 | spin_lock_irqsave(&cct->task_lock, flags_cct); | ||
565 | |||
566 | spin_lock_irqsave(&cq->task_lock, flags_cq); | ||
567 | cq->nr_callbacks--; | ||
568 | if (cq->nr_callbacks == 0) { | ||
569 | list_del_init(cct->cq_list.next); | ||
570 | cct->cq_jobs--; | ||
571 | } | ||
572 | spin_unlock_irqrestore(&cq->task_lock, flags_cq); | ||
573 | |||
574 | } | ||
575 | |||
576 | spin_unlock_irqrestore(&cct->task_lock, flags_cct); | ||
577 | |||
578 | return; | ||
579 | } | ||
580 | |||
581 | static int comp_task(void *__cct) | ||
582 | { | ||
583 | struct ehca_cpu_comp_task* cct = __cct; | ||
584 | DECLARE_WAITQUEUE(wait, current); | ||
585 | |||
586 | set_current_state(TASK_INTERRUPTIBLE); | ||
587 | while(!kthread_should_stop()) { | ||
588 | add_wait_queue(&cct->wait_queue, &wait); | ||
589 | |||
590 | if (list_empty(&cct->cq_list)) | ||
591 | schedule(); | ||
592 | else | ||
593 | __set_current_state(TASK_RUNNING); | ||
594 | |||
595 | remove_wait_queue(&cct->wait_queue, &wait); | ||
596 | |||
597 | if (!list_empty(&cct->cq_list)) | ||
598 | run_comp_task(__cct); | ||
599 | |||
600 | set_current_state(TASK_INTERRUPTIBLE); | ||
601 | } | ||
602 | __set_current_state(TASK_RUNNING); | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static struct task_struct *create_comp_task(struct ehca_comp_pool *pool, | ||
608 | int cpu) | ||
609 | { | ||
610 | struct ehca_cpu_comp_task *cct; | ||
611 | |||
612 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
613 | spin_lock_init(&cct->task_lock); | ||
614 | INIT_LIST_HEAD(&cct->cq_list); | ||
615 | init_waitqueue_head(&cct->wait_queue); | ||
616 | cct->task = kthread_create(comp_task, cct, "ehca_comp/%d", cpu); | ||
617 | |||
618 | return cct->task; | ||
619 | } | ||
620 | |||
621 | static void destroy_comp_task(struct ehca_comp_pool *pool, | ||
622 | int cpu) | ||
623 | { | ||
624 | struct ehca_cpu_comp_task *cct; | ||
625 | struct task_struct *task; | ||
626 | unsigned long flags_cct; | ||
627 | |||
628 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
629 | |||
630 | spin_lock_irqsave(&cct->task_lock, flags_cct); | ||
631 | |||
632 | task = cct->task; | ||
633 | cct->task = NULL; | ||
634 | cct->cq_jobs = 0; | ||
635 | |||
636 | spin_unlock_irqrestore(&cct->task_lock, flags_cct); | ||
637 | |||
638 | if (task) | ||
639 | kthread_stop(task); | ||
640 | |||
641 | return; | ||
642 | } | ||
643 | |||
644 | static void take_over_work(struct ehca_comp_pool *pool, | ||
645 | int cpu) | ||
646 | { | ||
647 | struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
648 | LIST_HEAD(list); | ||
649 | struct ehca_cq *cq; | ||
650 | unsigned long flags_cct; | ||
651 | |||
652 | spin_lock_irqsave(&cct->task_lock, flags_cct); | ||
653 | |||
654 | list_splice_init(&cct->cq_list, &list); | ||
655 | |||
656 | while(!list_empty(&list)) { | ||
657 | cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); | ||
658 | |||
659 | list_del(&cq->entry); | ||
660 | __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks, | ||
661 | smp_processor_id())); | ||
662 | } | ||
663 | |||
664 | spin_unlock_irqrestore(&cct->task_lock, flags_cct); | ||
665 | |||
666 | } | ||
667 | |||
668 | static int comp_pool_callback(struct notifier_block *nfb, | ||
669 | unsigned long action, | ||
670 | void *hcpu) | ||
671 | { | ||
672 | unsigned int cpu = (unsigned long)hcpu; | ||
673 | struct ehca_cpu_comp_task *cct; | ||
674 | |||
675 | switch (action) { | ||
676 | case CPU_UP_PREPARE: | ||
677 | ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu); | ||
678 | if(!create_comp_task(pool, cpu)) { | ||
679 | ehca_gen_err("Can't create comp_task for cpu: %x", cpu); | ||
680 | return NOTIFY_BAD; | ||
681 | } | ||
682 | break; | ||
683 | case CPU_UP_CANCELED: | ||
684 | ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu); | ||
685 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
686 | kthread_bind(cct->task, any_online_cpu(cpu_online_map)); | ||
687 | destroy_comp_task(pool, cpu); | ||
688 | break; | ||
689 | case CPU_ONLINE: | ||
690 | ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu); | ||
691 | cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); | ||
692 | kthread_bind(cct->task, cpu); | ||
693 | wake_up_process(cct->task); | ||
694 | break; | ||
695 | case CPU_DOWN_PREPARE: | ||
696 | ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu); | ||
697 | break; | ||
698 | case CPU_DOWN_FAILED: | ||
699 | ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu); | ||
700 | break; | ||
701 | case CPU_DEAD: | ||
702 | ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu); | ||
703 | destroy_comp_task(pool, cpu); | ||
704 | take_over_work(pool, cpu); | ||
705 | break; | ||
706 | } | ||
707 | |||
708 | return NOTIFY_OK; | ||
709 | } | ||
710 | |||
711 | #endif | ||
712 | |||
713 | int ehca_create_comp_pool(void) | ||
714 | { | ||
715 | #ifdef CONFIG_INFINIBAND_EHCA_SCALING | ||
716 | int cpu; | ||
717 | struct task_struct *task; | ||
718 | |||
719 | pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL); | ||
720 | if (pool == NULL) | ||
721 | return -ENOMEM; | ||
722 | |||
723 | spin_lock_init(&pool->last_cpu_lock); | ||
724 | pool->last_cpu = any_online_cpu(cpu_online_map); | ||
725 | |||
726 | pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task); | ||
727 | if (pool->cpu_comp_tasks == NULL) { | ||
728 | kfree(pool); | ||
729 | return -EINVAL; | ||
730 | } | ||
731 | |||
732 | for_each_online_cpu(cpu) { | ||
733 | task = create_comp_task(pool, cpu); | ||
734 | if (task) { | ||
735 | kthread_bind(task, cpu); | ||
736 | wake_up_process(task); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | comp_pool_callback_nb.notifier_call = comp_pool_callback; | ||
741 | comp_pool_callback_nb.priority =0; | ||
742 | register_cpu_notifier(&comp_pool_callback_nb); | ||
743 | #endif | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | void ehca_destroy_comp_pool(void) | ||
749 | { | ||
750 | #ifdef CONFIG_INFINIBAND_EHCA_SCALING | ||
751 | int i; | ||
752 | |||
753 | unregister_cpu_notifier(&comp_pool_callback_nb); | ||
754 | |||
755 | for (i = 0; i < NR_CPUS; i++) { | ||
756 | if (cpu_online(i)) | ||
757 | destroy_comp_task(pool, i); | ||
758 | } | ||
759 | #endif | ||
760 | |||
761 | return; | ||
762 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h new file mode 100644 index 000000000000..85bf1fe16fe4 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_irq.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Function definitions and structs for EQs, NEQs and interrupts | ||
5 | * | ||
6 | * Authors: Heiko J Schick <schickhj@de.ibm.com> | ||
7 | * Khadija Souissi <souissi@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #ifndef __EHCA_IRQ_H | ||
43 | #define __EHCA_IRQ_H | ||
44 | |||
45 | |||
46 | struct ehca_shca; | ||
47 | |||
48 | #include <linux/interrupt.h> | ||
49 | #include <linux/types.h> | ||
50 | #include <asm/atomic.h> | ||
51 | |||
52 | int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource); | ||
53 | |||
54 | irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs); | ||
55 | void ehca_tasklet_neq(unsigned long data); | ||
56 | |||
57 | irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs); | ||
58 | void ehca_tasklet_eq(unsigned long data); | ||
59 | |||
60 | struct ehca_cpu_comp_task { | ||
61 | wait_queue_head_t wait_queue; | ||
62 | struct list_head cq_list; | ||
63 | struct task_struct *task; | ||
64 | spinlock_t task_lock; | ||
65 | int cq_jobs; | ||
66 | }; | ||
67 | |||
68 | struct ehca_comp_pool { | ||
69 | struct ehca_cpu_comp_task *cpu_comp_tasks; | ||
70 | int last_cpu; | ||
71 | spinlock_t last_cpu_lock; | ||
72 | }; | ||
73 | |||
74 | int ehca_create_comp_pool(void); | ||
75 | void ehca_destroy_comp_pool(void); | ||
76 | |||
77 | #endif | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h new file mode 100644 index 000000000000..319c39d47f3a --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Function definitions for internal functions | ||
5 | * | ||
6 | * Authors: Heiko J Schick <schickhj@de.ibm.com> | ||
7 | * Dietmar Decker <ddecker@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #ifndef __EHCA_IVERBS_H__ | ||
43 | #define __EHCA_IVERBS_H__ | ||
44 | |||
45 | #include "ehca_classes.h" | ||
46 | |||
47 | int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props); | ||
48 | |||
49 | int ehca_query_port(struct ib_device *ibdev, u8 port, | ||
50 | struct ib_port_attr *props); | ||
51 | |||
52 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey); | ||
53 | |||
54 | int ehca_query_gid(struct ib_device *ibdev, u8 port, int index, | ||
55 | union ib_gid *gid); | ||
56 | |||
57 | int ehca_modify_port(struct ib_device *ibdev, u8 port, int port_modify_mask, | ||
58 | struct ib_port_modify *props); | ||
59 | |||
60 | struct ib_pd *ehca_alloc_pd(struct ib_device *device, | ||
61 | struct ib_ucontext *context, | ||
62 | struct ib_udata *udata); | ||
63 | |||
64 | int ehca_dealloc_pd(struct ib_pd *pd); | ||
65 | |||
66 | struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); | ||
67 | |||
68 | int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); | ||
69 | |||
70 | int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); | ||
71 | |||
72 | int ehca_destroy_ah(struct ib_ah *ah); | ||
73 | |||
74 | struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags); | ||
75 | |||
76 | struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, | ||
77 | struct ib_phys_buf *phys_buf_array, | ||
78 | int num_phys_buf, | ||
79 | int mr_access_flags, u64 *iova_start); | ||
80 | |||
81 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, | ||
82 | struct ib_umem *region, | ||
83 | int mr_access_flags, struct ib_udata *udata); | ||
84 | |||
85 | int ehca_rereg_phys_mr(struct ib_mr *mr, | ||
86 | int mr_rereg_mask, | ||
87 | struct ib_pd *pd, | ||
88 | struct ib_phys_buf *phys_buf_array, | ||
89 | int num_phys_buf, int mr_access_flags, u64 *iova_start); | ||
90 | |||
91 | int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr); | ||
92 | |||
93 | int ehca_dereg_mr(struct ib_mr *mr); | ||
94 | |||
95 | struct ib_mw *ehca_alloc_mw(struct ib_pd *pd); | ||
96 | |||
97 | int ehca_bind_mw(struct ib_qp *qp, struct ib_mw *mw, | ||
98 | struct ib_mw_bind *mw_bind); | ||
99 | |||
100 | int ehca_dealloc_mw(struct ib_mw *mw); | ||
101 | |||
102 | struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd, | ||
103 | int mr_access_flags, | ||
104 | struct ib_fmr_attr *fmr_attr); | ||
105 | |||
106 | int ehca_map_phys_fmr(struct ib_fmr *fmr, | ||
107 | u64 *page_list, int list_len, u64 iova); | ||
108 | |||
109 | int ehca_unmap_fmr(struct list_head *fmr_list); | ||
110 | |||
111 | int ehca_dealloc_fmr(struct ib_fmr *fmr); | ||
112 | |||
113 | enum ehca_eq_type { | ||
114 | EHCA_EQ = 0, /* Event Queue */ | ||
115 | EHCA_NEQ /* Notification Event Queue */ | ||
116 | }; | ||
117 | |||
118 | int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq, | ||
119 | enum ehca_eq_type type, const u32 length); | ||
120 | |||
121 | int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq); | ||
122 | |||
123 | void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq); | ||
124 | |||
125 | |||
126 | struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, | ||
127 | struct ib_ucontext *context, | ||
128 | struct ib_udata *udata); | ||
129 | |||
130 | int ehca_destroy_cq(struct ib_cq *cq); | ||
131 | |||
132 | int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata); | ||
133 | |||
134 | int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc); | ||
135 | |||
136 | int ehca_peek_cq(struct ib_cq *cq, int wc_cnt); | ||
137 | |||
138 | int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify); | ||
139 | |||
140 | struct ib_qp *ehca_create_qp(struct ib_pd *pd, | ||
141 | struct ib_qp_init_attr *init_attr, | ||
142 | struct ib_udata *udata); | ||
143 | |||
144 | int ehca_destroy_qp(struct ib_qp *qp); | ||
145 | |||
146 | int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, | ||
147 | struct ib_udata *udata); | ||
148 | |||
149 | int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr, | ||
150 | int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr); | ||
151 | |||
152 | int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr, | ||
153 | struct ib_send_wr **bad_send_wr); | ||
154 | |||
155 | int ehca_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr, | ||
156 | struct ib_recv_wr **bad_recv_wr); | ||
157 | |||
158 | u64 ehca_define_sqp(struct ehca_shca *shca, struct ehca_qp *ibqp, | ||
159 | struct ib_qp_init_attr *qp_init_attr); | ||
160 | |||
161 | int ehca_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); | ||
162 | |||
163 | int ehca_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); | ||
164 | |||
165 | struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device, | ||
166 | struct ib_udata *udata); | ||
167 | |||
168 | int ehca_dealloc_ucontext(struct ib_ucontext *context); | ||
169 | |||
170 | int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); | ||
171 | |||
172 | void ehca_poll_eqs(unsigned long data); | ||
173 | |||
174 | int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped, | ||
175 | struct vm_area_struct **vma); | ||
176 | |||
177 | int ehca_mmap_register(u64 physical,void **mapped, | ||
178 | struct vm_area_struct **vma); | ||
179 | |||
180 | int ehca_munmap(unsigned long addr, size_t len); | ||
181 | |||
182 | #endif | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c new file mode 100644 index 000000000000..2380994418a5 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_main.c | |||
@@ -0,0 +1,818 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * module start stop, hca detection | ||
5 | * | ||
6 | * Authors: Heiko J Schick <schickhj@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Joachim Fenkes <fenkes@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | #include "ehca_classes.h" | ||
44 | #include "ehca_iverbs.h" | ||
45 | #include "ehca_mrmw.h" | ||
46 | #include "ehca_tools.h" | ||
47 | #include "hcp_if.h" | ||
48 | |||
49 | MODULE_LICENSE("Dual BSD/GPL"); | ||
50 | MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); | ||
51 | MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); | ||
52 | MODULE_VERSION("SVNEHCA_0016"); | ||
53 | |||
54 | int ehca_open_aqp1 = 0; | ||
55 | int ehca_debug_level = 0; | ||
56 | int ehca_hw_level = 0; | ||
57 | int ehca_nr_ports = 2; | ||
58 | int ehca_use_hp_mr = 0; | ||
59 | int ehca_port_act_time = 30; | ||
60 | int ehca_poll_all_eqs = 1; | ||
61 | int ehca_static_rate = -1; | ||
62 | |||
63 | module_param_named(open_aqp1, ehca_open_aqp1, int, 0); | ||
64 | module_param_named(debug_level, ehca_debug_level, int, 0); | ||
65 | module_param_named(hw_level, ehca_hw_level, int, 0); | ||
66 | module_param_named(nr_ports, ehca_nr_ports, int, 0); | ||
67 | module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0); | ||
68 | module_param_named(port_act_time, ehca_port_act_time, int, 0); | ||
69 | module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0); | ||
70 | module_param_named(static_rate, ehca_static_rate, int, 0); | ||
71 | |||
72 | MODULE_PARM_DESC(open_aqp1, | ||
73 | "AQP1 on startup (0: no (default), 1: yes)"); | ||
74 | MODULE_PARM_DESC(debug_level, | ||
75 | "debug level" | ||
76 | " (0: no debug traces (default), 1: with debug traces)"); | ||
77 | MODULE_PARM_DESC(hw_level, | ||
78 | "hardware level" | ||
79 | " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)"); | ||
80 | MODULE_PARM_DESC(nr_ports, | ||
81 | "number of connected ports (default: 2)"); | ||
82 | MODULE_PARM_DESC(use_hp_mr, | ||
83 | "high performance MRs (0: no (default), 1: yes)"); | ||
84 | MODULE_PARM_DESC(port_act_time, | ||
85 | "time to wait for port activation (default: 30 sec)"); | ||
86 | MODULE_PARM_DESC(poll_all_eqs, | ||
87 | "polls all event queues periodically" | ||
88 | " (0: no, 1: yes (default))"); | ||
89 | MODULE_PARM_DESC(static_rate, | ||
90 | "set permanent static rate (default: disabled)"); | ||
91 | |||
92 | spinlock_t ehca_qp_idr_lock; | ||
93 | spinlock_t ehca_cq_idr_lock; | ||
94 | DEFINE_IDR(ehca_qp_idr); | ||
95 | DEFINE_IDR(ehca_cq_idr); | ||
96 | |||
97 | static struct list_head shca_list; /* list of all registered ehcas */ | ||
98 | static spinlock_t shca_list_lock; | ||
99 | |||
100 | static struct timer_list poll_eqs_timer; | ||
101 | |||
102 | static int ehca_create_slab_caches(void) | ||
103 | { | ||
104 | int ret; | ||
105 | |||
106 | ret = ehca_init_pd_cache(); | ||
107 | if (ret) { | ||
108 | ehca_gen_err("Cannot create PD SLAB cache."); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | ret = ehca_init_cq_cache(); | ||
113 | if (ret) { | ||
114 | ehca_gen_err("Cannot create CQ SLAB cache."); | ||
115 | goto create_slab_caches2; | ||
116 | } | ||
117 | |||
118 | ret = ehca_init_qp_cache(); | ||
119 | if (ret) { | ||
120 | ehca_gen_err("Cannot create QP SLAB cache."); | ||
121 | goto create_slab_caches3; | ||
122 | } | ||
123 | |||
124 | ret = ehca_init_av_cache(); | ||
125 | if (ret) { | ||
126 | ehca_gen_err("Cannot create AV SLAB cache."); | ||
127 | goto create_slab_caches4; | ||
128 | } | ||
129 | |||
130 | ret = ehca_init_mrmw_cache(); | ||
131 | if (ret) { | ||
132 | ehca_gen_err("Cannot create MR&MW SLAB cache."); | ||
133 | goto create_slab_caches5; | ||
134 | } | ||
135 | |||
136 | return 0; | ||
137 | |||
138 | create_slab_caches5: | ||
139 | ehca_cleanup_av_cache(); | ||
140 | |||
141 | create_slab_caches4: | ||
142 | ehca_cleanup_qp_cache(); | ||
143 | |||
144 | create_slab_caches3: | ||
145 | ehca_cleanup_cq_cache(); | ||
146 | |||
147 | create_slab_caches2: | ||
148 | ehca_cleanup_pd_cache(); | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static void ehca_destroy_slab_caches(void) | ||
154 | { | ||
155 | ehca_cleanup_mrmw_cache(); | ||
156 | ehca_cleanup_av_cache(); | ||
157 | ehca_cleanup_qp_cache(); | ||
158 | ehca_cleanup_cq_cache(); | ||
159 | ehca_cleanup_pd_cache(); | ||
160 | } | ||
161 | |||
162 | #define EHCA_HCAAVER EHCA_BMASK_IBM(32,39) | ||
163 | #define EHCA_REVID EHCA_BMASK_IBM(40,63) | ||
164 | |||
165 | int ehca_sense_attributes(struct ehca_shca *shca) | ||
166 | { | ||
167 | int ret = 0; | ||
168 | u64 h_ret; | ||
169 | struct hipz_query_hca *rblock; | ||
170 | |||
171 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
172 | if (!rblock) { | ||
173 | ehca_gen_err("Cannot allocate rblock memory."); | ||
174 | return -ENOMEM; | ||
175 | } | ||
176 | |||
177 | h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock); | ||
178 | if (h_ret != H_SUCCESS) { | ||
179 | ehca_gen_err("Cannot query device properties. h_ret=%lx", | ||
180 | h_ret); | ||
181 | ret = -EPERM; | ||
182 | goto num_ports1; | ||
183 | } | ||
184 | |||
185 | if (ehca_nr_ports == 1) | ||
186 | shca->num_ports = 1; | ||
187 | else | ||
188 | shca->num_ports = (u8)rblock->num_ports; | ||
189 | |||
190 | ehca_gen_dbg(" ... found %x ports", rblock->num_ports); | ||
191 | |||
192 | if (ehca_hw_level == 0) { | ||
193 | u32 hcaaver; | ||
194 | u32 revid; | ||
195 | |||
196 | hcaaver = EHCA_BMASK_GET(EHCA_HCAAVER, rblock->hw_ver); | ||
197 | revid = EHCA_BMASK_GET(EHCA_REVID, rblock->hw_ver); | ||
198 | |||
199 | ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid); | ||
200 | |||
201 | if ((hcaaver == 1) && (revid == 0)) | ||
202 | shca->hw_level = 0; | ||
203 | else if ((hcaaver == 1) && (revid == 1)) | ||
204 | shca->hw_level = 1; | ||
205 | else if ((hcaaver == 1) && (revid == 2)) | ||
206 | shca->hw_level = 2; | ||
207 | } | ||
208 | ehca_gen_dbg(" ... hardware level=%x", shca->hw_level); | ||
209 | |||
210 | shca->sport[0].rate = IB_RATE_30_GBPS; | ||
211 | shca->sport[1].rate = IB_RATE_30_GBPS; | ||
212 | |||
213 | num_ports1: | ||
214 | kfree(rblock); | ||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | static int init_node_guid(struct ehca_shca *shca) | ||
219 | { | ||
220 | int ret = 0; | ||
221 | struct hipz_query_hca *rblock; | ||
222 | |||
223 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
224 | if (!rblock) { | ||
225 | ehca_err(&shca->ib_device, "Can't allocate rblock memory."); | ||
226 | return -ENOMEM; | ||
227 | } | ||
228 | |||
229 | if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { | ||
230 | ehca_err(&shca->ib_device, "Can't query device properties"); | ||
231 | ret = -EINVAL; | ||
232 | goto init_node_guid1; | ||
233 | } | ||
234 | |||
235 | memcpy(&shca->ib_device.node_guid, &rblock->node_guid, sizeof(u64)); | ||
236 | |||
237 | init_node_guid1: | ||
238 | kfree(rblock); | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | int ehca_register_device(struct ehca_shca *shca) | ||
243 | { | ||
244 | int ret; | ||
245 | |||
246 | ret = init_node_guid(shca); | ||
247 | if (ret) | ||
248 | return ret; | ||
249 | |||
250 | strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX); | ||
251 | shca->ib_device.owner = THIS_MODULE; | ||
252 | |||
253 | shca->ib_device.uverbs_abi_ver = 5; | ||
254 | shca->ib_device.uverbs_cmd_mask = | ||
255 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | | ||
256 | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | | ||
257 | (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | | ||
258 | (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | | ||
259 | (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | | ||
260 | (1ull << IB_USER_VERBS_CMD_REG_MR) | | ||
261 | (1ull << IB_USER_VERBS_CMD_DEREG_MR) | | ||
262 | (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | | ||
263 | (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | | ||
264 | (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | | ||
265 | (1ull << IB_USER_VERBS_CMD_CREATE_QP) | | ||
266 | (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | | ||
267 | (1ull << IB_USER_VERBS_CMD_QUERY_QP) | | ||
268 | (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | | ||
269 | (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | | ||
270 | (1ull << IB_USER_VERBS_CMD_DETACH_MCAST); | ||
271 | |||
272 | shca->ib_device.node_type = RDMA_NODE_IB_CA; | ||
273 | shca->ib_device.phys_port_cnt = shca->num_ports; | ||
274 | shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev; | ||
275 | shca->ib_device.query_device = ehca_query_device; | ||
276 | shca->ib_device.query_port = ehca_query_port; | ||
277 | shca->ib_device.query_gid = ehca_query_gid; | ||
278 | shca->ib_device.query_pkey = ehca_query_pkey; | ||
279 | /* shca->in_device.modify_device = ehca_modify_device */ | ||
280 | shca->ib_device.modify_port = ehca_modify_port; | ||
281 | shca->ib_device.alloc_ucontext = ehca_alloc_ucontext; | ||
282 | shca->ib_device.dealloc_ucontext = ehca_dealloc_ucontext; | ||
283 | shca->ib_device.alloc_pd = ehca_alloc_pd; | ||
284 | shca->ib_device.dealloc_pd = ehca_dealloc_pd; | ||
285 | shca->ib_device.create_ah = ehca_create_ah; | ||
286 | /* shca->ib_device.modify_ah = ehca_modify_ah; */ | ||
287 | shca->ib_device.query_ah = ehca_query_ah; | ||
288 | shca->ib_device.destroy_ah = ehca_destroy_ah; | ||
289 | shca->ib_device.create_qp = ehca_create_qp; | ||
290 | shca->ib_device.modify_qp = ehca_modify_qp; | ||
291 | shca->ib_device.query_qp = ehca_query_qp; | ||
292 | shca->ib_device.destroy_qp = ehca_destroy_qp; | ||
293 | shca->ib_device.post_send = ehca_post_send; | ||
294 | shca->ib_device.post_recv = ehca_post_recv; | ||
295 | shca->ib_device.create_cq = ehca_create_cq; | ||
296 | shca->ib_device.destroy_cq = ehca_destroy_cq; | ||
297 | shca->ib_device.resize_cq = ehca_resize_cq; | ||
298 | shca->ib_device.poll_cq = ehca_poll_cq; | ||
299 | /* shca->ib_device.peek_cq = ehca_peek_cq; */ | ||
300 | shca->ib_device.req_notify_cq = ehca_req_notify_cq; | ||
301 | /* shca->ib_device.req_ncomp_notif = ehca_req_ncomp_notif; */ | ||
302 | shca->ib_device.get_dma_mr = ehca_get_dma_mr; | ||
303 | shca->ib_device.reg_phys_mr = ehca_reg_phys_mr; | ||
304 | shca->ib_device.reg_user_mr = ehca_reg_user_mr; | ||
305 | shca->ib_device.query_mr = ehca_query_mr; | ||
306 | shca->ib_device.dereg_mr = ehca_dereg_mr; | ||
307 | shca->ib_device.rereg_phys_mr = ehca_rereg_phys_mr; | ||
308 | shca->ib_device.alloc_mw = ehca_alloc_mw; | ||
309 | shca->ib_device.bind_mw = ehca_bind_mw; | ||
310 | shca->ib_device.dealloc_mw = ehca_dealloc_mw; | ||
311 | shca->ib_device.alloc_fmr = ehca_alloc_fmr; | ||
312 | shca->ib_device.map_phys_fmr = ehca_map_phys_fmr; | ||
313 | shca->ib_device.unmap_fmr = ehca_unmap_fmr; | ||
314 | shca->ib_device.dealloc_fmr = ehca_dealloc_fmr; | ||
315 | shca->ib_device.attach_mcast = ehca_attach_mcast; | ||
316 | shca->ib_device.detach_mcast = ehca_detach_mcast; | ||
317 | /* shca->ib_device.process_mad = ehca_process_mad; */ | ||
318 | shca->ib_device.mmap = ehca_mmap; | ||
319 | |||
320 | ret = ib_register_device(&shca->ib_device); | ||
321 | if (ret) | ||
322 | ehca_err(&shca->ib_device, | ||
323 | "ib_register_device() failed ret=%x", ret); | ||
324 | |||
325 | return ret; | ||
326 | } | ||
327 | |||
328 | static int ehca_create_aqp1(struct ehca_shca *shca, u32 port) | ||
329 | { | ||
330 | struct ehca_sport *sport = &shca->sport[port - 1]; | ||
331 | struct ib_cq *ibcq; | ||
332 | struct ib_qp *ibqp; | ||
333 | struct ib_qp_init_attr qp_init_attr; | ||
334 | int ret; | ||
335 | |||
336 | if (sport->ibcq_aqp1) { | ||
337 | ehca_err(&shca->ib_device, "AQP1 CQ is already created."); | ||
338 | return -EPERM; | ||
339 | } | ||
340 | |||
341 | ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10); | ||
342 | if (IS_ERR(ibcq)) { | ||
343 | ehca_err(&shca->ib_device, "Cannot create AQP1 CQ."); | ||
344 | return PTR_ERR(ibcq); | ||
345 | } | ||
346 | sport->ibcq_aqp1 = ibcq; | ||
347 | |||
348 | if (sport->ibqp_aqp1) { | ||
349 | ehca_err(&shca->ib_device, "AQP1 QP is already created."); | ||
350 | ret = -EPERM; | ||
351 | goto create_aqp1; | ||
352 | } | ||
353 | |||
354 | memset(&qp_init_attr, 0, sizeof(struct ib_qp_init_attr)); | ||
355 | qp_init_attr.send_cq = ibcq; | ||
356 | qp_init_attr.recv_cq = ibcq; | ||
357 | qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; | ||
358 | qp_init_attr.cap.max_send_wr = 100; | ||
359 | qp_init_attr.cap.max_recv_wr = 100; | ||
360 | qp_init_attr.cap.max_send_sge = 2; | ||
361 | qp_init_attr.cap.max_recv_sge = 1; | ||
362 | qp_init_attr.qp_type = IB_QPT_GSI; | ||
363 | qp_init_attr.port_num = port; | ||
364 | qp_init_attr.qp_context = NULL; | ||
365 | qp_init_attr.event_handler = NULL; | ||
366 | qp_init_attr.srq = NULL; | ||
367 | |||
368 | ibqp = ib_create_qp(&shca->pd->ib_pd, &qp_init_attr); | ||
369 | if (IS_ERR(ibqp)) { | ||
370 | ehca_err(&shca->ib_device, "Cannot create AQP1 QP."); | ||
371 | ret = PTR_ERR(ibqp); | ||
372 | goto create_aqp1; | ||
373 | } | ||
374 | sport->ibqp_aqp1 = ibqp; | ||
375 | |||
376 | return 0; | ||
377 | |||
378 | create_aqp1: | ||
379 | ib_destroy_cq(sport->ibcq_aqp1); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | static int ehca_destroy_aqp1(struct ehca_sport *sport) | ||
384 | { | ||
385 | int ret; | ||
386 | |||
387 | ret = ib_destroy_qp(sport->ibqp_aqp1); | ||
388 | if (ret) { | ||
389 | ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret); | ||
390 | return ret; | ||
391 | } | ||
392 | |||
393 | ret = ib_destroy_cq(sport->ibcq_aqp1); | ||
394 | if (ret) | ||
395 | ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret); | ||
396 | |||
397 | return ret; | ||
398 | } | ||
399 | |||
400 | static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf) | ||
401 | { | ||
402 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
403 | ehca_debug_level); | ||
404 | } | ||
405 | |||
406 | static ssize_t ehca_store_debug_level(struct device_driver *ddp, | ||
407 | const char *buf, size_t count) | ||
408 | { | ||
409 | int value = (*buf) - '0'; | ||
410 | if (value >= 0 && value <= 9) | ||
411 | ehca_debug_level = value; | ||
412 | return 1; | ||
413 | } | ||
414 | |||
415 | DRIVER_ATTR(debug_level, S_IRUSR | S_IWUSR, | ||
416 | ehca_show_debug_level, ehca_store_debug_level); | ||
417 | |||
418 | void ehca_create_driver_sysfs(struct ibmebus_driver *drv) | ||
419 | { | ||
420 | driver_create_file(&drv->driver, &driver_attr_debug_level); | ||
421 | } | ||
422 | |||
423 | void ehca_remove_driver_sysfs(struct ibmebus_driver *drv) | ||
424 | { | ||
425 | driver_remove_file(&drv->driver, &driver_attr_debug_level); | ||
426 | } | ||
427 | |||
428 | #define EHCA_RESOURCE_ATTR(name) \ | ||
429 | static ssize_t ehca_show_##name(struct device *dev, \ | ||
430 | struct device_attribute *attr, \ | ||
431 | char *buf) \ | ||
432 | { \ | ||
433 | struct ehca_shca *shca; \ | ||
434 | struct hipz_query_hca *rblock; \ | ||
435 | int data; \ | ||
436 | \ | ||
437 | shca = dev->driver_data; \ | ||
438 | \ | ||
439 | rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); \ | ||
440 | if (!rblock) { \ | ||
441 | dev_err(dev, "Can't allocate rblock memory."); \ | ||
442 | return 0; \ | ||
443 | } \ | ||
444 | \ | ||
445 | if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \ | ||
446 | dev_err(dev, "Can't query device properties"); \ | ||
447 | kfree(rblock); \ | ||
448 | return 0; \ | ||
449 | } \ | ||
450 | \ | ||
451 | data = rblock->name; \ | ||
452 | kfree(rblock); \ | ||
453 | \ | ||
454 | if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1)) \ | ||
455 | return snprintf(buf, 256, "1\n"); \ | ||
456 | else \ | ||
457 | return snprintf(buf, 256, "%d\n", data); \ | ||
458 | \ | ||
459 | } \ | ||
460 | static DEVICE_ATTR(name, S_IRUGO, ehca_show_##name, NULL); | ||
461 | |||
462 | EHCA_RESOURCE_ATTR(num_ports); | ||
463 | EHCA_RESOURCE_ATTR(hw_ver); | ||
464 | EHCA_RESOURCE_ATTR(max_eq); | ||
465 | EHCA_RESOURCE_ATTR(cur_eq); | ||
466 | EHCA_RESOURCE_ATTR(max_cq); | ||
467 | EHCA_RESOURCE_ATTR(cur_cq); | ||
468 | EHCA_RESOURCE_ATTR(max_qp); | ||
469 | EHCA_RESOURCE_ATTR(cur_qp); | ||
470 | EHCA_RESOURCE_ATTR(max_mr); | ||
471 | EHCA_RESOURCE_ATTR(cur_mr); | ||
472 | EHCA_RESOURCE_ATTR(max_mw); | ||
473 | EHCA_RESOURCE_ATTR(cur_mw); | ||
474 | EHCA_RESOURCE_ATTR(max_pd); | ||
475 | EHCA_RESOURCE_ATTR(max_ah); | ||
476 | |||
477 | static ssize_t ehca_show_adapter_handle(struct device *dev, | ||
478 | struct device_attribute *attr, | ||
479 | char *buf) | ||
480 | { | ||
481 | struct ehca_shca *shca = dev->driver_data; | ||
482 | |||
483 | return sprintf(buf, "%lx\n", shca->ipz_hca_handle.handle); | ||
484 | |||
485 | } | ||
486 | static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL); | ||
487 | |||
488 | |||
489 | void ehca_create_device_sysfs(struct ibmebus_dev *dev) | ||
490 | { | ||
491 | device_create_file(&dev->ofdev.dev, &dev_attr_adapter_handle); | ||
492 | device_create_file(&dev->ofdev.dev, &dev_attr_num_ports); | ||
493 | device_create_file(&dev->ofdev.dev, &dev_attr_hw_ver); | ||
494 | device_create_file(&dev->ofdev.dev, &dev_attr_max_eq); | ||
495 | device_create_file(&dev->ofdev.dev, &dev_attr_cur_eq); | ||
496 | device_create_file(&dev->ofdev.dev, &dev_attr_max_cq); | ||
497 | device_create_file(&dev->ofdev.dev, &dev_attr_cur_cq); | ||
498 | device_create_file(&dev->ofdev.dev, &dev_attr_max_qp); | ||
499 | device_create_file(&dev->ofdev.dev, &dev_attr_cur_qp); | ||
500 | device_create_file(&dev->ofdev.dev, &dev_attr_max_mr); | ||
501 | device_create_file(&dev->ofdev.dev, &dev_attr_cur_mr); | ||
502 | device_create_file(&dev->ofdev.dev, &dev_attr_max_mw); | ||
503 | device_create_file(&dev->ofdev.dev, &dev_attr_cur_mw); | ||
504 | device_create_file(&dev->ofdev.dev, &dev_attr_max_pd); | ||
505 | device_create_file(&dev->ofdev.dev, &dev_attr_max_ah); | ||
506 | } | ||
507 | |||
508 | void ehca_remove_device_sysfs(struct ibmebus_dev *dev) | ||
509 | { | ||
510 | device_remove_file(&dev->ofdev.dev, &dev_attr_adapter_handle); | ||
511 | device_remove_file(&dev->ofdev.dev, &dev_attr_num_ports); | ||
512 | device_remove_file(&dev->ofdev.dev, &dev_attr_hw_ver); | ||
513 | device_remove_file(&dev->ofdev.dev, &dev_attr_max_eq); | ||
514 | device_remove_file(&dev->ofdev.dev, &dev_attr_cur_eq); | ||
515 | device_remove_file(&dev->ofdev.dev, &dev_attr_max_cq); | ||
516 | device_remove_file(&dev->ofdev.dev, &dev_attr_cur_cq); | ||
517 | device_remove_file(&dev->ofdev.dev, &dev_attr_max_qp); | ||
518 | device_remove_file(&dev->ofdev.dev, &dev_attr_cur_qp); | ||
519 | device_remove_file(&dev->ofdev.dev, &dev_attr_max_mr); | ||
520 | device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mr); | ||
521 | device_remove_file(&dev->ofdev.dev, &dev_attr_max_mw); | ||
522 | device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mw); | ||
523 | device_remove_file(&dev->ofdev.dev, &dev_attr_max_pd); | ||
524 | device_remove_file(&dev->ofdev.dev, &dev_attr_max_ah); | ||
525 | } | ||
526 | |||
527 | static int __devinit ehca_probe(struct ibmebus_dev *dev, | ||
528 | const struct of_device_id *id) | ||
529 | { | ||
530 | struct ehca_shca *shca; | ||
531 | u64 *handle; | ||
532 | struct ib_pd *ibpd; | ||
533 | int ret; | ||
534 | |||
535 | handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL); | ||
536 | if (!handle) { | ||
537 | ehca_gen_err("Cannot get eHCA handle for adapter: %s.", | ||
538 | dev->ofdev.node->full_name); | ||
539 | return -ENODEV; | ||
540 | } | ||
541 | |||
542 | if (!(*handle)) { | ||
543 | ehca_gen_err("Wrong eHCA handle for adapter: %s.", | ||
544 | dev->ofdev.node->full_name); | ||
545 | return -ENODEV; | ||
546 | } | ||
547 | |||
548 | shca = (struct ehca_shca *)ib_alloc_device(sizeof(*shca)); | ||
549 | if (!shca) { | ||
550 | ehca_gen_err("Cannot allocate shca memory."); | ||
551 | return -ENOMEM; | ||
552 | } | ||
553 | |||
554 | shca->ibmebus_dev = dev; | ||
555 | shca->ipz_hca_handle.handle = *handle; | ||
556 | dev->ofdev.dev.driver_data = shca; | ||
557 | |||
558 | ret = ehca_sense_attributes(shca); | ||
559 | if (ret < 0) { | ||
560 | ehca_gen_err("Cannot sense eHCA attributes."); | ||
561 | goto probe1; | ||
562 | } | ||
563 | |||
564 | ret = ehca_register_device(shca); | ||
565 | if (ret) { | ||
566 | ehca_gen_err("Cannot register Infiniband device"); | ||
567 | goto probe1; | ||
568 | } | ||
569 | |||
570 | /* create event queues */ | ||
571 | ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048); | ||
572 | if (ret) { | ||
573 | ehca_err(&shca->ib_device, "Cannot create EQ."); | ||
574 | goto probe2; | ||
575 | } | ||
576 | |||
577 | ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513); | ||
578 | if (ret) { | ||
579 | ehca_err(&shca->ib_device, "Cannot create NEQ."); | ||
580 | goto probe3; | ||
581 | } | ||
582 | |||
583 | /* create internal protection domain */ | ||
584 | ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL); | ||
585 | if (IS_ERR(ibpd)) { | ||
586 | ehca_err(&shca->ib_device, "Cannot create internal PD."); | ||
587 | ret = PTR_ERR(ibpd); | ||
588 | goto probe4; | ||
589 | } | ||
590 | |||
591 | shca->pd = container_of(ibpd, struct ehca_pd, ib_pd); | ||
592 | shca->pd->ib_pd.device = &shca->ib_device; | ||
593 | |||
594 | /* create internal max MR */ | ||
595 | ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr); | ||
596 | |||
597 | if (ret) { | ||
598 | ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x", | ||
599 | ret); | ||
600 | goto probe5; | ||
601 | } | ||
602 | |||
603 | /* create AQP1 for port 1 */ | ||
604 | if (ehca_open_aqp1 == 1) { | ||
605 | shca->sport[0].port_state = IB_PORT_DOWN; | ||
606 | ret = ehca_create_aqp1(shca, 1); | ||
607 | if (ret) { | ||
608 | ehca_err(&shca->ib_device, | ||
609 | "Cannot create AQP1 for port 1."); | ||
610 | goto probe6; | ||
611 | } | ||
612 | } | ||
613 | |||
614 | /* create AQP1 for port 2 */ | ||
615 | if ((ehca_open_aqp1 == 1) && (shca->num_ports == 2)) { | ||
616 | shca->sport[1].port_state = IB_PORT_DOWN; | ||
617 | ret = ehca_create_aqp1(shca, 2); | ||
618 | if (ret) { | ||
619 | ehca_err(&shca->ib_device, | ||
620 | "Cannot create AQP1 for port 2."); | ||
621 | goto probe7; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | ehca_create_device_sysfs(dev); | ||
626 | |||
627 | spin_lock(&shca_list_lock); | ||
628 | list_add(&shca->shca_list, &shca_list); | ||
629 | spin_unlock(&shca_list_lock); | ||
630 | |||
631 | return 0; | ||
632 | |||
633 | probe7: | ||
634 | ret = ehca_destroy_aqp1(&shca->sport[0]); | ||
635 | if (ret) | ||
636 | ehca_err(&shca->ib_device, | ||
637 | "Cannot destroy AQP1 for port 1. ret=%x", ret); | ||
638 | |||
639 | probe6: | ||
640 | ret = ehca_dereg_internal_maxmr(shca); | ||
641 | if (ret) | ||
642 | ehca_err(&shca->ib_device, | ||
643 | "Cannot destroy internal MR. ret=%x", ret); | ||
644 | |||
645 | probe5: | ||
646 | ret = ehca_dealloc_pd(&shca->pd->ib_pd); | ||
647 | if (ret) | ||
648 | ehca_err(&shca->ib_device, | ||
649 | "Cannot destroy internal PD. ret=%x", ret); | ||
650 | |||
651 | probe4: | ||
652 | ret = ehca_destroy_eq(shca, &shca->neq); | ||
653 | if (ret) | ||
654 | ehca_err(&shca->ib_device, | ||
655 | "Cannot destroy NEQ. ret=%x", ret); | ||
656 | |||
657 | probe3: | ||
658 | ret = ehca_destroy_eq(shca, &shca->eq); | ||
659 | if (ret) | ||
660 | ehca_err(&shca->ib_device, | ||
661 | "Cannot destroy EQ. ret=%x", ret); | ||
662 | |||
663 | probe2: | ||
664 | ib_unregister_device(&shca->ib_device); | ||
665 | |||
666 | probe1: | ||
667 | ib_dealloc_device(&shca->ib_device); | ||
668 | |||
669 | return -EINVAL; | ||
670 | } | ||
671 | |||
672 | static int __devexit ehca_remove(struct ibmebus_dev *dev) | ||
673 | { | ||
674 | struct ehca_shca *shca = dev->ofdev.dev.driver_data; | ||
675 | int ret; | ||
676 | |||
677 | ehca_remove_device_sysfs(dev); | ||
678 | |||
679 | if (ehca_open_aqp1 == 1) { | ||
680 | int i; | ||
681 | for (i = 0; i < shca->num_ports; i++) { | ||
682 | ret = ehca_destroy_aqp1(&shca->sport[i]); | ||
683 | if (ret) | ||
684 | ehca_err(&shca->ib_device, | ||
685 | "Cannot destroy AQP1 for port %x " | ||
686 | "ret=%x", ret, i); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | ib_unregister_device(&shca->ib_device); | ||
691 | |||
692 | ret = ehca_dereg_internal_maxmr(shca); | ||
693 | if (ret) | ||
694 | ehca_err(&shca->ib_device, | ||
695 | "Cannot destroy internal MR. ret=%x", ret); | ||
696 | |||
697 | ret = ehca_dealloc_pd(&shca->pd->ib_pd); | ||
698 | if (ret) | ||
699 | ehca_err(&shca->ib_device, | ||
700 | "Cannot destroy internal PD. ret=%x", ret); | ||
701 | |||
702 | ret = ehca_destroy_eq(shca, &shca->eq); | ||
703 | if (ret) | ||
704 | ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret); | ||
705 | |||
706 | ret = ehca_destroy_eq(shca, &shca->neq); | ||
707 | if (ret) | ||
708 | ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret); | ||
709 | |||
710 | ib_dealloc_device(&shca->ib_device); | ||
711 | |||
712 | spin_lock(&shca_list_lock); | ||
713 | list_del(&shca->shca_list); | ||
714 | spin_unlock(&shca_list_lock); | ||
715 | |||
716 | return ret; | ||
717 | } | ||
718 | |||
719 | static struct of_device_id ehca_device_table[] = | ||
720 | { | ||
721 | { | ||
722 | .name = "lhca", | ||
723 | .compatible = "IBM,lhca", | ||
724 | }, | ||
725 | {}, | ||
726 | }; | ||
727 | |||
728 | static struct ibmebus_driver ehca_driver = { | ||
729 | .name = "ehca", | ||
730 | .id_table = ehca_device_table, | ||
731 | .probe = ehca_probe, | ||
732 | .remove = ehca_remove, | ||
733 | }; | ||
734 | |||
735 | void ehca_poll_eqs(unsigned long data) | ||
736 | { | ||
737 | struct ehca_shca *shca; | ||
738 | |||
739 | spin_lock(&shca_list_lock); | ||
740 | list_for_each_entry(shca, &shca_list, shca_list) { | ||
741 | if (shca->eq.is_initialized) | ||
742 | ehca_tasklet_eq((unsigned long)(void*)shca); | ||
743 | } | ||
744 | mod_timer(&poll_eqs_timer, jiffies + HZ); | ||
745 | spin_unlock(&shca_list_lock); | ||
746 | } | ||
747 | |||
748 | int __init ehca_module_init(void) | ||
749 | { | ||
750 | int ret; | ||
751 | |||
752 | printk(KERN_INFO "eHCA Infiniband Device Driver " | ||
753 | "(Rel.: SVNEHCA_0016)\n"); | ||
754 | idr_init(&ehca_qp_idr); | ||
755 | idr_init(&ehca_cq_idr); | ||
756 | spin_lock_init(&ehca_qp_idr_lock); | ||
757 | spin_lock_init(&ehca_cq_idr_lock); | ||
758 | |||
759 | INIT_LIST_HEAD(&shca_list); | ||
760 | spin_lock_init(&shca_list_lock); | ||
761 | |||
762 | if ((ret = ehca_create_comp_pool())) { | ||
763 | ehca_gen_err("Cannot create comp pool."); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | if ((ret = ehca_create_slab_caches())) { | ||
768 | ehca_gen_err("Cannot create SLAB caches"); | ||
769 | ret = -ENOMEM; | ||
770 | goto module_init1; | ||
771 | } | ||
772 | |||
773 | if ((ret = ibmebus_register_driver(&ehca_driver))) { | ||
774 | ehca_gen_err("Cannot register eHCA device driver"); | ||
775 | ret = -EINVAL; | ||
776 | goto module_init2; | ||
777 | } | ||
778 | |||
779 | ehca_create_driver_sysfs(&ehca_driver); | ||
780 | |||
781 | if (ehca_poll_all_eqs != 1) { | ||
782 | ehca_gen_err("WARNING!!!"); | ||
783 | ehca_gen_err("It is possible to lose interrupts."); | ||
784 | } else { | ||
785 | init_timer(&poll_eqs_timer); | ||
786 | poll_eqs_timer.function = ehca_poll_eqs; | ||
787 | poll_eqs_timer.expires = jiffies + HZ; | ||
788 | add_timer(&poll_eqs_timer); | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | |||
793 | module_init2: | ||
794 | ehca_destroy_slab_caches(); | ||
795 | |||
796 | module_init1: | ||
797 | ehca_destroy_comp_pool(); | ||
798 | return ret; | ||
799 | }; | ||
800 | |||
801 | void __exit ehca_module_exit(void) | ||
802 | { | ||
803 | if (ehca_poll_all_eqs == 1) | ||
804 | del_timer_sync(&poll_eqs_timer); | ||
805 | |||
806 | ehca_remove_driver_sysfs(&ehca_driver); | ||
807 | ibmebus_unregister_driver(&ehca_driver); | ||
808 | |||
809 | ehca_destroy_slab_caches(); | ||
810 | |||
811 | ehca_destroy_comp_pool(); | ||
812 | |||
813 | idr_destroy(&ehca_cq_idr); | ||
814 | idr_destroy(&ehca_qp_idr); | ||
815 | }; | ||
816 | |||
817 | module_init(ehca_module_init); | ||
818 | module_exit(ehca_module_exit); | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c new file mode 100644 index 000000000000..32a870660bfe --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_mcast.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * mcast functions | ||
5 | * | ||
6 | * Authors: Khadija Souissi <souissik@de.ibm.com> | ||
7 | * Waleri Fomin <fomin@de.ibm.com> | ||
8 | * Reinhard Ernst <rernst@de.ibm.com> | ||
9 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
10 | * Heiko J Schick <schickhj@de.ibm.com> | ||
11 | * | ||
12 | * Copyright (c) 2005 IBM Corporation | ||
13 | * | ||
14 | * All rights reserved. | ||
15 | * | ||
16 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
17 | * BSD. | ||
18 | * | ||
19 | * OpenIB BSD License | ||
20 | * | ||
21 | * Redistribution and use in source and binary forms, with or without | ||
22 | * modification, are permitted provided that the following conditions are met: | ||
23 | * | ||
24 | * Redistributions of source code must retain the above copyright notice, this | ||
25 | * list of conditions and the following disclaimer. | ||
26 | * | ||
27 | * Redistributions in binary form must reproduce the above copyright notice, | ||
28 | * this list of conditions and the following disclaimer in the documentation | ||
29 | * and/or other materials | ||
30 | * provided with the distribution. | ||
31 | * | ||
32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
33 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
34 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
35 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
36 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
37 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
38 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
39 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
40 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
41 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
42 | * POSSIBILITY OF SUCH DAMAGE. | ||
43 | */ | ||
44 | |||
45 | #include <linux/module.h> | ||
46 | #include <linux/err.h> | ||
47 | #include "ehca_classes.h" | ||
48 | #include "ehca_tools.h" | ||
49 | #include "ehca_qes.h" | ||
50 | #include "ehca_iverbs.h" | ||
51 | #include "hcp_if.h" | ||
52 | |||
53 | #define MAX_MC_LID 0xFFFE | ||
54 | #define MIN_MC_LID 0xC000 /* Multicast limits */ | ||
55 | #define EHCA_VALID_MULTICAST_GID(gid) ((gid)[0] == 0xFF) | ||
56 | #define EHCA_VALID_MULTICAST_LID(lid) \ | ||
57 | (((lid) >= MIN_MC_LID) && ((lid) <= MAX_MC_LID)) | ||
58 | |||
59 | int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
60 | { | ||
61 | struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); | ||
62 | struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, | ||
63 | ib_device); | ||
64 | union ib_gid my_gid; | ||
65 | u64 subnet_prefix, interface_id, h_ret; | ||
66 | |||
67 | if (ibqp->qp_type != IB_QPT_UD) { | ||
68 | ehca_err(ibqp->device, "invalid qp_type=%x", ibqp->qp_type); | ||
69 | return -EINVAL; | ||
70 | } | ||
71 | |||
72 | if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) { | ||
73 | ehca_err(ibqp->device, "invalid mulitcast gid"); | ||
74 | return -EINVAL; | ||
75 | } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) { | ||
76 | ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid)); | ||
81 | |||
82 | subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix); | ||
83 | interface_id = be64_to_cpu(my_gid.global.interface_id); | ||
84 | h_ret = hipz_h_attach_mcqp(shca->ipz_hca_handle, | ||
85 | my_qp->ipz_qp_handle, | ||
86 | my_qp->galpas.kernel, | ||
87 | lid, subnet_prefix, interface_id); | ||
88 | if (h_ret != H_SUCCESS) | ||
89 | ehca_err(ibqp->device, | ||
90 | "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed " | ||
91 | "h_ret=%lx", my_qp, ibqp->qp_num, h_ret); | ||
92 | |||
93 | return ehca2ib_return_code(h_ret); | ||
94 | } | ||
95 | |||
96 | int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
97 | { | ||
98 | struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); | ||
99 | struct ehca_shca *shca = container_of(ibqp->pd->device, | ||
100 | struct ehca_shca, ib_device); | ||
101 | union ib_gid my_gid; | ||
102 | u64 subnet_prefix, interface_id, h_ret; | ||
103 | |||
104 | if (ibqp->qp_type != IB_QPT_UD) { | ||
105 | ehca_err(ibqp->device, "invalid qp_type %x", ibqp->qp_type); | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | |||
109 | if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) { | ||
110 | ehca_err(ibqp->device, "invalid mulitcast gid"); | ||
111 | return -EINVAL; | ||
112 | } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) { | ||
113 | ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid); | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid)); | ||
118 | |||
119 | subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix); | ||
120 | interface_id = be64_to_cpu(my_gid.global.interface_id); | ||
121 | h_ret = hipz_h_detach_mcqp(shca->ipz_hca_handle, | ||
122 | my_qp->ipz_qp_handle, | ||
123 | my_qp->galpas.kernel, | ||
124 | lid, subnet_prefix, interface_id); | ||
125 | if (h_ret != H_SUCCESS) | ||
126 | ehca_err(ibqp->device, | ||
127 | "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed " | ||
128 | "h_ret=%lx", my_qp, ibqp->qp_num, h_ret); | ||
129 | |||
130 | return ehca2ib_return_code(h_ret); | ||
131 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c new file mode 100644 index 000000000000..5ca65441e1da --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c | |||
@@ -0,0 +1,2261 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * MR/MW functions | ||
5 | * | ||
6 | * Authors: Dietmar Decker <ddecker@de.ibm.com> | ||
7 | * Christoph Raisch <raisch@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #include <asm/current.h> | ||
43 | |||
44 | #include "ehca_iverbs.h" | ||
45 | #include "ehca_mrmw.h" | ||
46 | #include "hcp_if.h" | ||
47 | #include "hipz_hw.h" | ||
48 | |||
49 | static struct kmem_cache *mr_cache; | ||
50 | static struct kmem_cache *mw_cache; | ||
51 | |||
52 | static struct ehca_mr *ehca_mr_new(void) | ||
53 | { | ||
54 | struct ehca_mr *me; | ||
55 | |||
56 | me = kmem_cache_alloc(mr_cache, SLAB_KERNEL); | ||
57 | if (me) { | ||
58 | memset(me, 0, sizeof(struct ehca_mr)); | ||
59 | spin_lock_init(&me->mrlock); | ||
60 | } else | ||
61 | ehca_gen_err("alloc failed"); | ||
62 | |||
63 | return me; | ||
64 | } | ||
65 | |||
66 | static void ehca_mr_delete(struct ehca_mr *me) | ||
67 | { | ||
68 | kmem_cache_free(mr_cache, me); | ||
69 | } | ||
70 | |||
71 | static struct ehca_mw *ehca_mw_new(void) | ||
72 | { | ||
73 | struct ehca_mw *me; | ||
74 | |||
75 | me = kmem_cache_alloc(mw_cache, SLAB_KERNEL); | ||
76 | if (me) { | ||
77 | memset(me, 0, sizeof(struct ehca_mw)); | ||
78 | spin_lock_init(&me->mwlock); | ||
79 | } else | ||
80 | ehca_gen_err("alloc failed"); | ||
81 | |||
82 | return me; | ||
83 | } | ||
84 | |||
85 | static void ehca_mw_delete(struct ehca_mw *me) | ||
86 | { | ||
87 | kmem_cache_free(mw_cache, me); | ||
88 | } | ||
89 | |||
90 | /*----------------------------------------------------------------------*/ | ||
91 | |||
92 | struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags) | ||
93 | { | ||
94 | struct ib_mr *ib_mr; | ||
95 | int ret; | ||
96 | struct ehca_mr *e_maxmr; | ||
97 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
98 | struct ehca_shca *shca = | ||
99 | container_of(pd->device, struct ehca_shca, ib_device); | ||
100 | |||
101 | if (shca->maxmr) { | ||
102 | e_maxmr = ehca_mr_new(); | ||
103 | if (!e_maxmr) { | ||
104 | ehca_err(&shca->ib_device, "out of memory"); | ||
105 | ib_mr = ERR_PTR(-ENOMEM); | ||
106 | goto get_dma_mr_exit0; | ||
107 | } | ||
108 | |||
109 | ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE, | ||
110 | mr_access_flags, e_pd, | ||
111 | &e_maxmr->ib.ib_mr.lkey, | ||
112 | &e_maxmr->ib.ib_mr.rkey); | ||
113 | if (ret) { | ||
114 | ib_mr = ERR_PTR(ret); | ||
115 | goto get_dma_mr_exit0; | ||
116 | } | ||
117 | ib_mr = &e_maxmr->ib.ib_mr; | ||
118 | } else { | ||
119 | ehca_err(&shca->ib_device, "no internal max-MR exist!"); | ||
120 | ib_mr = ERR_PTR(-EINVAL); | ||
121 | goto get_dma_mr_exit0; | ||
122 | } | ||
123 | |||
124 | get_dma_mr_exit0: | ||
125 | if (IS_ERR(ib_mr)) | ||
126 | ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ", | ||
127 | PTR_ERR(ib_mr), pd, mr_access_flags); | ||
128 | return ib_mr; | ||
129 | } /* end ehca_get_dma_mr() */ | ||
130 | |||
131 | /*----------------------------------------------------------------------*/ | ||
132 | |||
133 | struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, | ||
134 | struct ib_phys_buf *phys_buf_array, | ||
135 | int num_phys_buf, | ||
136 | int mr_access_flags, | ||
137 | u64 *iova_start) | ||
138 | { | ||
139 | struct ib_mr *ib_mr; | ||
140 | int ret; | ||
141 | struct ehca_mr *e_mr; | ||
142 | struct ehca_shca *shca = | ||
143 | container_of(pd->device, struct ehca_shca, ib_device); | ||
144 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
145 | |||
146 | u64 size; | ||
147 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
148 | u32 num_pages_mr; | ||
149 | u32 num_pages_4k; /* 4k portion "pages" */ | ||
150 | |||
151 | if ((num_phys_buf <= 0) || !phys_buf_array) { | ||
152 | ehca_err(pd->device, "bad input values: num_phys_buf=%x " | ||
153 | "phys_buf_array=%p", num_phys_buf, phys_buf_array); | ||
154 | ib_mr = ERR_PTR(-EINVAL); | ||
155 | goto reg_phys_mr_exit0; | ||
156 | } | ||
157 | if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && | ||
158 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) || | ||
159 | ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) && | ||
160 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) { | ||
161 | /* | ||
162 | * Remote Write Access requires Local Write Access | ||
163 | * Remote Atomic Access requires Local Write Access | ||
164 | */ | ||
165 | ehca_err(pd->device, "bad input values: mr_access_flags=%x", | ||
166 | mr_access_flags); | ||
167 | ib_mr = ERR_PTR(-EINVAL); | ||
168 | goto reg_phys_mr_exit0; | ||
169 | } | ||
170 | |||
171 | /* check physical buffer list and calculate size */ | ||
172 | ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array, num_phys_buf, | ||
173 | iova_start, &size); | ||
174 | if (ret) { | ||
175 | ib_mr = ERR_PTR(ret); | ||
176 | goto reg_phys_mr_exit0; | ||
177 | } | ||
178 | if ((size == 0) || | ||
179 | (((u64)iova_start + size) < (u64)iova_start)) { | ||
180 | ehca_err(pd->device, "bad input values: size=%lx iova_start=%p", | ||
181 | size, iova_start); | ||
182 | ib_mr = ERR_PTR(-EINVAL); | ||
183 | goto reg_phys_mr_exit0; | ||
184 | } | ||
185 | |||
186 | e_mr = ehca_mr_new(); | ||
187 | if (!e_mr) { | ||
188 | ehca_err(pd->device, "out of memory"); | ||
189 | ib_mr = ERR_PTR(-ENOMEM); | ||
190 | goto reg_phys_mr_exit0; | ||
191 | } | ||
192 | |||
193 | /* determine number of MR pages */ | ||
194 | num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size + | ||
195 | PAGE_SIZE - 1) / PAGE_SIZE); | ||
196 | num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size + | ||
197 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | ||
198 | |||
199 | /* register MR on HCA */ | ||
200 | if (ehca_mr_is_maxmr(size, iova_start)) { | ||
201 | e_mr->flags |= EHCA_MR_FLAG_MAXMR; | ||
202 | ret = ehca_reg_maxmr(shca, e_mr, iova_start, mr_access_flags, | ||
203 | e_pd, &e_mr->ib.ib_mr.lkey, | ||
204 | &e_mr->ib.ib_mr.rkey); | ||
205 | if (ret) { | ||
206 | ib_mr = ERR_PTR(ret); | ||
207 | goto reg_phys_mr_exit1; | ||
208 | } | ||
209 | } else { | ||
210 | pginfo.type = EHCA_MR_PGI_PHYS; | ||
211 | pginfo.num_pages = num_pages_mr; | ||
212 | pginfo.num_4k = num_pages_4k; | ||
213 | pginfo.num_phys_buf = num_phys_buf; | ||
214 | pginfo.phys_buf_array = phys_buf_array; | ||
215 | pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) / | ||
216 | EHCA_PAGESIZE); | ||
217 | |||
218 | ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags, | ||
219 | e_pd, &pginfo, &e_mr->ib.ib_mr.lkey, | ||
220 | &e_mr->ib.ib_mr.rkey); | ||
221 | if (ret) { | ||
222 | ib_mr = ERR_PTR(ret); | ||
223 | goto reg_phys_mr_exit1; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* successful registration of all pages */ | ||
228 | return &e_mr->ib.ib_mr; | ||
229 | |||
230 | reg_phys_mr_exit1: | ||
231 | ehca_mr_delete(e_mr); | ||
232 | reg_phys_mr_exit0: | ||
233 | if (IS_ERR(ib_mr)) | ||
234 | ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p " | ||
235 | "num_phys_buf=%x mr_access_flags=%x iova_start=%p", | ||
236 | PTR_ERR(ib_mr), pd, phys_buf_array, | ||
237 | num_phys_buf, mr_access_flags, iova_start); | ||
238 | return ib_mr; | ||
239 | } /* end ehca_reg_phys_mr() */ | ||
240 | |||
241 | /*----------------------------------------------------------------------*/ | ||
242 | |||
243 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, | ||
244 | struct ib_umem *region, | ||
245 | int mr_access_flags, | ||
246 | struct ib_udata *udata) | ||
247 | { | ||
248 | struct ib_mr *ib_mr; | ||
249 | struct ehca_mr *e_mr; | ||
250 | struct ehca_shca *shca = | ||
251 | container_of(pd->device, struct ehca_shca, ib_device); | ||
252 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
253 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
254 | int ret; | ||
255 | u32 num_pages_mr; | ||
256 | u32 num_pages_4k; /* 4k portion "pages" */ | ||
257 | |||
258 | if (!pd) { | ||
259 | ehca_gen_err("bad pd=%p", pd); | ||
260 | return ERR_PTR(-EFAULT); | ||
261 | } | ||
262 | if (!region) { | ||
263 | ehca_err(pd->device, "bad input values: region=%p", region); | ||
264 | ib_mr = ERR_PTR(-EINVAL); | ||
265 | goto reg_user_mr_exit0; | ||
266 | } | ||
267 | if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && | ||
268 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) || | ||
269 | ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) && | ||
270 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) { | ||
271 | /* | ||
272 | * Remote Write Access requires Local Write Access | ||
273 | * Remote Atomic Access requires Local Write Access | ||
274 | */ | ||
275 | ehca_err(pd->device, "bad input values: mr_access_flags=%x", | ||
276 | mr_access_flags); | ||
277 | ib_mr = ERR_PTR(-EINVAL); | ||
278 | goto reg_user_mr_exit0; | ||
279 | } | ||
280 | if (region->page_size != PAGE_SIZE) { | ||
281 | ehca_err(pd->device, "page size not supported, " | ||
282 | "region->page_size=%x", region->page_size); | ||
283 | ib_mr = ERR_PTR(-EINVAL); | ||
284 | goto reg_user_mr_exit0; | ||
285 | } | ||
286 | |||
287 | if ((region->length == 0) || | ||
288 | ((region->virt_base + region->length) < region->virt_base)) { | ||
289 | ehca_err(pd->device, "bad input values: length=%lx " | ||
290 | "virt_base=%lx", region->length, region->virt_base); | ||
291 | ib_mr = ERR_PTR(-EINVAL); | ||
292 | goto reg_user_mr_exit0; | ||
293 | } | ||
294 | |||
295 | e_mr = ehca_mr_new(); | ||
296 | if (!e_mr) { | ||
297 | ehca_err(pd->device, "out of memory"); | ||
298 | ib_mr = ERR_PTR(-ENOMEM); | ||
299 | goto reg_user_mr_exit0; | ||
300 | } | ||
301 | |||
302 | /* determine number of MR pages */ | ||
303 | num_pages_mr = (((region->virt_base % PAGE_SIZE) + region->length + | ||
304 | PAGE_SIZE - 1) / PAGE_SIZE); | ||
305 | num_pages_4k = (((region->virt_base % EHCA_PAGESIZE) + region->length + | ||
306 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | ||
307 | |||
308 | /* register MR on HCA */ | ||
309 | pginfo.type = EHCA_MR_PGI_USER; | ||
310 | pginfo.num_pages = num_pages_mr; | ||
311 | pginfo.num_4k = num_pages_4k; | ||
312 | pginfo.region = region; | ||
313 | pginfo.next_4k = region->offset / EHCA_PAGESIZE; | ||
314 | pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk, | ||
315 | (®ion->chunk_list), | ||
316 | list); | ||
317 | |||
318 | ret = ehca_reg_mr(shca, e_mr, (u64*)region->virt_base, | ||
319 | region->length, mr_access_flags, e_pd, &pginfo, | ||
320 | &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey); | ||
321 | if (ret) { | ||
322 | ib_mr = ERR_PTR(ret); | ||
323 | goto reg_user_mr_exit1; | ||
324 | } | ||
325 | |||
326 | /* successful registration of all pages */ | ||
327 | return &e_mr->ib.ib_mr; | ||
328 | |||
329 | reg_user_mr_exit1: | ||
330 | ehca_mr_delete(e_mr); | ||
331 | reg_user_mr_exit0: | ||
332 | if (IS_ERR(ib_mr)) | ||
333 | ehca_err(pd->device, "rc=%lx pd=%p region=%p mr_access_flags=%x" | ||
334 | " udata=%p", | ||
335 | PTR_ERR(ib_mr), pd, region, mr_access_flags, udata); | ||
336 | return ib_mr; | ||
337 | } /* end ehca_reg_user_mr() */ | ||
338 | |||
339 | /*----------------------------------------------------------------------*/ | ||
340 | |||
341 | int ehca_rereg_phys_mr(struct ib_mr *mr, | ||
342 | int mr_rereg_mask, | ||
343 | struct ib_pd *pd, | ||
344 | struct ib_phys_buf *phys_buf_array, | ||
345 | int num_phys_buf, | ||
346 | int mr_access_flags, | ||
347 | u64 *iova_start) | ||
348 | { | ||
349 | int ret; | ||
350 | |||
351 | struct ehca_shca *shca = | ||
352 | container_of(mr->device, struct ehca_shca, ib_device); | ||
353 | struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr); | ||
354 | struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd); | ||
355 | u64 new_size; | ||
356 | u64 *new_start; | ||
357 | u32 new_acl; | ||
358 | struct ehca_pd *new_pd; | ||
359 | u32 tmp_lkey, tmp_rkey; | ||
360 | unsigned long sl_flags; | ||
361 | u32 num_pages_mr = 0; | ||
362 | u32 num_pages_4k = 0; /* 4k portion "pages" */ | ||
363 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
364 | u32 cur_pid = current->tgid; | ||
365 | |||
366 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
367 | (my_pd->ownpid != cur_pid)) { | ||
368 | ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x", | ||
369 | cur_pid, my_pd->ownpid); | ||
370 | ret = -EINVAL; | ||
371 | goto rereg_phys_mr_exit0; | ||
372 | } | ||
373 | |||
374 | if (!(mr_rereg_mask & IB_MR_REREG_TRANS)) { | ||
375 | /* TODO not supported, because PHYP rereg hCall needs pages */ | ||
376 | ehca_err(mr->device, "rereg without IB_MR_REREG_TRANS not " | ||
377 | "supported yet, mr_rereg_mask=%x", mr_rereg_mask); | ||
378 | ret = -EINVAL; | ||
379 | goto rereg_phys_mr_exit0; | ||
380 | } | ||
381 | |||
382 | if (mr_rereg_mask & IB_MR_REREG_PD) { | ||
383 | if (!pd) { | ||
384 | ehca_err(mr->device, "rereg with bad pd, pd=%p " | ||
385 | "mr_rereg_mask=%x", pd, mr_rereg_mask); | ||
386 | ret = -EINVAL; | ||
387 | goto rereg_phys_mr_exit0; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | if ((mr_rereg_mask & | ||
392 | ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS)) || | ||
393 | (mr_rereg_mask == 0)) { | ||
394 | ret = -EINVAL; | ||
395 | goto rereg_phys_mr_exit0; | ||
396 | } | ||
397 | |||
398 | /* check other parameters */ | ||
399 | if (e_mr == shca->maxmr) { | ||
400 | /* should be impossible, however reject to be sure */ | ||
401 | ehca_err(mr->device, "rereg internal max-MR impossible, mr=%p " | ||
402 | "shca->maxmr=%p mr->lkey=%x", | ||
403 | mr, shca->maxmr, mr->lkey); | ||
404 | ret = -EINVAL; | ||
405 | goto rereg_phys_mr_exit0; | ||
406 | } | ||
407 | if (mr_rereg_mask & IB_MR_REREG_TRANS) { /* transl., i.e. addr/size */ | ||
408 | if (e_mr->flags & EHCA_MR_FLAG_FMR) { | ||
409 | ehca_err(mr->device, "not supported for FMR, mr=%p " | ||
410 | "flags=%x", mr, e_mr->flags); | ||
411 | ret = -EINVAL; | ||
412 | goto rereg_phys_mr_exit0; | ||
413 | } | ||
414 | if (!phys_buf_array || num_phys_buf <= 0) { | ||
415 | ehca_err(mr->device, "bad input values: mr_rereg_mask=%x" | ||
416 | " phys_buf_array=%p num_phys_buf=%x", | ||
417 | mr_rereg_mask, phys_buf_array, num_phys_buf); | ||
418 | ret = -EINVAL; | ||
419 | goto rereg_phys_mr_exit0; | ||
420 | } | ||
421 | } | ||
422 | if ((mr_rereg_mask & IB_MR_REREG_ACCESS) && /* change ACL */ | ||
423 | (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && | ||
424 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) || | ||
425 | ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) && | ||
426 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)))) { | ||
427 | /* | ||
428 | * Remote Write Access requires Local Write Access | ||
429 | * Remote Atomic Access requires Local Write Access | ||
430 | */ | ||
431 | ehca_err(mr->device, "bad input values: mr_rereg_mask=%x " | ||
432 | "mr_access_flags=%x", mr_rereg_mask, mr_access_flags); | ||
433 | ret = -EINVAL; | ||
434 | goto rereg_phys_mr_exit0; | ||
435 | } | ||
436 | |||
437 | /* set requested values dependent on rereg request */ | ||
438 | spin_lock_irqsave(&e_mr->mrlock, sl_flags); | ||
439 | new_start = e_mr->start; /* new == old address */ | ||
440 | new_size = e_mr->size; /* new == old length */ | ||
441 | new_acl = e_mr->acl; /* new == old access control */ | ||
442 | new_pd = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/ | ||
443 | |||
444 | if (mr_rereg_mask & IB_MR_REREG_TRANS) { | ||
445 | new_start = iova_start; /* change address */ | ||
446 | /* check physical buffer list and calculate size */ | ||
447 | ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array, | ||
448 | num_phys_buf, iova_start, | ||
449 | &new_size); | ||
450 | if (ret) | ||
451 | goto rereg_phys_mr_exit1; | ||
452 | if ((new_size == 0) || | ||
453 | (((u64)iova_start + new_size) < (u64)iova_start)) { | ||
454 | ehca_err(mr->device, "bad input values: new_size=%lx " | ||
455 | "iova_start=%p", new_size, iova_start); | ||
456 | ret = -EINVAL; | ||
457 | goto rereg_phys_mr_exit1; | ||
458 | } | ||
459 | num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size + | ||
460 | PAGE_SIZE - 1) / PAGE_SIZE); | ||
461 | num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size + | ||
462 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | ||
463 | pginfo.type = EHCA_MR_PGI_PHYS; | ||
464 | pginfo.num_pages = num_pages_mr; | ||
465 | pginfo.num_4k = num_pages_4k; | ||
466 | pginfo.num_phys_buf = num_phys_buf; | ||
467 | pginfo.phys_buf_array = phys_buf_array; | ||
468 | pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) / | ||
469 | EHCA_PAGESIZE); | ||
470 | } | ||
471 | if (mr_rereg_mask & IB_MR_REREG_ACCESS) | ||
472 | new_acl = mr_access_flags; | ||
473 | if (mr_rereg_mask & IB_MR_REREG_PD) | ||
474 | new_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
475 | |||
476 | ret = ehca_rereg_mr(shca, e_mr, new_start, new_size, new_acl, | ||
477 | new_pd, &pginfo, &tmp_lkey, &tmp_rkey); | ||
478 | if (ret) | ||
479 | goto rereg_phys_mr_exit1; | ||
480 | |||
481 | /* successful reregistration */ | ||
482 | if (mr_rereg_mask & IB_MR_REREG_PD) | ||
483 | mr->pd = pd; | ||
484 | mr->lkey = tmp_lkey; | ||
485 | mr->rkey = tmp_rkey; | ||
486 | |||
487 | rereg_phys_mr_exit1: | ||
488 | spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); | ||
489 | rereg_phys_mr_exit0: | ||
490 | if (ret) | ||
491 | ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p " | ||
492 | "phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x " | ||
493 | "iova_start=%p", | ||
494 | ret, mr, mr_rereg_mask, pd, phys_buf_array, | ||
495 | num_phys_buf, mr_access_flags, iova_start); | ||
496 | return ret; | ||
497 | } /* end ehca_rereg_phys_mr() */ | ||
498 | |||
499 | /*----------------------------------------------------------------------*/ | ||
500 | |||
501 | int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) | ||
502 | { | ||
503 | int ret = 0; | ||
504 | u64 h_ret; | ||
505 | struct ehca_shca *shca = | ||
506 | container_of(mr->device, struct ehca_shca, ib_device); | ||
507 | struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr); | ||
508 | struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd); | ||
509 | u32 cur_pid = current->tgid; | ||
510 | unsigned long sl_flags; | ||
511 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | ||
512 | |||
513 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
514 | (my_pd->ownpid != cur_pid)) { | ||
515 | ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x", | ||
516 | cur_pid, my_pd->ownpid); | ||
517 | ret = -EINVAL; | ||
518 | goto query_mr_exit0; | ||
519 | } | ||
520 | |||
521 | if ((e_mr->flags & EHCA_MR_FLAG_FMR)) { | ||
522 | ehca_err(mr->device, "not supported for FMR, mr=%p e_mr=%p " | ||
523 | "e_mr->flags=%x", mr, e_mr, e_mr->flags); | ||
524 | ret = -EINVAL; | ||
525 | goto query_mr_exit0; | ||
526 | } | ||
527 | |||
528 | memset(mr_attr, 0, sizeof(struct ib_mr_attr)); | ||
529 | spin_lock_irqsave(&e_mr->mrlock, sl_flags); | ||
530 | |||
531 | h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout); | ||
532 | if (h_ret != H_SUCCESS) { | ||
533 | ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p " | ||
534 | "hca_hndl=%lx mr_hndl=%lx lkey=%x", | ||
535 | h_ret, mr, shca->ipz_hca_handle.handle, | ||
536 | e_mr->ipz_mr_handle.handle, mr->lkey); | ||
537 | ret = ehca_mrmw_map_hrc_query_mr(h_ret); | ||
538 | goto query_mr_exit1; | ||
539 | } | ||
540 | mr_attr->pd = mr->pd; | ||
541 | mr_attr->device_virt_addr = hipzout.vaddr; | ||
542 | mr_attr->size = hipzout.len; | ||
543 | mr_attr->lkey = hipzout.lkey; | ||
544 | mr_attr->rkey = hipzout.rkey; | ||
545 | ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags); | ||
546 | |||
547 | query_mr_exit1: | ||
548 | spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); | ||
549 | query_mr_exit0: | ||
550 | if (ret) | ||
551 | ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p", | ||
552 | ret, mr, mr_attr); | ||
553 | return ret; | ||
554 | } /* end ehca_query_mr() */ | ||
555 | |||
556 | /*----------------------------------------------------------------------*/ | ||
557 | |||
558 | int ehca_dereg_mr(struct ib_mr *mr) | ||
559 | { | ||
560 | int ret = 0; | ||
561 | u64 h_ret; | ||
562 | struct ehca_shca *shca = | ||
563 | container_of(mr->device, struct ehca_shca, ib_device); | ||
564 | struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr); | ||
565 | struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd); | ||
566 | u32 cur_pid = current->tgid; | ||
567 | |||
568 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
569 | (my_pd->ownpid != cur_pid)) { | ||
570 | ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x", | ||
571 | cur_pid, my_pd->ownpid); | ||
572 | ret = -EINVAL; | ||
573 | goto dereg_mr_exit0; | ||
574 | } | ||
575 | |||
576 | if ((e_mr->flags & EHCA_MR_FLAG_FMR)) { | ||
577 | ehca_err(mr->device, "not supported for FMR, mr=%p e_mr=%p " | ||
578 | "e_mr->flags=%x", mr, e_mr, e_mr->flags); | ||
579 | ret = -EINVAL; | ||
580 | goto dereg_mr_exit0; | ||
581 | } else if (e_mr == shca->maxmr) { | ||
582 | /* should be impossible, however reject to be sure */ | ||
583 | ehca_err(mr->device, "dereg internal max-MR impossible, mr=%p " | ||
584 | "shca->maxmr=%p mr->lkey=%x", | ||
585 | mr, shca->maxmr, mr->lkey); | ||
586 | ret = -EINVAL; | ||
587 | goto dereg_mr_exit0; | ||
588 | } | ||
589 | |||
590 | /* TODO: BUSY: MR still has bound window(s) */ | ||
591 | h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); | ||
592 | if (h_ret != H_SUCCESS) { | ||
593 | ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p " | ||
594 | "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x", | ||
595 | h_ret, shca, e_mr, shca->ipz_hca_handle.handle, | ||
596 | e_mr->ipz_mr_handle.handle, mr->lkey); | ||
597 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | ||
598 | goto dereg_mr_exit0; | ||
599 | } | ||
600 | |||
601 | /* successful deregistration */ | ||
602 | ehca_mr_delete(e_mr); | ||
603 | |||
604 | dereg_mr_exit0: | ||
605 | if (ret) | ||
606 | ehca_err(mr->device, "ret=%x mr=%p", ret, mr); | ||
607 | return ret; | ||
608 | } /* end ehca_dereg_mr() */ | ||
609 | |||
610 | /*----------------------------------------------------------------------*/ | ||
611 | |||
612 | struct ib_mw *ehca_alloc_mw(struct ib_pd *pd) | ||
613 | { | ||
614 | struct ib_mw *ib_mw; | ||
615 | u64 h_ret; | ||
616 | struct ehca_mw *e_mw; | ||
617 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
618 | struct ehca_shca *shca = | ||
619 | container_of(pd->device, struct ehca_shca, ib_device); | ||
620 | struct ehca_mw_hipzout_parms hipzout = {{0},0}; | ||
621 | |||
622 | e_mw = ehca_mw_new(); | ||
623 | if (!e_mw) { | ||
624 | ib_mw = ERR_PTR(-ENOMEM); | ||
625 | goto alloc_mw_exit0; | ||
626 | } | ||
627 | |||
628 | h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw, | ||
629 | e_pd->fw_pd, &hipzout); | ||
630 | if (h_ret != H_SUCCESS) { | ||
631 | ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx " | ||
632 | "shca=%p hca_hndl=%lx mw=%p", | ||
633 | h_ret, shca, shca->ipz_hca_handle.handle, e_mw); | ||
634 | ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret)); | ||
635 | goto alloc_mw_exit1; | ||
636 | } | ||
637 | /* successful MW allocation */ | ||
638 | e_mw->ipz_mw_handle = hipzout.handle; | ||
639 | e_mw->ib_mw.rkey = hipzout.rkey; | ||
640 | return &e_mw->ib_mw; | ||
641 | |||
642 | alloc_mw_exit1: | ||
643 | ehca_mw_delete(e_mw); | ||
644 | alloc_mw_exit0: | ||
645 | if (IS_ERR(ib_mw)) | ||
646 | ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd); | ||
647 | return ib_mw; | ||
648 | } /* end ehca_alloc_mw() */ | ||
649 | |||
650 | /*----------------------------------------------------------------------*/ | ||
651 | |||
652 | int ehca_bind_mw(struct ib_qp *qp, | ||
653 | struct ib_mw *mw, | ||
654 | struct ib_mw_bind *mw_bind) | ||
655 | { | ||
656 | /* TODO: not supported up to now */ | ||
657 | ehca_gen_err("bind MW currently not supported by HCAD"); | ||
658 | |||
659 | return -EPERM; | ||
660 | } /* end ehca_bind_mw() */ | ||
661 | |||
662 | /*----------------------------------------------------------------------*/ | ||
663 | |||
664 | int ehca_dealloc_mw(struct ib_mw *mw) | ||
665 | { | ||
666 | u64 h_ret; | ||
667 | struct ehca_shca *shca = | ||
668 | container_of(mw->device, struct ehca_shca, ib_device); | ||
669 | struct ehca_mw *e_mw = container_of(mw, struct ehca_mw, ib_mw); | ||
670 | |||
671 | h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw); | ||
672 | if (h_ret != H_SUCCESS) { | ||
673 | ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p " | ||
674 | "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx", | ||
675 | h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle, | ||
676 | e_mw->ipz_mw_handle.handle); | ||
677 | return ehca_mrmw_map_hrc_free_mw(h_ret); | ||
678 | } | ||
679 | /* successful deallocation */ | ||
680 | ehca_mw_delete(e_mw); | ||
681 | return 0; | ||
682 | } /* end ehca_dealloc_mw() */ | ||
683 | |||
684 | /*----------------------------------------------------------------------*/ | ||
685 | |||
686 | struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd, | ||
687 | int mr_access_flags, | ||
688 | struct ib_fmr_attr *fmr_attr) | ||
689 | { | ||
690 | struct ib_fmr *ib_fmr; | ||
691 | struct ehca_shca *shca = | ||
692 | container_of(pd->device, struct ehca_shca, ib_device); | ||
693 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
694 | struct ehca_mr *e_fmr; | ||
695 | int ret; | ||
696 | u32 tmp_lkey, tmp_rkey; | ||
697 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
698 | |||
699 | /* check other parameters */ | ||
700 | if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && | ||
701 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) || | ||
702 | ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) && | ||
703 | !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) { | ||
704 | /* | ||
705 | * Remote Write Access requires Local Write Access | ||
706 | * Remote Atomic Access requires Local Write Access | ||
707 | */ | ||
708 | ehca_err(pd->device, "bad input values: mr_access_flags=%x", | ||
709 | mr_access_flags); | ||
710 | ib_fmr = ERR_PTR(-EINVAL); | ||
711 | goto alloc_fmr_exit0; | ||
712 | } | ||
713 | if (mr_access_flags & IB_ACCESS_MW_BIND) { | ||
714 | ehca_err(pd->device, "bad input values: mr_access_flags=%x", | ||
715 | mr_access_flags); | ||
716 | ib_fmr = ERR_PTR(-EINVAL); | ||
717 | goto alloc_fmr_exit0; | ||
718 | } | ||
719 | if ((fmr_attr->max_pages == 0) || (fmr_attr->max_maps == 0)) { | ||
720 | ehca_err(pd->device, "bad input values: fmr_attr->max_pages=%x " | ||
721 | "fmr_attr->max_maps=%x fmr_attr->page_shift=%x", | ||
722 | fmr_attr->max_pages, fmr_attr->max_maps, | ||
723 | fmr_attr->page_shift); | ||
724 | ib_fmr = ERR_PTR(-EINVAL); | ||
725 | goto alloc_fmr_exit0; | ||
726 | } | ||
727 | if (((1 << fmr_attr->page_shift) != EHCA_PAGESIZE) && | ||
728 | ((1 << fmr_attr->page_shift) != PAGE_SIZE)) { | ||
729 | ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x", | ||
730 | fmr_attr->page_shift); | ||
731 | ib_fmr = ERR_PTR(-EINVAL); | ||
732 | goto alloc_fmr_exit0; | ||
733 | } | ||
734 | |||
735 | e_fmr = ehca_mr_new(); | ||
736 | if (!e_fmr) { | ||
737 | ib_fmr = ERR_PTR(-ENOMEM); | ||
738 | goto alloc_fmr_exit0; | ||
739 | } | ||
740 | e_fmr->flags |= EHCA_MR_FLAG_FMR; | ||
741 | |||
742 | /* register MR on HCA */ | ||
743 | ret = ehca_reg_mr(shca, e_fmr, NULL, | ||
744 | fmr_attr->max_pages * (1 << fmr_attr->page_shift), | ||
745 | mr_access_flags, e_pd, &pginfo, | ||
746 | &tmp_lkey, &tmp_rkey); | ||
747 | if (ret) { | ||
748 | ib_fmr = ERR_PTR(ret); | ||
749 | goto alloc_fmr_exit1; | ||
750 | } | ||
751 | |||
752 | /* successful */ | ||
753 | e_fmr->fmr_page_size = 1 << fmr_attr->page_shift; | ||
754 | e_fmr->fmr_max_pages = fmr_attr->max_pages; | ||
755 | e_fmr->fmr_max_maps = fmr_attr->max_maps; | ||
756 | e_fmr->fmr_map_cnt = 0; | ||
757 | return &e_fmr->ib.ib_fmr; | ||
758 | |||
759 | alloc_fmr_exit1: | ||
760 | ehca_mr_delete(e_fmr); | ||
761 | alloc_fmr_exit0: | ||
762 | if (IS_ERR(ib_fmr)) | ||
763 | ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x " | ||
764 | "fmr_attr=%p", PTR_ERR(ib_fmr), pd, | ||
765 | mr_access_flags, fmr_attr); | ||
766 | return ib_fmr; | ||
767 | } /* end ehca_alloc_fmr() */ | ||
768 | |||
769 | /*----------------------------------------------------------------------*/ | ||
770 | |||
771 | int ehca_map_phys_fmr(struct ib_fmr *fmr, | ||
772 | u64 *page_list, | ||
773 | int list_len, | ||
774 | u64 iova) | ||
775 | { | ||
776 | int ret; | ||
777 | struct ehca_shca *shca = | ||
778 | container_of(fmr->device, struct ehca_shca, ib_device); | ||
779 | struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr); | ||
780 | struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd); | ||
781 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
782 | u32 tmp_lkey, tmp_rkey; | ||
783 | |||
784 | if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) { | ||
785 | ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x", | ||
786 | e_fmr, e_fmr->flags); | ||
787 | ret = -EINVAL; | ||
788 | goto map_phys_fmr_exit0; | ||
789 | } | ||
790 | ret = ehca_fmr_check_page_list(e_fmr, page_list, list_len); | ||
791 | if (ret) | ||
792 | goto map_phys_fmr_exit0; | ||
793 | if (iova % e_fmr->fmr_page_size) { | ||
794 | /* only whole-numbered pages */ | ||
795 | ehca_err(fmr->device, "bad iova, iova=%lx fmr_page_size=%x", | ||
796 | iova, e_fmr->fmr_page_size); | ||
797 | ret = -EINVAL; | ||
798 | goto map_phys_fmr_exit0; | ||
799 | } | ||
800 | if (e_fmr->fmr_map_cnt >= e_fmr->fmr_max_maps) { | ||
801 | /* HCAD does not limit the maps, however trace this anyway */ | ||
802 | ehca_info(fmr->device, "map limit exceeded, fmr=%p " | ||
803 | "e_fmr->fmr_map_cnt=%x e_fmr->fmr_max_maps=%x", | ||
804 | fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps); | ||
805 | } | ||
806 | |||
807 | pginfo.type = EHCA_MR_PGI_FMR; | ||
808 | pginfo.num_pages = list_len; | ||
809 | pginfo.num_4k = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE); | ||
810 | pginfo.page_list = page_list; | ||
811 | pginfo.next_4k = ((iova & (e_fmr->fmr_page_size-1)) / | ||
812 | EHCA_PAGESIZE); | ||
813 | |||
814 | ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova, | ||
815 | list_len * e_fmr->fmr_page_size, | ||
816 | e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey); | ||
817 | if (ret) | ||
818 | goto map_phys_fmr_exit0; | ||
819 | |||
820 | /* successful reregistration */ | ||
821 | e_fmr->fmr_map_cnt++; | ||
822 | e_fmr->ib.ib_fmr.lkey = tmp_lkey; | ||
823 | e_fmr->ib.ib_fmr.rkey = tmp_rkey; | ||
824 | return 0; | ||
825 | |||
826 | map_phys_fmr_exit0: | ||
827 | if (ret) | ||
828 | ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x " | ||
829 | "iova=%lx", | ||
830 | ret, fmr, page_list, list_len, iova); | ||
831 | return ret; | ||
832 | } /* end ehca_map_phys_fmr() */ | ||
833 | |||
834 | /*----------------------------------------------------------------------*/ | ||
835 | |||
836 | int ehca_unmap_fmr(struct list_head *fmr_list) | ||
837 | { | ||
838 | int ret = 0; | ||
839 | struct ib_fmr *ib_fmr; | ||
840 | struct ehca_shca *shca = NULL; | ||
841 | struct ehca_shca *prev_shca; | ||
842 | struct ehca_mr *e_fmr; | ||
843 | u32 num_fmr = 0; | ||
844 | u32 unmap_fmr_cnt = 0; | ||
845 | |||
846 | /* check all FMR belong to same SHCA, and check internal flag */ | ||
847 | list_for_each_entry(ib_fmr, fmr_list, list) { | ||
848 | prev_shca = shca; | ||
849 | if (!ib_fmr) { | ||
850 | ehca_gen_err("bad fmr=%p in list", ib_fmr); | ||
851 | ret = -EINVAL; | ||
852 | goto unmap_fmr_exit0; | ||
853 | } | ||
854 | shca = container_of(ib_fmr->device, struct ehca_shca, | ||
855 | ib_device); | ||
856 | e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr); | ||
857 | if ((shca != prev_shca) && prev_shca) { | ||
858 | ehca_err(&shca->ib_device, "SHCA mismatch, shca=%p " | ||
859 | "prev_shca=%p e_fmr=%p", | ||
860 | shca, prev_shca, e_fmr); | ||
861 | ret = -EINVAL; | ||
862 | goto unmap_fmr_exit0; | ||
863 | } | ||
864 | if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) { | ||
865 | ehca_err(&shca->ib_device, "not a FMR, e_fmr=%p " | ||
866 | "e_fmr->flags=%x", e_fmr, e_fmr->flags); | ||
867 | ret = -EINVAL; | ||
868 | goto unmap_fmr_exit0; | ||
869 | } | ||
870 | num_fmr++; | ||
871 | } | ||
872 | |||
873 | /* loop over all FMRs to unmap */ | ||
874 | list_for_each_entry(ib_fmr, fmr_list, list) { | ||
875 | unmap_fmr_cnt++; | ||
876 | e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr); | ||
877 | shca = container_of(ib_fmr->device, struct ehca_shca, | ||
878 | ib_device); | ||
879 | ret = ehca_unmap_one_fmr(shca, e_fmr); | ||
880 | if (ret) { | ||
881 | /* unmap failed, stop unmapping of rest of FMRs */ | ||
882 | ehca_err(&shca->ib_device, "unmap of one FMR failed, " | ||
883 | "stop rest, e_fmr=%p num_fmr=%x " | ||
884 | "unmap_fmr_cnt=%x lkey=%x", e_fmr, num_fmr, | ||
885 | unmap_fmr_cnt, e_fmr->ib.ib_fmr.lkey); | ||
886 | goto unmap_fmr_exit0; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | unmap_fmr_exit0: | ||
891 | if (ret) | ||
892 | ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x", | ||
893 | ret, fmr_list, num_fmr, unmap_fmr_cnt); | ||
894 | return ret; | ||
895 | } /* end ehca_unmap_fmr() */ | ||
896 | |||
897 | /*----------------------------------------------------------------------*/ | ||
898 | |||
899 | int ehca_dealloc_fmr(struct ib_fmr *fmr) | ||
900 | { | ||
901 | int ret; | ||
902 | u64 h_ret; | ||
903 | struct ehca_shca *shca = | ||
904 | container_of(fmr->device, struct ehca_shca, ib_device); | ||
905 | struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr); | ||
906 | |||
907 | if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) { | ||
908 | ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x", | ||
909 | e_fmr, e_fmr->flags); | ||
910 | ret = -EINVAL; | ||
911 | goto free_fmr_exit0; | ||
912 | } | ||
913 | |||
914 | h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); | ||
915 | if (h_ret != H_SUCCESS) { | ||
916 | ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p " | ||
917 | "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x", | ||
918 | h_ret, e_fmr, shca->ipz_hca_handle.handle, | ||
919 | e_fmr->ipz_mr_handle.handle, fmr->lkey); | ||
920 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | ||
921 | goto free_fmr_exit0; | ||
922 | } | ||
923 | /* successful deregistration */ | ||
924 | ehca_mr_delete(e_fmr); | ||
925 | return 0; | ||
926 | |||
927 | free_fmr_exit0: | ||
928 | if (ret) | ||
929 | ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr); | ||
930 | return ret; | ||
931 | } /* end ehca_dealloc_fmr() */ | ||
932 | |||
933 | /*----------------------------------------------------------------------*/ | ||
934 | |||
935 | int ehca_reg_mr(struct ehca_shca *shca, | ||
936 | struct ehca_mr *e_mr, | ||
937 | u64 *iova_start, | ||
938 | u64 size, | ||
939 | int acl, | ||
940 | struct ehca_pd *e_pd, | ||
941 | struct ehca_mr_pginfo *pginfo, | ||
942 | u32 *lkey, /*OUT*/ | ||
943 | u32 *rkey) /*OUT*/ | ||
944 | { | ||
945 | int ret; | ||
946 | u64 h_ret; | ||
947 | u32 hipz_acl; | ||
948 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | ||
949 | |||
950 | ehca_mrmw_map_acl(acl, &hipz_acl); | ||
951 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | ||
952 | if (ehca_use_hp_mr == 1) | ||
953 | hipz_acl |= 0x00000001; | ||
954 | |||
955 | h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr, | ||
956 | (u64)iova_start, size, hipz_acl, | ||
957 | e_pd->fw_pd, &hipzout); | ||
958 | if (h_ret != H_SUCCESS) { | ||
959 | ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx " | ||
960 | "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle); | ||
961 | ret = ehca_mrmw_map_hrc_alloc(h_ret); | ||
962 | goto ehca_reg_mr_exit0; | ||
963 | } | ||
964 | |||
965 | e_mr->ipz_mr_handle = hipzout.handle; | ||
966 | |||
967 | ret = ehca_reg_mr_rpages(shca, e_mr, pginfo); | ||
968 | if (ret) | ||
969 | goto ehca_reg_mr_exit1; | ||
970 | |||
971 | /* successful registration */ | ||
972 | e_mr->num_pages = pginfo->num_pages; | ||
973 | e_mr->num_4k = pginfo->num_4k; | ||
974 | e_mr->start = iova_start; | ||
975 | e_mr->size = size; | ||
976 | e_mr->acl = acl; | ||
977 | *lkey = hipzout.lkey; | ||
978 | *rkey = hipzout.rkey; | ||
979 | return 0; | ||
980 | |||
981 | ehca_reg_mr_exit1: | ||
982 | h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); | ||
983 | if (h_ret != H_SUCCESS) { | ||
984 | ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p " | ||
985 | "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x " | ||
986 | "pginfo=%p num_pages=%lx num_4k=%lx ret=%x", | ||
987 | h_ret, shca, e_mr, iova_start, size, acl, e_pd, | ||
988 | hipzout.lkey, pginfo, pginfo->num_pages, | ||
989 | pginfo->num_4k, ret); | ||
990 | ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, " | ||
991 | "not recoverable"); | ||
992 | } | ||
993 | ehca_reg_mr_exit0: | ||
994 | if (ret) | ||
995 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " | ||
996 | "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " | ||
997 | "num_pages=%lx num_4k=%lx", | ||
998 | ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo, | ||
999 | pginfo->num_pages, pginfo->num_4k); | ||
1000 | return ret; | ||
1001 | } /* end ehca_reg_mr() */ | ||
1002 | |||
1003 | /*----------------------------------------------------------------------*/ | ||
1004 | |||
1005 | int ehca_reg_mr_rpages(struct ehca_shca *shca, | ||
1006 | struct ehca_mr *e_mr, | ||
1007 | struct ehca_mr_pginfo *pginfo) | ||
1008 | { | ||
1009 | int ret = 0; | ||
1010 | u64 h_ret; | ||
1011 | u32 rnum; | ||
1012 | u64 rpage; | ||
1013 | u32 i; | ||
1014 | u64 *kpage; | ||
1015 | |||
1016 | kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
1017 | if (!kpage) { | ||
1018 | ehca_err(&shca->ib_device, "kpage alloc failed"); | ||
1019 | ret = -ENOMEM; | ||
1020 | goto ehca_reg_mr_rpages_exit0; | ||
1021 | } | ||
1022 | |||
1023 | /* max 512 pages per shot */ | ||
1024 | for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) { | ||
1025 | |||
1026 | if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) { | ||
1027 | rnum = pginfo->num_4k % 512; /* last shot */ | ||
1028 | if (rnum == 0) | ||
1029 | rnum = 512; /* last shot is full */ | ||
1030 | } else | ||
1031 | rnum = 512; | ||
1032 | |||
1033 | if (rnum > 1) { | ||
1034 | ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage); | ||
1035 | if (ret) { | ||
1036 | ehca_err(&shca->ib_device, "ehca_set_pagebuf " | ||
1037 | "bad rc, ret=%x rnum=%x kpage=%p", | ||
1038 | ret, rnum, kpage); | ||
1039 | ret = -EFAULT; | ||
1040 | goto ehca_reg_mr_rpages_exit1; | ||
1041 | } | ||
1042 | rpage = virt_to_abs(kpage); | ||
1043 | if (!rpage) { | ||
1044 | ehca_err(&shca->ib_device, "kpage=%p i=%x", | ||
1045 | kpage, i); | ||
1046 | ret = -EFAULT; | ||
1047 | goto ehca_reg_mr_rpages_exit1; | ||
1048 | } | ||
1049 | } else { /* rnum==1 */ | ||
1050 | ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage); | ||
1051 | if (ret) { | ||
1052 | ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 " | ||
1053 | "bad rc, ret=%x i=%x", ret, i); | ||
1054 | ret = -EFAULT; | ||
1055 | goto ehca_reg_mr_rpages_exit1; | ||
1056 | } | ||
1057 | } | ||
1058 | |||
1059 | h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr, | ||
1060 | 0, /* pagesize 4k */ | ||
1061 | 0, rpage, rnum); | ||
1062 | |||
1063 | if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) { | ||
1064 | /* | ||
1065 | * check for 'registration complete'==H_SUCCESS | ||
1066 | * and for 'page registered'==H_PAGE_REGISTERED | ||
1067 | */ | ||
1068 | if (h_ret != H_SUCCESS) { | ||
1069 | ehca_err(&shca->ib_device, "last " | ||
1070 | "hipz_reg_rpage_mr failed, h_ret=%lx " | ||
1071 | "e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx" | ||
1072 | " lkey=%x", h_ret, e_mr, i, | ||
1073 | shca->ipz_hca_handle.handle, | ||
1074 | e_mr->ipz_mr_handle.handle, | ||
1075 | e_mr->ib.ib_mr.lkey); | ||
1076 | ret = ehca_mrmw_map_hrc_rrpg_last(h_ret); | ||
1077 | break; | ||
1078 | } else | ||
1079 | ret = 0; | ||
1080 | } else if (h_ret != H_PAGE_REGISTERED) { | ||
1081 | ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, " | ||
1082 | "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx " | ||
1083 | "mr_hndl=%lx", h_ret, e_mr, i, | ||
1084 | e_mr->ib.ib_mr.lkey, | ||
1085 | shca->ipz_hca_handle.handle, | ||
1086 | e_mr->ipz_mr_handle.handle); | ||
1087 | ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret); | ||
1088 | break; | ||
1089 | } else | ||
1090 | ret = 0; | ||
1091 | } /* end for(i) */ | ||
1092 | |||
1093 | |||
1094 | ehca_reg_mr_rpages_exit1: | ||
1095 | kfree(kpage); | ||
1096 | ehca_reg_mr_rpages_exit0: | ||
1097 | if (ret) | ||
1098 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p " | ||
1099 | "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo, | ||
1100 | pginfo->num_pages, pginfo->num_4k); | ||
1101 | return ret; | ||
1102 | } /* end ehca_reg_mr_rpages() */ | ||
1103 | |||
1104 | /*----------------------------------------------------------------------*/ | ||
1105 | |||
1106 | inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, | ||
1107 | struct ehca_mr *e_mr, | ||
1108 | u64 *iova_start, | ||
1109 | u64 size, | ||
1110 | u32 acl, | ||
1111 | struct ehca_pd *e_pd, | ||
1112 | struct ehca_mr_pginfo *pginfo, | ||
1113 | u32 *lkey, /*OUT*/ | ||
1114 | u32 *rkey) /*OUT*/ | ||
1115 | { | ||
1116 | int ret; | ||
1117 | u64 h_ret; | ||
1118 | u32 hipz_acl; | ||
1119 | u64 *kpage; | ||
1120 | u64 rpage; | ||
1121 | struct ehca_mr_pginfo pginfo_save; | ||
1122 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | ||
1123 | |||
1124 | ehca_mrmw_map_acl(acl, &hipz_acl); | ||
1125 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | ||
1126 | |||
1127 | kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
1128 | if (!kpage) { | ||
1129 | ehca_err(&shca->ib_device, "kpage alloc failed"); | ||
1130 | ret = -ENOMEM; | ||
1131 | goto ehca_rereg_mr_rereg1_exit0; | ||
1132 | } | ||
1133 | |||
1134 | pginfo_save = *pginfo; | ||
1135 | ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage); | ||
1136 | if (ret) { | ||
1137 | ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p " | ||
1138 | "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p", | ||
1139 | e_mr, pginfo, pginfo->type, pginfo->num_pages, | ||
1140 | pginfo->num_4k,kpage); | ||
1141 | goto ehca_rereg_mr_rereg1_exit1; | ||
1142 | } | ||
1143 | rpage = virt_to_abs(kpage); | ||
1144 | if (!rpage) { | ||
1145 | ehca_err(&shca->ib_device, "kpage=%p", kpage); | ||
1146 | ret = -EFAULT; | ||
1147 | goto ehca_rereg_mr_rereg1_exit1; | ||
1148 | } | ||
1149 | h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_mr, | ||
1150 | (u64)iova_start, size, hipz_acl, | ||
1151 | e_pd->fw_pd, rpage, &hipzout); | ||
1152 | if (h_ret != H_SUCCESS) { | ||
1153 | /* | ||
1154 | * reregistration unsuccessful, try it again with the 3 hCalls, | ||
1155 | * e.g. this is required in case H_MR_CONDITION | ||
1156 | * (MW bound or MR is shared) | ||
1157 | */ | ||
1158 | ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed " | ||
1159 | "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr); | ||
1160 | *pginfo = pginfo_save; | ||
1161 | ret = -EAGAIN; | ||
1162 | } else if ((u64*)hipzout.vaddr != iova_start) { | ||
1163 | ehca_err(&shca->ib_device, "PHYP changed iova_start in " | ||
1164 | "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p " | ||
1165 | "mr_handle=%lx lkey=%x lkey_out=%x", iova_start, | ||
1166 | hipzout.vaddr, e_mr, e_mr->ipz_mr_handle.handle, | ||
1167 | e_mr->ib.ib_mr.lkey, hipzout.lkey); | ||
1168 | ret = -EFAULT; | ||
1169 | } else { | ||
1170 | /* | ||
1171 | * successful reregistration | ||
1172 | * note: start and start_out are identical for eServer HCAs | ||
1173 | */ | ||
1174 | e_mr->num_pages = pginfo->num_pages; | ||
1175 | e_mr->num_4k = pginfo->num_4k; | ||
1176 | e_mr->start = iova_start; | ||
1177 | e_mr->size = size; | ||
1178 | e_mr->acl = acl; | ||
1179 | *lkey = hipzout.lkey; | ||
1180 | *rkey = hipzout.rkey; | ||
1181 | } | ||
1182 | |||
1183 | ehca_rereg_mr_rereg1_exit1: | ||
1184 | kfree(kpage); | ||
1185 | ehca_rereg_mr_rereg1_exit0: | ||
1186 | if ( ret && (ret != -EAGAIN) ) | ||
1187 | ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x " | ||
1188 | "pginfo=%p num_pages=%lx num_4k=%lx", | ||
1189 | ret, *lkey, *rkey, pginfo, pginfo->num_pages, | ||
1190 | pginfo->num_4k); | ||
1191 | return ret; | ||
1192 | } /* end ehca_rereg_mr_rereg1() */ | ||
1193 | |||
1194 | /*----------------------------------------------------------------------*/ | ||
1195 | |||
1196 | int ehca_rereg_mr(struct ehca_shca *shca, | ||
1197 | struct ehca_mr *e_mr, | ||
1198 | u64 *iova_start, | ||
1199 | u64 size, | ||
1200 | int acl, | ||
1201 | struct ehca_pd *e_pd, | ||
1202 | struct ehca_mr_pginfo *pginfo, | ||
1203 | u32 *lkey, | ||
1204 | u32 *rkey) | ||
1205 | { | ||
1206 | int ret = 0; | ||
1207 | u64 h_ret; | ||
1208 | int rereg_1_hcall = 1; /* 1: use hipz_h_reregister_pmr directly */ | ||
1209 | int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */ | ||
1210 | |||
1211 | /* first determine reregistration hCall(s) */ | ||
1212 | if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) || | ||
1213 | (pginfo->num_4k > e_mr->num_4k)) { | ||
1214 | ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx " | ||
1215 | "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k); | ||
1216 | rereg_1_hcall = 0; | ||
1217 | rereg_3_hcall = 1; | ||
1218 | } | ||
1219 | |||
1220 | if (e_mr->flags & EHCA_MR_FLAG_MAXMR) { /* check for max-MR */ | ||
1221 | rereg_1_hcall = 0; | ||
1222 | rereg_3_hcall = 1; | ||
1223 | e_mr->flags &= ~EHCA_MR_FLAG_MAXMR; | ||
1224 | ehca_err(&shca->ib_device, "Rereg MR for max-MR! e_mr=%p", | ||
1225 | e_mr); | ||
1226 | } | ||
1227 | |||
1228 | if (rereg_1_hcall) { | ||
1229 | ret = ehca_rereg_mr_rereg1(shca, e_mr, iova_start, size, | ||
1230 | acl, e_pd, pginfo, lkey, rkey); | ||
1231 | if (ret) { | ||
1232 | if (ret == -EAGAIN) | ||
1233 | rereg_3_hcall = 1; | ||
1234 | else | ||
1235 | goto ehca_rereg_mr_exit0; | ||
1236 | } | ||
1237 | } | ||
1238 | |||
1239 | if (rereg_3_hcall) { | ||
1240 | struct ehca_mr save_mr; | ||
1241 | |||
1242 | /* first deregister old MR */ | ||
1243 | h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); | ||
1244 | if (h_ret != H_SUCCESS) { | ||
1245 | ehca_err(&shca->ib_device, "hipz_free_mr failed, " | ||
1246 | "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx " | ||
1247 | "mr->lkey=%x", | ||
1248 | h_ret, e_mr, shca->ipz_hca_handle.handle, | ||
1249 | e_mr->ipz_mr_handle.handle, | ||
1250 | e_mr->ib.ib_mr.lkey); | ||
1251 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | ||
1252 | goto ehca_rereg_mr_exit0; | ||
1253 | } | ||
1254 | /* clean ehca_mr_t, without changing struct ib_mr and lock */ | ||
1255 | save_mr = *e_mr; | ||
1256 | ehca_mr_deletenew(e_mr); | ||
1257 | |||
1258 | /* set some MR values */ | ||
1259 | e_mr->flags = save_mr.flags; | ||
1260 | e_mr->fmr_page_size = save_mr.fmr_page_size; | ||
1261 | e_mr->fmr_max_pages = save_mr.fmr_max_pages; | ||
1262 | e_mr->fmr_max_maps = save_mr.fmr_max_maps; | ||
1263 | e_mr->fmr_map_cnt = save_mr.fmr_map_cnt; | ||
1264 | |||
1265 | ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl, | ||
1266 | e_pd, pginfo, lkey, rkey); | ||
1267 | if (ret) { | ||
1268 | u32 offset = (u64)(&e_mr->flags) - (u64)e_mr; | ||
1269 | memcpy(&e_mr->flags, &(save_mr.flags), | ||
1270 | sizeof(struct ehca_mr) - offset); | ||
1271 | goto ehca_rereg_mr_exit0; | ||
1272 | } | ||
1273 | } | ||
1274 | |||
1275 | ehca_rereg_mr_exit0: | ||
1276 | if (ret) | ||
1277 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " | ||
1278 | "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " | ||
1279 | "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x " | ||
1280 | "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size, | ||
1281 | acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey, | ||
1282 | rereg_1_hcall, rereg_3_hcall); | ||
1283 | return ret; | ||
1284 | } /* end ehca_rereg_mr() */ | ||
1285 | |||
1286 | /*----------------------------------------------------------------------*/ | ||
1287 | |||
1288 | int ehca_unmap_one_fmr(struct ehca_shca *shca, | ||
1289 | struct ehca_mr *e_fmr) | ||
1290 | { | ||
1291 | int ret = 0; | ||
1292 | u64 h_ret; | ||
1293 | int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */ | ||
1294 | int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */ | ||
1295 | struct ehca_pd *e_pd = | ||
1296 | container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd); | ||
1297 | struct ehca_mr save_fmr; | ||
1298 | u32 tmp_lkey, tmp_rkey; | ||
1299 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
1300 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | ||
1301 | |||
1302 | /* first check if reregistration hCall can be used for unmap */ | ||
1303 | if (e_fmr->fmr_max_pages > 512) { | ||
1304 | rereg_1_hcall = 0; | ||
1305 | rereg_3_hcall = 1; | ||
1306 | } | ||
1307 | |||
1308 | if (rereg_1_hcall) { | ||
1309 | /* | ||
1310 | * note: after using rereg hcall with len=0, | ||
1311 | * rereg hcall must be used again for registering pages | ||
1312 | */ | ||
1313 | h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0, | ||
1314 | 0, 0, e_pd->fw_pd, 0, &hipzout); | ||
1315 | if (h_ret != H_SUCCESS) { | ||
1316 | /* | ||
1317 | * should not happen, because length checked above, | ||
1318 | * FMRs are not shared and no MW bound to FMRs | ||
1319 | */ | ||
1320 | ehca_err(&shca->ib_device, "hipz_reregister_pmr failed " | ||
1321 | "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx " | ||
1322 | "mr_hndl=%lx lkey=%x lkey_out=%x", | ||
1323 | h_ret, e_fmr, shca->ipz_hca_handle.handle, | ||
1324 | e_fmr->ipz_mr_handle.handle, | ||
1325 | e_fmr->ib.ib_fmr.lkey, hipzout.lkey); | ||
1326 | rereg_3_hcall = 1; | ||
1327 | } else { | ||
1328 | /* successful reregistration */ | ||
1329 | e_fmr->start = NULL; | ||
1330 | e_fmr->size = 0; | ||
1331 | tmp_lkey = hipzout.lkey; | ||
1332 | tmp_rkey = hipzout.rkey; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | if (rereg_3_hcall) { | ||
1337 | struct ehca_mr save_mr; | ||
1338 | |||
1339 | /* first free old FMR */ | ||
1340 | h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); | ||
1341 | if (h_ret != H_SUCCESS) { | ||
1342 | ehca_err(&shca->ib_device, "hipz_free_mr failed, " | ||
1343 | "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx " | ||
1344 | "lkey=%x", | ||
1345 | h_ret, e_fmr, shca->ipz_hca_handle.handle, | ||
1346 | e_fmr->ipz_mr_handle.handle, | ||
1347 | e_fmr->ib.ib_fmr.lkey); | ||
1348 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | ||
1349 | goto ehca_unmap_one_fmr_exit0; | ||
1350 | } | ||
1351 | /* clean ehca_mr_t, without changing lock */ | ||
1352 | save_fmr = *e_fmr; | ||
1353 | ehca_mr_deletenew(e_fmr); | ||
1354 | |||
1355 | /* set some MR values */ | ||
1356 | e_fmr->flags = save_fmr.flags; | ||
1357 | e_fmr->fmr_page_size = save_fmr.fmr_page_size; | ||
1358 | e_fmr->fmr_max_pages = save_fmr.fmr_max_pages; | ||
1359 | e_fmr->fmr_max_maps = save_fmr.fmr_max_maps; | ||
1360 | e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt; | ||
1361 | e_fmr->acl = save_fmr.acl; | ||
1362 | |||
1363 | pginfo.type = EHCA_MR_PGI_FMR; | ||
1364 | pginfo.num_pages = 0; | ||
1365 | pginfo.num_4k = 0; | ||
1366 | ret = ehca_reg_mr(shca, e_fmr, NULL, | ||
1367 | (e_fmr->fmr_max_pages * e_fmr->fmr_page_size), | ||
1368 | e_fmr->acl, e_pd, &pginfo, &tmp_lkey, | ||
1369 | &tmp_rkey); | ||
1370 | if (ret) { | ||
1371 | u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr; | ||
1372 | memcpy(&e_fmr->flags, &(save_mr.flags), | ||
1373 | sizeof(struct ehca_mr) - offset); | ||
1374 | goto ehca_unmap_one_fmr_exit0; | ||
1375 | } | ||
1376 | } | ||
1377 | |||
1378 | ehca_unmap_one_fmr_exit0: | ||
1379 | if (ret) | ||
1380 | ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x " | ||
1381 | "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x", | ||
1382 | ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages, | ||
1383 | rereg_1_hcall, rereg_3_hcall); | ||
1384 | return ret; | ||
1385 | } /* end ehca_unmap_one_fmr() */ | ||
1386 | |||
1387 | /*----------------------------------------------------------------------*/ | ||
1388 | |||
1389 | int ehca_reg_smr(struct ehca_shca *shca, | ||
1390 | struct ehca_mr *e_origmr, | ||
1391 | struct ehca_mr *e_newmr, | ||
1392 | u64 *iova_start, | ||
1393 | int acl, | ||
1394 | struct ehca_pd *e_pd, | ||
1395 | u32 *lkey, /*OUT*/ | ||
1396 | u32 *rkey) /*OUT*/ | ||
1397 | { | ||
1398 | int ret = 0; | ||
1399 | u64 h_ret; | ||
1400 | u32 hipz_acl; | ||
1401 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | ||
1402 | |||
1403 | ehca_mrmw_map_acl(acl, &hipz_acl); | ||
1404 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | ||
1405 | |||
1406 | h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr, | ||
1407 | (u64)iova_start, hipz_acl, e_pd->fw_pd, | ||
1408 | &hipzout); | ||
1409 | if (h_ret != H_SUCCESS) { | ||
1410 | ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx " | ||
1411 | "shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x " | ||
1412 | "e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x", | ||
1413 | h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd, | ||
1414 | shca->ipz_hca_handle.handle, | ||
1415 | e_origmr->ipz_mr_handle.handle, | ||
1416 | e_origmr->ib.ib_mr.lkey); | ||
1417 | ret = ehca_mrmw_map_hrc_reg_smr(h_ret); | ||
1418 | goto ehca_reg_smr_exit0; | ||
1419 | } | ||
1420 | /* successful registration */ | ||
1421 | e_newmr->num_pages = e_origmr->num_pages; | ||
1422 | e_newmr->num_4k = e_origmr->num_4k; | ||
1423 | e_newmr->start = iova_start; | ||
1424 | e_newmr->size = e_origmr->size; | ||
1425 | e_newmr->acl = acl; | ||
1426 | e_newmr->ipz_mr_handle = hipzout.handle; | ||
1427 | *lkey = hipzout.lkey; | ||
1428 | *rkey = hipzout.rkey; | ||
1429 | return 0; | ||
1430 | |||
1431 | ehca_reg_smr_exit0: | ||
1432 | if (ret) | ||
1433 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p " | ||
1434 | "e_newmr=%p iova_start=%p acl=%x e_pd=%p", | ||
1435 | ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd); | ||
1436 | return ret; | ||
1437 | } /* end ehca_reg_smr() */ | ||
1438 | |||
1439 | /*----------------------------------------------------------------------*/ | ||
1440 | |||
1441 | /* register internal max-MR to internal SHCA */ | ||
1442 | int ehca_reg_internal_maxmr( | ||
1443 | struct ehca_shca *shca, | ||
1444 | struct ehca_pd *e_pd, | ||
1445 | struct ehca_mr **e_maxmr) /*OUT*/ | ||
1446 | { | ||
1447 | int ret; | ||
1448 | struct ehca_mr *e_mr; | ||
1449 | u64 *iova_start; | ||
1450 | u64 size_maxmr; | ||
1451 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
1452 | struct ib_phys_buf ib_pbuf; | ||
1453 | u32 num_pages_mr; | ||
1454 | u32 num_pages_4k; /* 4k portion "pages" */ | ||
1455 | |||
1456 | e_mr = ehca_mr_new(); | ||
1457 | if (!e_mr) { | ||
1458 | ehca_err(&shca->ib_device, "out of memory"); | ||
1459 | ret = -ENOMEM; | ||
1460 | goto ehca_reg_internal_maxmr_exit0; | ||
1461 | } | ||
1462 | e_mr->flags |= EHCA_MR_FLAG_MAXMR; | ||
1463 | |||
1464 | /* register internal max-MR on HCA */ | ||
1465 | size_maxmr = (u64)high_memory - PAGE_OFFSET; | ||
1466 | iova_start = (u64*)KERNELBASE; | ||
1467 | ib_pbuf.addr = 0; | ||
1468 | ib_pbuf.size = size_maxmr; | ||
1469 | num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr + | ||
1470 | PAGE_SIZE - 1) / PAGE_SIZE); | ||
1471 | num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr + | ||
1472 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | ||
1473 | |||
1474 | pginfo.type = EHCA_MR_PGI_PHYS; | ||
1475 | pginfo.num_pages = num_pages_mr; | ||
1476 | pginfo.num_4k = num_pages_4k; | ||
1477 | pginfo.num_phys_buf = 1; | ||
1478 | pginfo.phys_buf_array = &ib_pbuf; | ||
1479 | |||
1480 | ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd, | ||
1481 | &pginfo, &e_mr->ib.ib_mr.lkey, | ||
1482 | &e_mr->ib.ib_mr.rkey); | ||
1483 | if (ret) { | ||
1484 | ehca_err(&shca->ib_device, "reg of internal max MR failed, " | ||
1485 | "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x " | ||
1486 | "num_pages_4k=%x", e_mr, iova_start, size_maxmr, | ||
1487 | num_pages_mr, num_pages_4k); | ||
1488 | goto ehca_reg_internal_maxmr_exit1; | ||
1489 | } | ||
1490 | |||
1491 | /* successful registration of all pages */ | ||
1492 | e_mr->ib.ib_mr.device = e_pd->ib_pd.device; | ||
1493 | e_mr->ib.ib_mr.pd = &e_pd->ib_pd; | ||
1494 | e_mr->ib.ib_mr.uobject = NULL; | ||
1495 | atomic_inc(&(e_pd->ib_pd.usecnt)); | ||
1496 | atomic_set(&(e_mr->ib.ib_mr.usecnt), 0); | ||
1497 | *e_maxmr = e_mr; | ||
1498 | return 0; | ||
1499 | |||
1500 | ehca_reg_internal_maxmr_exit1: | ||
1501 | ehca_mr_delete(e_mr); | ||
1502 | ehca_reg_internal_maxmr_exit0: | ||
1503 | if (ret) | ||
1504 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p", | ||
1505 | ret, shca, e_pd, e_maxmr); | ||
1506 | return ret; | ||
1507 | } /* end ehca_reg_internal_maxmr() */ | ||
1508 | |||
1509 | /*----------------------------------------------------------------------*/ | ||
1510 | |||
1511 | int ehca_reg_maxmr(struct ehca_shca *shca, | ||
1512 | struct ehca_mr *e_newmr, | ||
1513 | u64 *iova_start, | ||
1514 | int acl, | ||
1515 | struct ehca_pd *e_pd, | ||
1516 | u32 *lkey, | ||
1517 | u32 *rkey) | ||
1518 | { | ||
1519 | u64 h_ret; | ||
1520 | struct ehca_mr *e_origmr = shca->maxmr; | ||
1521 | u32 hipz_acl; | ||
1522 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | ||
1523 | |||
1524 | ehca_mrmw_map_acl(acl, &hipz_acl); | ||
1525 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | ||
1526 | |||
1527 | h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr, | ||
1528 | (u64)iova_start, hipz_acl, e_pd->fw_pd, | ||
1529 | &hipzout); | ||
1530 | if (h_ret != H_SUCCESS) { | ||
1531 | ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx " | ||
1532 | "e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x", | ||
1533 | h_ret, e_origmr, shca->ipz_hca_handle.handle, | ||
1534 | e_origmr->ipz_mr_handle.handle, | ||
1535 | e_origmr->ib.ib_mr.lkey); | ||
1536 | return ehca_mrmw_map_hrc_reg_smr(h_ret); | ||
1537 | } | ||
1538 | /* successful registration */ | ||
1539 | e_newmr->num_pages = e_origmr->num_pages; | ||
1540 | e_newmr->num_4k = e_origmr->num_4k; | ||
1541 | e_newmr->start = iova_start; | ||
1542 | e_newmr->size = e_origmr->size; | ||
1543 | e_newmr->acl = acl; | ||
1544 | e_newmr->ipz_mr_handle = hipzout.handle; | ||
1545 | *lkey = hipzout.lkey; | ||
1546 | *rkey = hipzout.rkey; | ||
1547 | return 0; | ||
1548 | } /* end ehca_reg_maxmr() */ | ||
1549 | |||
1550 | /*----------------------------------------------------------------------*/ | ||
1551 | |||
1552 | int ehca_dereg_internal_maxmr(struct ehca_shca *shca) | ||
1553 | { | ||
1554 | int ret; | ||
1555 | struct ehca_mr *e_maxmr; | ||
1556 | struct ib_pd *ib_pd; | ||
1557 | |||
1558 | if (!shca->maxmr) { | ||
1559 | ehca_err(&shca->ib_device, "bad call, shca=%p", shca); | ||
1560 | ret = -EINVAL; | ||
1561 | goto ehca_dereg_internal_maxmr_exit0; | ||
1562 | } | ||
1563 | |||
1564 | e_maxmr = shca->maxmr; | ||
1565 | ib_pd = e_maxmr->ib.ib_mr.pd; | ||
1566 | shca->maxmr = NULL; /* remove internal max-MR indication from SHCA */ | ||
1567 | |||
1568 | ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr); | ||
1569 | if (ret) { | ||
1570 | ehca_err(&shca->ib_device, "dereg internal max-MR failed, " | ||
1571 | "ret=%x e_maxmr=%p shca=%p lkey=%x", | ||
1572 | ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey); | ||
1573 | shca->maxmr = e_maxmr; | ||
1574 | goto ehca_dereg_internal_maxmr_exit0; | ||
1575 | } | ||
1576 | |||
1577 | atomic_dec(&ib_pd->usecnt); | ||
1578 | |||
1579 | ehca_dereg_internal_maxmr_exit0: | ||
1580 | if (ret) | ||
1581 | ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p", | ||
1582 | ret, shca, shca->maxmr); | ||
1583 | return ret; | ||
1584 | } /* end ehca_dereg_internal_maxmr() */ | ||
1585 | |||
1586 | /*----------------------------------------------------------------------*/ | ||
1587 | |||
1588 | /* | ||
1589 | * check physical buffer array of MR verbs for validness and | ||
1590 | * calculates MR size | ||
1591 | */ | ||
1592 | int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array, | ||
1593 | int num_phys_buf, | ||
1594 | u64 *iova_start, | ||
1595 | u64 *size) | ||
1596 | { | ||
1597 | struct ib_phys_buf *pbuf = phys_buf_array; | ||
1598 | u64 size_count = 0; | ||
1599 | u32 i; | ||
1600 | |||
1601 | if (num_phys_buf == 0) { | ||
1602 | ehca_gen_err("bad phys buf array len, num_phys_buf=0"); | ||
1603 | return -EINVAL; | ||
1604 | } | ||
1605 | /* check first buffer */ | ||
1606 | if (((u64)iova_start & ~PAGE_MASK) != (pbuf->addr & ~PAGE_MASK)) { | ||
1607 | ehca_gen_err("iova_start/addr mismatch, iova_start=%p " | ||
1608 | "pbuf->addr=%lx pbuf->size=%lx", | ||
1609 | iova_start, pbuf->addr, pbuf->size); | ||
1610 | return -EINVAL; | ||
1611 | } | ||
1612 | if (((pbuf->addr + pbuf->size) % PAGE_SIZE) && | ||
1613 | (num_phys_buf > 1)) { | ||
1614 | ehca_gen_err("addr/size mismatch in 1st buf, pbuf->addr=%lx " | ||
1615 | "pbuf->size=%lx", pbuf->addr, pbuf->size); | ||
1616 | return -EINVAL; | ||
1617 | } | ||
1618 | |||
1619 | for (i = 0; i < num_phys_buf; i++) { | ||
1620 | if ((i > 0) && (pbuf->addr % PAGE_SIZE)) { | ||
1621 | ehca_gen_err("bad address, i=%x pbuf->addr=%lx " | ||
1622 | "pbuf->size=%lx", | ||
1623 | i, pbuf->addr, pbuf->size); | ||
1624 | return -EINVAL; | ||
1625 | } | ||
1626 | if (((i > 0) && /* not 1st */ | ||
1627 | (i < (num_phys_buf - 1)) && /* not last */ | ||
1628 | (pbuf->size % PAGE_SIZE)) || (pbuf->size == 0)) { | ||
1629 | ehca_gen_err("bad size, i=%x pbuf->size=%lx", | ||
1630 | i, pbuf->size); | ||
1631 | return -EINVAL; | ||
1632 | } | ||
1633 | size_count += pbuf->size; | ||
1634 | pbuf++; | ||
1635 | } | ||
1636 | |||
1637 | *size = size_count; | ||
1638 | return 0; | ||
1639 | } /* end ehca_mr_chk_buf_and_calc_size() */ | ||
1640 | |||
1641 | /*----------------------------------------------------------------------*/ | ||
1642 | |||
1643 | /* check page list of map FMR verb for validness */ | ||
1644 | int ehca_fmr_check_page_list(struct ehca_mr *e_fmr, | ||
1645 | u64 *page_list, | ||
1646 | int list_len) | ||
1647 | { | ||
1648 | u32 i; | ||
1649 | u64 *page; | ||
1650 | |||
1651 | if ((list_len == 0) || (list_len > e_fmr->fmr_max_pages)) { | ||
1652 | ehca_gen_err("bad list_len, list_len=%x " | ||
1653 | "e_fmr->fmr_max_pages=%x fmr=%p", | ||
1654 | list_len, e_fmr->fmr_max_pages, e_fmr); | ||
1655 | return -EINVAL; | ||
1656 | } | ||
1657 | |||
1658 | /* each page must be aligned */ | ||
1659 | page = page_list; | ||
1660 | for (i = 0; i < list_len; i++) { | ||
1661 | if (*page % e_fmr->fmr_page_size) { | ||
1662 | ehca_gen_err("bad page, i=%x *page=%lx page=%p fmr=%p " | ||
1663 | "fmr_page_size=%x", i, *page, page, e_fmr, | ||
1664 | e_fmr->fmr_page_size); | ||
1665 | return -EINVAL; | ||
1666 | } | ||
1667 | page++; | ||
1668 | } | ||
1669 | |||
1670 | return 0; | ||
1671 | } /* end ehca_fmr_check_page_list() */ | ||
1672 | |||
1673 | /*----------------------------------------------------------------------*/ | ||
1674 | |||
1675 | /* setup page buffer from page info */ | ||
1676 | int ehca_set_pagebuf(struct ehca_mr *e_mr, | ||
1677 | struct ehca_mr_pginfo *pginfo, | ||
1678 | u32 number, | ||
1679 | u64 *kpage) | ||
1680 | { | ||
1681 | int ret = 0; | ||
1682 | struct ib_umem_chunk *prev_chunk; | ||
1683 | struct ib_umem_chunk *chunk; | ||
1684 | struct ib_phys_buf *pbuf; | ||
1685 | u64 *fmrlist; | ||
1686 | u64 num4k, pgaddr, offs4k; | ||
1687 | u32 i = 0; | ||
1688 | u32 j = 0; | ||
1689 | |||
1690 | if (pginfo->type == EHCA_MR_PGI_PHYS) { | ||
1691 | /* loop over desired phys_buf_array entries */ | ||
1692 | while (i < number) { | ||
1693 | pbuf = pginfo->phys_buf_array + pginfo->next_buf; | ||
1694 | num4k = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size + | ||
1695 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE; | ||
1696 | offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE; | ||
1697 | while (pginfo->next_4k < offs4k + num4k) { | ||
1698 | /* sanity check */ | ||
1699 | if ((pginfo->page_cnt >= pginfo->num_pages) || | ||
1700 | (pginfo->page_4k_cnt >= pginfo->num_4k)) { | ||
1701 | ehca_gen_err("page_cnt >= num_pages, " | ||
1702 | "page_cnt=%lx " | ||
1703 | "num_pages=%lx " | ||
1704 | "page_4k_cnt=%lx " | ||
1705 | "num_4k=%lx i=%x", | ||
1706 | pginfo->page_cnt, | ||
1707 | pginfo->num_pages, | ||
1708 | pginfo->page_4k_cnt, | ||
1709 | pginfo->num_4k, i); | ||
1710 | ret = -EFAULT; | ||
1711 | goto ehca_set_pagebuf_exit0; | ||
1712 | } | ||
1713 | *kpage = phys_to_abs( | ||
1714 | (pbuf->addr & EHCA_PAGEMASK) | ||
1715 | + (pginfo->next_4k * EHCA_PAGESIZE)); | ||
1716 | if ( !(*kpage) && pbuf->addr ) { | ||
1717 | ehca_gen_err("pbuf->addr=%lx " | ||
1718 | "pbuf->size=%lx " | ||
1719 | "next_4k=%lx", pbuf->addr, | ||
1720 | pbuf->size, | ||
1721 | pginfo->next_4k); | ||
1722 | ret = -EFAULT; | ||
1723 | goto ehca_set_pagebuf_exit0; | ||
1724 | } | ||
1725 | (pginfo->page_4k_cnt)++; | ||
1726 | (pginfo->next_4k)++; | ||
1727 | if (pginfo->next_4k % | ||
1728 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) | ||
1729 | (pginfo->page_cnt)++; | ||
1730 | kpage++; | ||
1731 | i++; | ||
1732 | if (i >= number) break; | ||
1733 | } | ||
1734 | if (pginfo->next_4k >= offs4k + num4k) { | ||
1735 | (pginfo->next_buf)++; | ||
1736 | pginfo->next_4k = 0; | ||
1737 | } | ||
1738 | } | ||
1739 | } else if (pginfo->type == EHCA_MR_PGI_USER) { | ||
1740 | /* loop over desired chunk entries */ | ||
1741 | chunk = pginfo->next_chunk; | ||
1742 | prev_chunk = pginfo->next_chunk; | ||
1743 | list_for_each_entry_continue(chunk, | ||
1744 | (&(pginfo->region->chunk_list)), | ||
1745 | list) { | ||
1746 | for (i = pginfo->next_nmap; i < chunk->nmap; ) { | ||
1747 | pgaddr = ( page_to_pfn(chunk->page_list[i].page) | ||
1748 | << PAGE_SHIFT ); | ||
1749 | *kpage = phys_to_abs(pgaddr + | ||
1750 | (pginfo->next_4k * | ||
1751 | EHCA_PAGESIZE)); | ||
1752 | if ( !(*kpage) ) { | ||
1753 | ehca_gen_err("pgaddr=%lx " | ||
1754 | "chunk->page_list[i]=%lx " | ||
1755 | "i=%x next_4k=%lx mr=%p", | ||
1756 | pgaddr, | ||
1757 | (u64)sg_dma_address( | ||
1758 | &chunk-> | ||
1759 | page_list[i]), | ||
1760 | i, pginfo->next_4k, e_mr); | ||
1761 | ret = -EFAULT; | ||
1762 | goto ehca_set_pagebuf_exit0; | ||
1763 | } | ||
1764 | (pginfo->page_4k_cnt)++; | ||
1765 | (pginfo->next_4k)++; | ||
1766 | kpage++; | ||
1767 | if (pginfo->next_4k % | ||
1768 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) { | ||
1769 | (pginfo->page_cnt)++; | ||
1770 | (pginfo->next_nmap)++; | ||
1771 | pginfo->next_4k = 0; | ||
1772 | i++; | ||
1773 | } | ||
1774 | j++; | ||
1775 | if (j >= number) break; | ||
1776 | } | ||
1777 | if ((pginfo->next_nmap >= chunk->nmap) && | ||
1778 | (j >= number)) { | ||
1779 | pginfo->next_nmap = 0; | ||
1780 | prev_chunk = chunk; | ||
1781 | break; | ||
1782 | } else if (pginfo->next_nmap >= chunk->nmap) { | ||
1783 | pginfo->next_nmap = 0; | ||
1784 | prev_chunk = chunk; | ||
1785 | } else if (j >= number) | ||
1786 | break; | ||
1787 | else | ||
1788 | prev_chunk = chunk; | ||
1789 | } | ||
1790 | pginfo->next_chunk = | ||
1791 | list_prepare_entry(prev_chunk, | ||
1792 | (&(pginfo->region->chunk_list)), | ||
1793 | list); | ||
1794 | } else if (pginfo->type == EHCA_MR_PGI_FMR) { | ||
1795 | /* loop over desired page_list entries */ | ||
1796 | fmrlist = pginfo->page_list + pginfo->next_listelem; | ||
1797 | for (i = 0; i < number; i++) { | ||
1798 | *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) + | ||
1799 | pginfo->next_4k * EHCA_PAGESIZE); | ||
1800 | if ( !(*kpage) ) { | ||
1801 | ehca_gen_err("*fmrlist=%lx fmrlist=%p " | ||
1802 | "next_listelem=%lx next_4k=%lx", | ||
1803 | *fmrlist, fmrlist, | ||
1804 | pginfo->next_listelem, | ||
1805 | pginfo->next_4k); | ||
1806 | ret = -EFAULT; | ||
1807 | goto ehca_set_pagebuf_exit0; | ||
1808 | } | ||
1809 | (pginfo->page_4k_cnt)++; | ||
1810 | (pginfo->next_4k)++; | ||
1811 | kpage++; | ||
1812 | if (pginfo->next_4k % | ||
1813 | (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) { | ||
1814 | (pginfo->page_cnt)++; | ||
1815 | (pginfo->next_listelem)++; | ||
1816 | fmrlist++; | ||
1817 | pginfo->next_4k = 0; | ||
1818 | } | ||
1819 | } | ||
1820 | } else { | ||
1821 | ehca_gen_err("bad pginfo->type=%x", pginfo->type); | ||
1822 | ret = -EFAULT; | ||
1823 | goto ehca_set_pagebuf_exit0; | ||
1824 | } | ||
1825 | |||
1826 | ehca_set_pagebuf_exit0: | ||
1827 | if (ret) | ||
1828 | ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx " | ||
1829 | "num_4k=%lx next_buf=%lx next_4k=%lx number=%x " | ||
1830 | "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x " | ||
1831 | "next_listelem=%lx region=%p next_chunk=%p " | ||
1832 | "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type, | ||
1833 | pginfo->num_pages, pginfo->num_4k, | ||
1834 | pginfo->next_buf, pginfo->next_4k, number, kpage, | ||
1835 | pginfo->page_cnt, pginfo->page_4k_cnt, i, | ||
1836 | pginfo->next_listelem, pginfo->region, | ||
1837 | pginfo->next_chunk, pginfo->next_nmap); | ||
1838 | return ret; | ||
1839 | } /* end ehca_set_pagebuf() */ | ||
1840 | |||
1841 | /*----------------------------------------------------------------------*/ | ||
1842 | |||
1843 | /* setup 1 page from page info page buffer */ | ||
1844 | int ehca_set_pagebuf_1(struct ehca_mr *e_mr, | ||
1845 | struct ehca_mr_pginfo *pginfo, | ||
1846 | u64 *rpage) | ||
1847 | { | ||
1848 | int ret = 0; | ||
1849 | struct ib_phys_buf *tmp_pbuf; | ||
1850 | u64 *fmrlist; | ||
1851 | struct ib_umem_chunk *chunk; | ||
1852 | struct ib_umem_chunk *prev_chunk; | ||
1853 | u64 pgaddr, num4k, offs4k; | ||
1854 | |||
1855 | if (pginfo->type == EHCA_MR_PGI_PHYS) { | ||
1856 | /* sanity check */ | ||
1857 | if ((pginfo->page_cnt >= pginfo->num_pages) || | ||
1858 | (pginfo->page_4k_cnt >= pginfo->num_4k)) { | ||
1859 | ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx " | ||
1860 | "num_pages=%lx page_4k_cnt=%lx num_4k=%lx", | ||
1861 | pginfo->page_cnt, pginfo->num_pages, | ||
1862 | pginfo->page_4k_cnt, pginfo->num_4k); | ||
1863 | ret = -EFAULT; | ||
1864 | goto ehca_set_pagebuf_1_exit0; | ||
1865 | } | ||
1866 | tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf; | ||
1867 | num4k = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size + | ||
1868 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE; | ||
1869 | offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE; | ||
1870 | *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) + | ||
1871 | (pginfo->next_4k * EHCA_PAGESIZE)); | ||
1872 | if ( !(*rpage) && tmp_pbuf->addr ) { | ||
1873 | ehca_gen_err("tmp_pbuf->addr=%lx" | ||
1874 | " tmp_pbuf->size=%lx next_4k=%lx", | ||
1875 | tmp_pbuf->addr, tmp_pbuf->size, | ||
1876 | pginfo->next_4k); | ||
1877 | ret = -EFAULT; | ||
1878 | goto ehca_set_pagebuf_1_exit0; | ||
1879 | } | ||
1880 | (pginfo->page_4k_cnt)++; | ||
1881 | (pginfo->next_4k)++; | ||
1882 | if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0) | ||
1883 | (pginfo->page_cnt)++; | ||
1884 | if (pginfo->next_4k >= offs4k + num4k) { | ||
1885 | (pginfo->next_buf)++; | ||
1886 | pginfo->next_4k = 0; | ||
1887 | } | ||
1888 | } else if (pginfo->type == EHCA_MR_PGI_USER) { | ||
1889 | chunk = pginfo->next_chunk; | ||
1890 | prev_chunk = pginfo->next_chunk; | ||
1891 | list_for_each_entry_continue(chunk, | ||
1892 | (&(pginfo->region->chunk_list)), | ||
1893 | list) { | ||
1894 | pgaddr = ( page_to_pfn(chunk->page_list[ | ||
1895 | pginfo->next_nmap].page) | ||
1896 | << PAGE_SHIFT); | ||
1897 | *rpage = phys_to_abs(pgaddr + | ||
1898 | (pginfo->next_4k * EHCA_PAGESIZE)); | ||
1899 | if ( !(*rpage) ) { | ||
1900 | ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx" | ||
1901 | " next_nmap=%lx next_4k=%lx mr=%p", | ||
1902 | pgaddr, (u64)sg_dma_address( | ||
1903 | &chunk->page_list[ | ||
1904 | pginfo-> | ||
1905 | next_nmap]), | ||
1906 | pginfo->next_nmap, pginfo->next_4k, | ||
1907 | e_mr); | ||
1908 | ret = -EFAULT; | ||
1909 | goto ehca_set_pagebuf_1_exit0; | ||
1910 | } | ||
1911 | (pginfo->page_4k_cnt)++; | ||
1912 | (pginfo->next_4k)++; | ||
1913 | if (pginfo->next_4k % | ||
1914 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) { | ||
1915 | (pginfo->page_cnt)++; | ||
1916 | (pginfo->next_nmap)++; | ||
1917 | pginfo->next_4k = 0; | ||
1918 | } | ||
1919 | if (pginfo->next_nmap >= chunk->nmap) { | ||
1920 | pginfo->next_nmap = 0; | ||
1921 | prev_chunk = chunk; | ||
1922 | } | ||
1923 | break; | ||
1924 | } | ||
1925 | pginfo->next_chunk = | ||
1926 | list_prepare_entry(prev_chunk, | ||
1927 | (&(pginfo->region->chunk_list)), | ||
1928 | list); | ||
1929 | } else if (pginfo->type == EHCA_MR_PGI_FMR) { | ||
1930 | fmrlist = pginfo->page_list + pginfo->next_listelem; | ||
1931 | *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) + | ||
1932 | pginfo->next_4k * EHCA_PAGESIZE); | ||
1933 | if ( !(*rpage) ) { | ||
1934 | ehca_gen_err("*fmrlist=%lx fmrlist=%p " | ||
1935 | "next_listelem=%lx next_4k=%lx", | ||
1936 | *fmrlist, fmrlist, pginfo->next_listelem, | ||
1937 | pginfo->next_4k); | ||
1938 | ret = -EFAULT; | ||
1939 | goto ehca_set_pagebuf_1_exit0; | ||
1940 | } | ||
1941 | (pginfo->page_4k_cnt)++; | ||
1942 | (pginfo->next_4k)++; | ||
1943 | if (pginfo->next_4k % | ||
1944 | (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) { | ||
1945 | (pginfo->page_cnt)++; | ||
1946 | (pginfo->next_listelem)++; | ||
1947 | pginfo->next_4k = 0; | ||
1948 | } | ||
1949 | } else { | ||
1950 | ehca_gen_err("bad pginfo->type=%x", pginfo->type); | ||
1951 | ret = -EFAULT; | ||
1952 | goto ehca_set_pagebuf_1_exit0; | ||
1953 | } | ||
1954 | |||
1955 | ehca_set_pagebuf_1_exit0: | ||
1956 | if (ret) | ||
1957 | ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx " | ||
1958 | "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p " | ||
1959 | "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx " | ||
1960 | "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr, | ||
1961 | pginfo, pginfo->type, pginfo->num_pages, | ||
1962 | pginfo->num_4k, pginfo->next_buf, pginfo->next_4k, | ||
1963 | rpage, pginfo->page_cnt, pginfo->page_4k_cnt, | ||
1964 | pginfo->next_listelem, pginfo->region, | ||
1965 | pginfo->next_chunk, pginfo->next_nmap); | ||
1966 | return ret; | ||
1967 | } /* end ehca_set_pagebuf_1() */ | ||
1968 | |||
1969 | /*----------------------------------------------------------------------*/ | ||
1970 | |||
1971 | /* | ||
1972 | * check MR if it is a max-MR, i.e. uses whole memory | ||
1973 | * in case it's a max-MR 1 is returned, else 0 | ||
1974 | */ | ||
1975 | int ehca_mr_is_maxmr(u64 size, | ||
1976 | u64 *iova_start) | ||
1977 | { | ||
1978 | /* a MR is treated as max-MR only if it fits following: */ | ||
1979 | if ((size == ((u64)high_memory - PAGE_OFFSET)) && | ||
1980 | (iova_start == (void*)KERNELBASE)) { | ||
1981 | ehca_gen_dbg("this is a max-MR"); | ||
1982 | return 1; | ||
1983 | } else | ||
1984 | return 0; | ||
1985 | } /* end ehca_mr_is_maxmr() */ | ||
1986 | |||
1987 | /*----------------------------------------------------------------------*/ | ||
1988 | |||
1989 | /* map access control for MR/MW. This routine is used for MR and MW. */ | ||
1990 | void ehca_mrmw_map_acl(int ib_acl, | ||
1991 | u32 *hipz_acl) | ||
1992 | { | ||
1993 | *hipz_acl = 0; | ||
1994 | if (ib_acl & IB_ACCESS_REMOTE_READ) | ||
1995 | *hipz_acl |= HIPZ_ACCESSCTRL_R_READ; | ||
1996 | if (ib_acl & IB_ACCESS_REMOTE_WRITE) | ||
1997 | *hipz_acl |= HIPZ_ACCESSCTRL_R_WRITE; | ||
1998 | if (ib_acl & IB_ACCESS_REMOTE_ATOMIC) | ||
1999 | *hipz_acl |= HIPZ_ACCESSCTRL_R_ATOMIC; | ||
2000 | if (ib_acl & IB_ACCESS_LOCAL_WRITE) | ||
2001 | *hipz_acl |= HIPZ_ACCESSCTRL_L_WRITE; | ||
2002 | if (ib_acl & IB_ACCESS_MW_BIND) | ||
2003 | *hipz_acl |= HIPZ_ACCESSCTRL_MW_BIND; | ||
2004 | } /* end ehca_mrmw_map_acl() */ | ||
2005 | |||
2006 | /*----------------------------------------------------------------------*/ | ||
2007 | |||
2008 | /* sets page size in hipz access control for MR/MW. */ | ||
2009 | void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl) /*INOUT*/ | ||
2010 | { | ||
2011 | return; /* HCA supports only 4k */ | ||
2012 | } /* end ehca_mrmw_set_pgsize_hipz_acl() */ | ||
2013 | |||
2014 | /*----------------------------------------------------------------------*/ | ||
2015 | |||
2016 | /* | ||
2017 | * reverse map access control for MR/MW. | ||
2018 | * This routine is used for MR and MW. | ||
2019 | */ | ||
2020 | void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl, | ||
2021 | int *ib_acl) /*OUT*/ | ||
2022 | { | ||
2023 | *ib_acl = 0; | ||
2024 | if (*hipz_acl & HIPZ_ACCESSCTRL_R_READ) | ||
2025 | *ib_acl |= IB_ACCESS_REMOTE_READ; | ||
2026 | if (*hipz_acl & HIPZ_ACCESSCTRL_R_WRITE) | ||
2027 | *ib_acl |= IB_ACCESS_REMOTE_WRITE; | ||
2028 | if (*hipz_acl & HIPZ_ACCESSCTRL_R_ATOMIC) | ||
2029 | *ib_acl |= IB_ACCESS_REMOTE_ATOMIC; | ||
2030 | if (*hipz_acl & HIPZ_ACCESSCTRL_L_WRITE) | ||
2031 | *ib_acl |= IB_ACCESS_LOCAL_WRITE; | ||
2032 | if (*hipz_acl & HIPZ_ACCESSCTRL_MW_BIND) | ||
2033 | *ib_acl |= IB_ACCESS_MW_BIND; | ||
2034 | } /* end ehca_mrmw_reverse_map_acl() */ | ||
2035 | |||
2036 | |||
2037 | /*----------------------------------------------------------------------*/ | ||
2038 | |||
2039 | /* | ||
2040 | * map HIPZ rc to IB retcodes for MR/MW allocations | ||
2041 | * Used for hipz_mr_reg_alloc and hipz_mw_alloc. | ||
2042 | */ | ||
2043 | int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc) | ||
2044 | { | ||
2045 | switch (hipz_rc) { | ||
2046 | case H_SUCCESS: /* successful completion */ | ||
2047 | return 0; | ||
2048 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2049 | case H_RT_PARM: /* invalid resource type */ | ||
2050 | case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */ | ||
2051 | case H_MLENGTH_PARM: /* invalid memory length */ | ||
2052 | case H_MEM_ACCESS_PARM: /* invalid access controls */ | ||
2053 | case H_CONSTRAINED: /* resource constraint */ | ||
2054 | return -EINVAL; | ||
2055 | case H_BUSY: /* long busy */ | ||
2056 | return -EBUSY; | ||
2057 | default: | ||
2058 | return -EINVAL; | ||
2059 | } | ||
2060 | } /* end ehca_mrmw_map_hrc_alloc() */ | ||
2061 | |||
2062 | /*----------------------------------------------------------------------*/ | ||
2063 | |||
2064 | /* | ||
2065 | * map HIPZ rc to IB retcodes for MR register rpage | ||
2066 | * Used for hipz_h_register_rpage_mr at registering last page | ||
2067 | */ | ||
2068 | int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc) | ||
2069 | { | ||
2070 | switch (hipz_rc) { | ||
2071 | case H_SUCCESS: /* registration complete */ | ||
2072 | return 0; | ||
2073 | case H_PAGE_REGISTERED: /* page registered */ | ||
2074 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2075 | case H_RH_PARM: /* invalid resource handle */ | ||
2076 | /* case H_QT_PARM: invalid queue type */ | ||
2077 | case H_PARAMETER: /* | ||
2078 | * invalid logical address, | ||
2079 | * or count zero or greater 512 | ||
2080 | */ | ||
2081 | case H_TABLE_FULL: /* page table full */ | ||
2082 | case H_HARDWARE: /* HCA not operational */ | ||
2083 | return -EINVAL; | ||
2084 | case H_BUSY: /* long busy */ | ||
2085 | return -EBUSY; | ||
2086 | default: | ||
2087 | return -EINVAL; | ||
2088 | } | ||
2089 | } /* end ehca_mrmw_map_hrc_rrpg_last() */ | ||
2090 | |||
2091 | /*----------------------------------------------------------------------*/ | ||
2092 | |||
2093 | /* | ||
2094 | * map HIPZ rc to IB retcodes for MR register rpage | ||
2095 | * Used for hipz_h_register_rpage_mr at registering one page, but not last page | ||
2096 | */ | ||
2097 | int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc) | ||
2098 | { | ||
2099 | switch (hipz_rc) { | ||
2100 | case H_PAGE_REGISTERED: /* page registered */ | ||
2101 | return 0; | ||
2102 | case H_SUCCESS: /* registration complete */ | ||
2103 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2104 | case H_RH_PARM: /* invalid resource handle */ | ||
2105 | /* case H_QT_PARM: invalid queue type */ | ||
2106 | case H_PARAMETER: /* | ||
2107 | * invalid logical address, | ||
2108 | * or count zero or greater 512 | ||
2109 | */ | ||
2110 | case H_TABLE_FULL: /* page table full */ | ||
2111 | case H_HARDWARE: /* HCA not operational */ | ||
2112 | return -EINVAL; | ||
2113 | case H_BUSY: /* long busy */ | ||
2114 | return -EBUSY; | ||
2115 | default: | ||
2116 | return -EINVAL; | ||
2117 | } | ||
2118 | } /* end ehca_mrmw_map_hrc_rrpg_notlast() */ | ||
2119 | |||
2120 | /*----------------------------------------------------------------------*/ | ||
2121 | |||
2122 | /* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */ | ||
2123 | int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc) | ||
2124 | { | ||
2125 | switch (hipz_rc) { | ||
2126 | case H_SUCCESS: /* successful completion */ | ||
2127 | return 0; | ||
2128 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2129 | case H_RH_PARM: /* invalid resource handle */ | ||
2130 | return -EINVAL; | ||
2131 | case H_BUSY: /* long busy */ | ||
2132 | return -EBUSY; | ||
2133 | default: | ||
2134 | return -EINVAL; | ||
2135 | } | ||
2136 | } /* end ehca_mrmw_map_hrc_query_mr() */ | ||
2137 | |||
2138 | /*----------------------------------------------------------------------*/ | ||
2139 | /*----------------------------------------------------------------------*/ | ||
2140 | |||
2141 | /* | ||
2142 | * map HIPZ rc to IB retcodes for freeing MR resource | ||
2143 | * Used for hipz_h_free_resource_mr | ||
2144 | */ | ||
2145 | int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc) | ||
2146 | { | ||
2147 | switch (hipz_rc) { | ||
2148 | case H_SUCCESS: /* resource freed */ | ||
2149 | return 0; | ||
2150 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2151 | case H_RH_PARM: /* invalid resource handle */ | ||
2152 | case H_R_STATE: /* invalid resource state */ | ||
2153 | case H_HARDWARE: /* HCA not operational */ | ||
2154 | return -EINVAL; | ||
2155 | case H_RESOURCE: /* Resource in use */ | ||
2156 | case H_BUSY: /* long busy */ | ||
2157 | return -EBUSY; | ||
2158 | default: | ||
2159 | return -EINVAL; | ||
2160 | } | ||
2161 | } /* end ehca_mrmw_map_hrc_free_mr() */ | ||
2162 | |||
2163 | /*----------------------------------------------------------------------*/ | ||
2164 | |||
2165 | /* | ||
2166 | * map HIPZ rc to IB retcodes for freeing MW resource | ||
2167 | * Used for hipz_h_free_resource_mw | ||
2168 | */ | ||
2169 | int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc) | ||
2170 | { | ||
2171 | switch (hipz_rc) { | ||
2172 | case H_SUCCESS: /* resource freed */ | ||
2173 | return 0; | ||
2174 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2175 | case H_RH_PARM: /* invalid resource handle */ | ||
2176 | case H_R_STATE: /* invalid resource state */ | ||
2177 | case H_HARDWARE: /* HCA not operational */ | ||
2178 | return -EINVAL; | ||
2179 | case H_RESOURCE: /* Resource in use */ | ||
2180 | case H_BUSY: /* long busy */ | ||
2181 | return -EBUSY; | ||
2182 | default: | ||
2183 | return -EINVAL; | ||
2184 | } | ||
2185 | } /* end ehca_mrmw_map_hrc_free_mw() */ | ||
2186 | |||
2187 | /*----------------------------------------------------------------------*/ | ||
2188 | |||
2189 | /* | ||
2190 | * map HIPZ rc to IB retcodes for SMR registrations | ||
2191 | * Used for hipz_h_register_smr. | ||
2192 | */ | ||
2193 | int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc) | ||
2194 | { | ||
2195 | switch (hipz_rc) { | ||
2196 | case H_SUCCESS: /* successful completion */ | ||
2197 | return 0; | ||
2198 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2199 | case H_RH_PARM: /* invalid resource handle */ | ||
2200 | case H_MEM_PARM: /* invalid MR virtual address */ | ||
2201 | case H_MEM_ACCESS_PARM: /* invalid access controls */ | ||
2202 | case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */ | ||
2203 | return -EINVAL; | ||
2204 | case H_BUSY: /* long busy */ | ||
2205 | return -EBUSY; | ||
2206 | default: | ||
2207 | return -EINVAL; | ||
2208 | } | ||
2209 | } /* end ehca_mrmw_map_hrc_reg_smr() */ | ||
2210 | |||
2211 | /*----------------------------------------------------------------------*/ | ||
2212 | |||
2213 | /* | ||
2214 | * MR destructor and constructor | ||
2215 | * used in Reregister MR verb, sets all fields in ehca_mr_t to 0, | ||
2216 | * except struct ib_mr and spinlock | ||
2217 | */ | ||
2218 | void ehca_mr_deletenew(struct ehca_mr *mr) | ||
2219 | { | ||
2220 | mr->flags = 0; | ||
2221 | mr->num_pages = 0; | ||
2222 | mr->num_4k = 0; | ||
2223 | mr->acl = 0; | ||
2224 | mr->start = NULL; | ||
2225 | mr->fmr_page_size = 0; | ||
2226 | mr->fmr_max_pages = 0; | ||
2227 | mr->fmr_max_maps = 0; | ||
2228 | mr->fmr_map_cnt = 0; | ||
2229 | memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle)); | ||
2230 | memset(&mr->galpas, 0, sizeof(mr->galpas)); | ||
2231 | mr->nr_of_pages = 0; | ||
2232 | mr->pagearray = NULL; | ||
2233 | } /* end ehca_mr_deletenew() */ | ||
2234 | |||
2235 | int ehca_init_mrmw_cache(void) | ||
2236 | { | ||
2237 | mr_cache = kmem_cache_create("ehca_cache_mr", | ||
2238 | sizeof(struct ehca_mr), 0, | ||
2239 | SLAB_HWCACHE_ALIGN, | ||
2240 | NULL, NULL); | ||
2241 | if (!mr_cache) | ||
2242 | return -ENOMEM; | ||
2243 | mw_cache = kmem_cache_create("ehca_cache_mw", | ||
2244 | sizeof(struct ehca_mw), 0, | ||
2245 | SLAB_HWCACHE_ALIGN, | ||
2246 | NULL, NULL); | ||
2247 | if (!mw_cache) { | ||
2248 | kmem_cache_destroy(mr_cache); | ||
2249 | mr_cache = NULL; | ||
2250 | return -ENOMEM; | ||
2251 | } | ||
2252 | return 0; | ||
2253 | } | ||
2254 | |||
2255 | void ehca_cleanup_mrmw_cache(void) | ||
2256 | { | ||
2257 | if (mr_cache) | ||
2258 | kmem_cache_destroy(mr_cache); | ||
2259 | if (mw_cache) | ||
2260 | kmem_cache_destroy(mw_cache); | ||
2261 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h new file mode 100644 index 000000000000..d936e40a5748 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * MR/MW declarations and inline functions | ||
5 | * | ||
6 | * Authors: Dietmar Decker <ddecker@de.ibm.com> | ||
7 | * Christoph Raisch <raisch@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #ifndef _EHCA_MRMW_H_ | ||
43 | #define _EHCA_MRMW_H_ | ||
44 | |||
45 | int ehca_reg_mr(struct ehca_shca *shca, | ||
46 | struct ehca_mr *e_mr, | ||
47 | u64 *iova_start, | ||
48 | u64 size, | ||
49 | int acl, | ||
50 | struct ehca_pd *e_pd, | ||
51 | struct ehca_mr_pginfo *pginfo, | ||
52 | u32 *lkey, | ||
53 | u32 *rkey); | ||
54 | |||
55 | int ehca_reg_mr_rpages(struct ehca_shca *shca, | ||
56 | struct ehca_mr *e_mr, | ||
57 | struct ehca_mr_pginfo *pginfo); | ||
58 | |||
59 | int ehca_rereg_mr(struct ehca_shca *shca, | ||
60 | struct ehca_mr *e_mr, | ||
61 | u64 *iova_start, | ||
62 | u64 size, | ||
63 | int mr_access_flags, | ||
64 | struct ehca_pd *e_pd, | ||
65 | struct ehca_mr_pginfo *pginfo, | ||
66 | u32 *lkey, | ||
67 | u32 *rkey); | ||
68 | |||
69 | int ehca_unmap_one_fmr(struct ehca_shca *shca, | ||
70 | struct ehca_mr *e_fmr); | ||
71 | |||
72 | int ehca_reg_smr(struct ehca_shca *shca, | ||
73 | struct ehca_mr *e_origmr, | ||
74 | struct ehca_mr *e_newmr, | ||
75 | u64 *iova_start, | ||
76 | int acl, | ||
77 | struct ehca_pd *e_pd, | ||
78 | u32 *lkey, | ||
79 | u32 *rkey); | ||
80 | |||
81 | int ehca_reg_internal_maxmr(struct ehca_shca *shca, | ||
82 | struct ehca_pd *e_pd, | ||
83 | struct ehca_mr **maxmr); | ||
84 | |||
85 | int ehca_reg_maxmr(struct ehca_shca *shca, | ||
86 | struct ehca_mr *e_newmr, | ||
87 | u64 *iova_start, | ||
88 | int acl, | ||
89 | struct ehca_pd *e_pd, | ||
90 | u32 *lkey, | ||
91 | u32 *rkey); | ||
92 | |||
93 | int ehca_dereg_internal_maxmr(struct ehca_shca *shca); | ||
94 | |||
95 | int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array, | ||
96 | int num_phys_buf, | ||
97 | u64 *iova_start, | ||
98 | u64 *size); | ||
99 | |||
100 | int ehca_fmr_check_page_list(struct ehca_mr *e_fmr, | ||
101 | u64 *page_list, | ||
102 | int list_len); | ||
103 | |||
104 | int ehca_set_pagebuf(struct ehca_mr *e_mr, | ||
105 | struct ehca_mr_pginfo *pginfo, | ||
106 | u32 number, | ||
107 | u64 *kpage); | ||
108 | |||
109 | int ehca_set_pagebuf_1(struct ehca_mr *e_mr, | ||
110 | struct ehca_mr_pginfo *pginfo, | ||
111 | u64 *rpage); | ||
112 | |||
113 | int ehca_mr_is_maxmr(u64 size, | ||
114 | u64 *iova_start); | ||
115 | |||
116 | void ehca_mrmw_map_acl(int ib_acl, | ||
117 | u32 *hipz_acl); | ||
118 | |||
119 | void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl); | ||
120 | |||
121 | void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl, | ||
122 | int *ib_acl); | ||
123 | |||
124 | int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc); | ||
125 | |||
126 | int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc); | ||
127 | |||
128 | int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc); | ||
129 | |||
130 | int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc); | ||
131 | |||
132 | int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc); | ||
133 | |||
134 | int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc); | ||
135 | |||
136 | int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc); | ||
137 | |||
138 | void ehca_mr_deletenew(struct ehca_mr *mr); | ||
139 | |||
140 | #endif /*_EHCA_MRMW_H_*/ | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c new file mode 100644 index 000000000000..2c3cdc6f7b39 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_pd.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * PD functions | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * | ||
8 | * Copyright (c) 2005 IBM Corporation | ||
9 | * | ||
10 | * All rights reserved. | ||
11 | * | ||
12 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
13 | * BSD. | ||
14 | * | ||
15 | * OpenIB BSD License | ||
16 | * | ||
17 | * Redistribution and use in source and binary forms, with or without | ||
18 | * modification, are permitted provided that the following conditions are met: | ||
19 | * | ||
20 | * Redistributions of source code must retain the above copyright notice, this | ||
21 | * list of conditions and the following disclaimer. | ||
22 | * | ||
23 | * Redistributions in binary form must reproduce the above copyright notice, | ||
24 | * this list of conditions and the following disclaimer in the documentation | ||
25 | * and/or other materials | ||
26 | * provided with the distribution. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
29 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
32 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
33 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
34 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
35 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
36 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
37 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | */ | ||
40 | |||
41 | #include <asm/current.h> | ||
42 | |||
43 | #include "ehca_tools.h" | ||
44 | #include "ehca_iverbs.h" | ||
45 | |||
46 | static struct kmem_cache *pd_cache; | ||
47 | |||
48 | struct ib_pd *ehca_alloc_pd(struct ib_device *device, | ||
49 | struct ib_ucontext *context, struct ib_udata *udata) | ||
50 | { | ||
51 | struct ehca_pd *pd; | ||
52 | |||
53 | pd = kmem_cache_alloc(pd_cache, SLAB_KERNEL); | ||
54 | if (!pd) { | ||
55 | ehca_err(device, "device=%p context=%p out of memory", | ||
56 | device, context); | ||
57 | return ERR_PTR(-ENOMEM); | ||
58 | } | ||
59 | |||
60 | memset(pd, 0, sizeof(struct ehca_pd)); | ||
61 | pd->ownpid = current->tgid; | ||
62 | |||
63 | /* | ||
64 | * Kernel PD: when device = -1, 0 | ||
65 | * User PD: when context != -1 | ||
66 | */ | ||
67 | if (!context) { | ||
68 | /* | ||
69 | * Kernel PDs after init reuses always | ||
70 | * the one created in ehca_shca_reopen() | ||
71 | */ | ||
72 | struct ehca_shca *shca = container_of(device, struct ehca_shca, | ||
73 | ib_device); | ||
74 | pd->fw_pd.value = shca->pd->fw_pd.value; | ||
75 | } else | ||
76 | pd->fw_pd.value = (u64)pd; | ||
77 | |||
78 | return &pd->ib_pd; | ||
79 | } | ||
80 | |||
81 | int ehca_dealloc_pd(struct ib_pd *pd) | ||
82 | { | ||
83 | u32 cur_pid = current->tgid; | ||
84 | struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
85 | |||
86 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
87 | my_pd->ownpid != cur_pid) { | ||
88 | ehca_err(pd->device, "Invalid caller pid=%x ownpid=%x", | ||
89 | cur_pid, my_pd->ownpid); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | |||
93 | kmem_cache_free(pd_cache, | ||
94 | container_of(pd, struct ehca_pd, ib_pd)); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | int ehca_init_pd_cache(void) | ||
100 | { | ||
101 | pd_cache = kmem_cache_create("ehca_cache_pd", | ||
102 | sizeof(struct ehca_pd), 0, | ||
103 | SLAB_HWCACHE_ALIGN, | ||
104 | NULL, NULL); | ||
105 | if (!pd_cache) | ||
106 | return -ENOMEM; | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | void ehca_cleanup_pd_cache(void) | ||
111 | { | ||
112 | if (pd_cache) | ||
113 | kmem_cache_destroy(pd_cache); | ||
114 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h new file mode 100644 index 000000000000..8707d297ce4c --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_qes.h | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Hardware request structures | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Reinhard Ernst <rernst@de.ibm.com> | ||
8 | * Christoph Raisch <raisch@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | |||
44 | #ifndef _EHCA_QES_H_ | ||
45 | #define _EHCA_QES_H_ | ||
46 | |||
47 | #include "ehca_tools.h" | ||
48 | |||
49 | /* virtual scatter gather entry to specify remote adresses with length */ | ||
50 | struct ehca_vsgentry { | ||
51 | u64 vaddr; | ||
52 | u32 lkey; | ||
53 | u32 length; | ||
54 | }; | ||
55 | |||
56 | #define GRH_FLAG_MASK EHCA_BMASK_IBM(7,7) | ||
57 | #define GRH_IPVERSION_MASK EHCA_BMASK_IBM(0,3) | ||
58 | #define GRH_TCLASS_MASK EHCA_BMASK_IBM(4,12) | ||
59 | #define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13,31) | ||
60 | #define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32,47) | ||
61 | #define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48,55) | ||
62 | #define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56,63) | ||
63 | |||
64 | /* | ||
65 | * Unreliable Datagram Address Vector Format | ||
66 | * see IBTA Vol1 chapter 8.3 Global Routing Header | ||
67 | */ | ||
68 | struct ehca_ud_av { | ||
69 | u8 sl; | ||
70 | u8 lnh; | ||
71 | u16 dlid; | ||
72 | u8 reserved1; | ||
73 | u8 reserved2; | ||
74 | u8 reserved3; | ||
75 | u8 slid_path_bits; | ||
76 | u8 reserved4; | ||
77 | u8 ipd; | ||
78 | u8 reserved5; | ||
79 | u8 pmtu; | ||
80 | u32 reserved6; | ||
81 | u64 reserved7; | ||
82 | union { | ||
83 | struct { | ||
84 | u64 word_0; /* always set to 6 */ | ||
85 | /*should be 0x1B for IB transport */ | ||
86 | u64 word_1; | ||
87 | u64 word_2; | ||
88 | u64 word_3; | ||
89 | u64 word_4; | ||
90 | } grh; | ||
91 | struct { | ||
92 | u32 wd_0; | ||
93 | u32 wd_1; | ||
94 | /* DWord_1 --> SGID */ | ||
95 | |||
96 | u32 sgid_wd3; | ||
97 | u32 sgid_wd2; | ||
98 | |||
99 | u32 sgid_wd1; | ||
100 | u32 sgid_wd0; | ||
101 | /* DWord_3 --> DGID */ | ||
102 | |||
103 | u32 dgid_wd3; | ||
104 | u32 dgid_wd2; | ||
105 | |||
106 | u32 dgid_wd1; | ||
107 | u32 dgid_wd0; | ||
108 | } grh_l; | ||
109 | }; | ||
110 | }; | ||
111 | |||
112 | /* maximum number of sg entries allowed in a WQE */ | ||
113 | #define MAX_WQE_SG_ENTRIES 252 | ||
114 | |||
115 | #define WQE_OPTYPE_SEND 0x80 | ||
116 | #define WQE_OPTYPE_RDMAREAD 0x40 | ||
117 | #define WQE_OPTYPE_RDMAWRITE 0x20 | ||
118 | #define WQE_OPTYPE_CMPSWAP 0x10 | ||
119 | #define WQE_OPTYPE_FETCHADD 0x08 | ||
120 | #define WQE_OPTYPE_BIND 0x04 | ||
121 | |||
122 | #define WQE_WRFLAG_REQ_SIGNAL_COM 0x80 | ||
123 | #define WQE_WRFLAG_FENCE 0x40 | ||
124 | #define WQE_WRFLAG_IMM_DATA_PRESENT 0x20 | ||
125 | #define WQE_WRFLAG_SOLIC_EVENT 0x10 | ||
126 | |||
127 | #define WQEF_CACHE_HINT 0x80 | ||
128 | #define WQEF_CACHE_HINT_RD_WR 0x40 | ||
129 | #define WQEF_TIMED_WQE 0x20 | ||
130 | #define WQEF_PURGE 0x08 | ||
131 | #define WQEF_HIGH_NIBBLE 0xF0 | ||
132 | |||
133 | #define MW_BIND_ACCESSCTRL_R_WRITE 0x40 | ||
134 | #define MW_BIND_ACCESSCTRL_R_READ 0x20 | ||
135 | #define MW_BIND_ACCESSCTRL_R_ATOMIC 0x10 | ||
136 | |||
137 | struct ehca_wqe { | ||
138 | u64 work_request_id; | ||
139 | u8 optype; | ||
140 | u8 wr_flag; | ||
141 | u16 pkeyi; | ||
142 | u8 wqef; | ||
143 | u8 nr_of_data_seg; | ||
144 | u16 wqe_provided_slid; | ||
145 | u32 destination_qp_number; | ||
146 | u32 resync_psn_sqp; | ||
147 | u32 local_ee_context_qkey; | ||
148 | u32 immediate_data; | ||
149 | union { | ||
150 | struct { | ||
151 | u64 remote_virtual_adress; | ||
152 | u32 rkey; | ||
153 | u32 reserved; | ||
154 | u64 atomic_1st_op_dma_len; | ||
155 | u64 atomic_2nd_op; | ||
156 | struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES]; | ||
157 | |||
158 | } nud; | ||
159 | struct { | ||
160 | u64 ehca_ud_av_ptr; | ||
161 | u64 reserved1; | ||
162 | u64 reserved2; | ||
163 | u64 reserved3; | ||
164 | struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES]; | ||
165 | } ud_avp; | ||
166 | struct { | ||
167 | struct ehca_ud_av ud_av; | ||
168 | struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES - | ||
169 | 2]; | ||
170 | } ud_av; | ||
171 | struct { | ||
172 | u64 reserved0; | ||
173 | u64 reserved1; | ||
174 | u64 reserved2; | ||
175 | u64 reserved3; | ||
176 | struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES]; | ||
177 | } all_rcv; | ||
178 | |||
179 | struct { | ||
180 | u64 reserved; | ||
181 | u32 rkey; | ||
182 | u32 old_rkey; | ||
183 | u64 reserved1; | ||
184 | u64 reserved2; | ||
185 | u64 virtual_address; | ||
186 | u32 reserved3; | ||
187 | u32 length; | ||
188 | u32 reserved4; | ||
189 | u16 reserved5; | ||
190 | u8 reserved6; | ||
191 | u8 lr_ctl; | ||
192 | u32 lkey; | ||
193 | u32 reserved7; | ||
194 | u64 reserved8; | ||
195 | u64 reserved9; | ||
196 | u64 reserved10; | ||
197 | u64 reserved11; | ||
198 | } bind; | ||
199 | struct { | ||
200 | u64 reserved12; | ||
201 | u64 reserved13; | ||
202 | u32 size; | ||
203 | u32 start; | ||
204 | } inline_data; | ||
205 | } u; | ||
206 | |||
207 | }; | ||
208 | |||
209 | #define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0) | ||
210 | #define WC_IMM_DATA EHCA_BMASK_IBM(1,1) | ||
211 | #define WC_GRH_PRESENT EHCA_BMASK_IBM(2,2) | ||
212 | #define WC_SE_BIT EHCA_BMASK_IBM(3,3) | ||
213 | #define WC_STATUS_ERROR_BIT 0x80000000 | ||
214 | #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800 | ||
215 | #define WC_STATUS_PURGE_BIT 0x10 | ||
216 | |||
217 | struct ehca_cqe { | ||
218 | u64 work_request_id; | ||
219 | u8 optype; | ||
220 | u8 w_completion_flags; | ||
221 | u16 reserved1; | ||
222 | u32 nr_bytes_transferred; | ||
223 | u32 immediate_data; | ||
224 | u32 local_qp_number; | ||
225 | u8 freed_resource_count; | ||
226 | u8 service_level; | ||
227 | u16 wqe_count; | ||
228 | u32 qp_token; | ||
229 | u32 qkey_ee_token; | ||
230 | u32 remote_qp_number; | ||
231 | u16 dlid; | ||
232 | u16 rlid; | ||
233 | u16 reserved2; | ||
234 | u16 pkey_index; | ||
235 | u32 cqe_timestamp; | ||
236 | u32 wqe_timestamp; | ||
237 | u8 wqe_timestamp_valid; | ||
238 | u8 reserved3; | ||
239 | u8 reserved4; | ||
240 | u8 cqe_flags; | ||
241 | u32 status; | ||
242 | }; | ||
243 | |||
244 | struct ehca_eqe { | ||
245 | u64 entry; | ||
246 | }; | ||
247 | |||
248 | struct ehca_mrte { | ||
249 | u64 starting_va; | ||
250 | u64 length; /* length of memory region in bytes*/ | ||
251 | u32 pd; | ||
252 | u8 key_instance; | ||
253 | u8 pagesize; | ||
254 | u8 mr_control; | ||
255 | u8 local_remote_access_ctrl; | ||
256 | u8 reserved[0x20 - 0x18]; | ||
257 | u64 at_pointer[4]; | ||
258 | }; | ||
259 | #endif /*_EHCA_QES_H_*/ | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c new file mode 100644 index 000000000000..4394123cdbd7 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_qp.c | |||
@@ -0,0 +1,1507 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * QP functions | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Reinhard Ernst <rernst@de.ibm.com> | ||
9 | * Heiko J Schick <schickhj@de.ibm.com> | ||
10 | * | ||
11 | * Copyright (c) 2005 IBM Corporation | ||
12 | * | ||
13 | * All rights reserved. | ||
14 | * | ||
15 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
16 | * BSD. | ||
17 | * | ||
18 | * OpenIB BSD License | ||
19 | * | ||
20 | * Redistribution and use in source and binary forms, with or without | ||
21 | * modification, are permitted provided that the following conditions are met: | ||
22 | * | ||
23 | * Redistributions of source code must retain the above copyright notice, this | ||
24 | * list of conditions and the following disclaimer. | ||
25 | * | ||
26 | * Redistributions in binary form must reproduce the above copyright notice, | ||
27 | * this list of conditions and the following disclaimer in the documentation | ||
28 | * and/or other materials | ||
29 | * provided with the distribution. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
32 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
34 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
35 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
36 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
37 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
38 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
39 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | */ | ||
43 | |||
44 | |||
45 | #include <asm/current.h> | ||
46 | |||
47 | #include "ehca_classes.h" | ||
48 | #include "ehca_tools.h" | ||
49 | #include "ehca_qes.h" | ||
50 | #include "ehca_iverbs.h" | ||
51 | #include "hcp_if.h" | ||
52 | #include "hipz_fns.h" | ||
53 | |||
54 | static struct kmem_cache *qp_cache; | ||
55 | |||
56 | /* | ||
57 | * attributes not supported by query qp | ||
58 | */ | ||
59 | #define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \ | ||
60 | IB_QP_MAX_QP_RD_ATOMIC | \ | ||
61 | IB_QP_ACCESS_FLAGS | \ | ||
62 | IB_QP_EN_SQD_ASYNC_NOTIFY) | ||
63 | |||
64 | /* | ||
65 | * ehca (internal) qp state values | ||
66 | */ | ||
67 | enum ehca_qp_state { | ||
68 | EHCA_QPS_RESET = 1, | ||
69 | EHCA_QPS_INIT = 2, | ||
70 | EHCA_QPS_RTR = 3, | ||
71 | EHCA_QPS_RTS = 5, | ||
72 | EHCA_QPS_SQD = 6, | ||
73 | EHCA_QPS_SQE = 8, | ||
74 | EHCA_QPS_ERR = 128 | ||
75 | }; | ||
76 | |||
77 | /* | ||
78 | * qp state transitions as defined by IB Arch Rel 1.1 page 431 | ||
79 | */ | ||
80 | enum ib_qp_statetrans { | ||
81 | IB_QPST_ANY2RESET, | ||
82 | IB_QPST_ANY2ERR, | ||
83 | IB_QPST_RESET2INIT, | ||
84 | IB_QPST_INIT2RTR, | ||
85 | IB_QPST_INIT2INIT, | ||
86 | IB_QPST_RTR2RTS, | ||
87 | IB_QPST_RTS2SQD, | ||
88 | IB_QPST_RTS2RTS, | ||
89 | IB_QPST_SQD2RTS, | ||
90 | IB_QPST_SQE2RTS, | ||
91 | IB_QPST_SQD2SQD, | ||
92 | IB_QPST_MAX /* nr of transitions, this must be last!!! */ | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * ib2ehca_qp_state maps IB to ehca qp_state | ||
97 | * returns ehca qp state corresponding to given ib qp state | ||
98 | */ | ||
99 | static inline enum ehca_qp_state ib2ehca_qp_state(enum ib_qp_state ib_qp_state) | ||
100 | { | ||
101 | switch (ib_qp_state) { | ||
102 | case IB_QPS_RESET: | ||
103 | return EHCA_QPS_RESET; | ||
104 | case IB_QPS_INIT: | ||
105 | return EHCA_QPS_INIT; | ||
106 | case IB_QPS_RTR: | ||
107 | return EHCA_QPS_RTR; | ||
108 | case IB_QPS_RTS: | ||
109 | return EHCA_QPS_RTS; | ||
110 | case IB_QPS_SQD: | ||
111 | return EHCA_QPS_SQD; | ||
112 | case IB_QPS_SQE: | ||
113 | return EHCA_QPS_SQE; | ||
114 | case IB_QPS_ERR: | ||
115 | return EHCA_QPS_ERR; | ||
116 | default: | ||
117 | ehca_gen_err("invalid ib_qp_state=%x", ib_qp_state); | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * ehca2ib_qp_state maps ehca to IB qp_state | ||
124 | * returns ib qp state corresponding to given ehca qp state | ||
125 | */ | ||
126 | static inline enum ib_qp_state ehca2ib_qp_state(enum ehca_qp_state | ||
127 | ehca_qp_state) | ||
128 | { | ||
129 | switch (ehca_qp_state) { | ||
130 | case EHCA_QPS_RESET: | ||
131 | return IB_QPS_RESET; | ||
132 | case EHCA_QPS_INIT: | ||
133 | return IB_QPS_INIT; | ||
134 | case EHCA_QPS_RTR: | ||
135 | return IB_QPS_RTR; | ||
136 | case EHCA_QPS_RTS: | ||
137 | return IB_QPS_RTS; | ||
138 | case EHCA_QPS_SQD: | ||
139 | return IB_QPS_SQD; | ||
140 | case EHCA_QPS_SQE: | ||
141 | return IB_QPS_SQE; | ||
142 | case EHCA_QPS_ERR: | ||
143 | return IB_QPS_ERR; | ||
144 | default: | ||
145 | ehca_gen_err("invalid ehca_qp_state=%x", ehca_qp_state); | ||
146 | return -EINVAL; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * ehca_qp_type used as index for req_attr and opt_attr of | ||
152 | * struct ehca_modqp_statetrans | ||
153 | */ | ||
154 | enum ehca_qp_type { | ||
155 | QPT_RC = 0, | ||
156 | QPT_UC = 1, | ||
157 | QPT_UD = 2, | ||
158 | QPT_SQP = 3, | ||
159 | QPT_MAX | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * ib2ehcaqptype maps Ib to ehca qp_type | ||
164 | * returns ehca qp type corresponding to ib qp type | ||
165 | */ | ||
166 | static inline enum ehca_qp_type ib2ehcaqptype(enum ib_qp_type ibqptype) | ||
167 | { | ||
168 | switch (ibqptype) { | ||
169 | case IB_QPT_SMI: | ||
170 | case IB_QPT_GSI: | ||
171 | return QPT_SQP; | ||
172 | case IB_QPT_RC: | ||
173 | return QPT_RC; | ||
174 | case IB_QPT_UC: | ||
175 | return QPT_UC; | ||
176 | case IB_QPT_UD: | ||
177 | return QPT_UD; | ||
178 | default: | ||
179 | ehca_gen_err("Invalid ibqptype=%x", ibqptype); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static inline enum ib_qp_statetrans get_modqp_statetrans(int ib_fromstate, | ||
185 | int ib_tostate) | ||
186 | { | ||
187 | int index = -EINVAL; | ||
188 | switch (ib_tostate) { | ||
189 | case IB_QPS_RESET: | ||
190 | index = IB_QPST_ANY2RESET; | ||
191 | break; | ||
192 | case IB_QPS_INIT: | ||
193 | switch (ib_fromstate) { | ||
194 | case IB_QPS_RESET: | ||
195 | index = IB_QPST_RESET2INIT; | ||
196 | break; | ||
197 | case IB_QPS_INIT: | ||
198 | index = IB_QPST_INIT2INIT; | ||
199 | break; | ||
200 | } | ||
201 | break; | ||
202 | case IB_QPS_RTR: | ||
203 | if (ib_fromstate == IB_QPS_INIT) | ||
204 | index = IB_QPST_INIT2RTR; | ||
205 | break; | ||
206 | case IB_QPS_RTS: | ||
207 | switch (ib_fromstate) { | ||
208 | case IB_QPS_RTR: | ||
209 | index = IB_QPST_RTR2RTS; | ||
210 | break; | ||
211 | case IB_QPS_RTS: | ||
212 | index = IB_QPST_RTS2RTS; | ||
213 | break; | ||
214 | case IB_QPS_SQD: | ||
215 | index = IB_QPST_SQD2RTS; | ||
216 | break; | ||
217 | case IB_QPS_SQE: | ||
218 | index = IB_QPST_SQE2RTS; | ||
219 | break; | ||
220 | } | ||
221 | break; | ||
222 | case IB_QPS_SQD: | ||
223 | if (ib_fromstate == IB_QPS_RTS) | ||
224 | index = IB_QPST_RTS2SQD; | ||
225 | break; | ||
226 | case IB_QPS_SQE: | ||
227 | break; | ||
228 | case IB_QPS_ERR: | ||
229 | index = IB_QPST_ANY2ERR; | ||
230 | break; | ||
231 | default: | ||
232 | break; | ||
233 | } | ||
234 | return index; | ||
235 | } | ||
236 | |||
237 | enum ehca_service_type { | ||
238 | ST_RC = 0, | ||
239 | ST_UC = 1, | ||
240 | ST_RD = 2, | ||
241 | ST_UD = 3 | ||
242 | }; | ||
243 | |||
244 | /* | ||
245 | * ibqptype2servicetype returns hcp service type corresponding to given | ||
246 | * ib qp type used by create_qp() | ||
247 | */ | ||
248 | static inline int ibqptype2servicetype(enum ib_qp_type ibqptype) | ||
249 | { | ||
250 | switch (ibqptype) { | ||
251 | case IB_QPT_SMI: | ||
252 | case IB_QPT_GSI: | ||
253 | return ST_UD; | ||
254 | case IB_QPT_RC: | ||
255 | return ST_RC; | ||
256 | case IB_QPT_UC: | ||
257 | return ST_UC; | ||
258 | case IB_QPT_UD: | ||
259 | return ST_UD; | ||
260 | case IB_QPT_RAW_IPV6: | ||
261 | return -EINVAL; | ||
262 | case IB_QPT_RAW_ETY: | ||
263 | return -EINVAL; | ||
264 | default: | ||
265 | ehca_gen_err("Invalid ibqptype=%x", ibqptype); | ||
266 | return -EINVAL; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * init_qp_queues initializes/constructs r/squeue and registers queue pages. | ||
272 | */ | ||
273 | static inline int init_qp_queues(struct ehca_shca *shca, | ||
274 | struct ehca_qp *my_qp, | ||
275 | int nr_sq_pages, | ||
276 | int nr_rq_pages, | ||
277 | int swqe_size, | ||
278 | int rwqe_size, | ||
279 | int nr_send_sges, int nr_receive_sges) | ||
280 | { | ||
281 | int ret, cnt, ipz_rc; | ||
282 | void *vpage; | ||
283 | u64 rpage, h_ret; | ||
284 | struct ib_device *ib_dev = &shca->ib_device; | ||
285 | struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle; | ||
286 | |||
287 | ipz_rc = ipz_queue_ctor(&my_qp->ipz_squeue, | ||
288 | nr_sq_pages, | ||
289 | EHCA_PAGESIZE, swqe_size, nr_send_sges); | ||
290 | if (!ipz_rc) { | ||
291 | ehca_err(ib_dev,"Cannot allocate page for squeue. ipz_rc=%x", | ||
292 | ipz_rc); | ||
293 | return -EBUSY; | ||
294 | } | ||
295 | |||
296 | ipz_rc = ipz_queue_ctor(&my_qp->ipz_rqueue, | ||
297 | nr_rq_pages, | ||
298 | EHCA_PAGESIZE, rwqe_size, nr_receive_sges); | ||
299 | if (!ipz_rc) { | ||
300 | ehca_err(ib_dev, "Cannot allocate page for rqueue. ipz_rc=%x", | ||
301 | ipz_rc); | ||
302 | ret = -EBUSY; | ||
303 | goto init_qp_queues0; | ||
304 | } | ||
305 | /* register SQ pages */ | ||
306 | for (cnt = 0; cnt < nr_sq_pages; cnt++) { | ||
307 | vpage = ipz_qpageit_get_inc(&my_qp->ipz_squeue); | ||
308 | if (!vpage) { | ||
309 | ehca_err(ib_dev, "SQ ipz_qpageit_get_inc() " | ||
310 | "failed p_vpage= %p", vpage); | ||
311 | ret = -EINVAL; | ||
312 | goto init_qp_queues1; | ||
313 | } | ||
314 | rpage = virt_to_abs(vpage); | ||
315 | |||
316 | h_ret = hipz_h_register_rpage_qp(ipz_hca_handle, | ||
317 | my_qp->ipz_qp_handle, | ||
318 | &my_qp->pf, 0, 0, | ||
319 | rpage, 1, | ||
320 | my_qp->galpas.kernel); | ||
321 | if (h_ret < H_SUCCESS) { | ||
322 | ehca_err(ib_dev, "SQ hipz_qp_register_rpage()" | ||
323 | " failed rc=%lx", h_ret); | ||
324 | ret = ehca2ib_return_code(h_ret); | ||
325 | goto init_qp_queues1; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | ipz_qeit_reset(&my_qp->ipz_squeue); | ||
330 | |||
331 | /* register RQ pages */ | ||
332 | for (cnt = 0; cnt < nr_rq_pages; cnt++) { | ||
333 | vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue); | ||
334 | if (!vpage) { | ||
335 | ehca_err(ib_dev, "RQ ipz_qpageit_get_inc() " | ||
336 | "failed p_vpage = %p", vpage); | ||
337 | ret = -EINVAL; | ||
338 | goto init_qp_queues1; | ||
339 | } | ||
340 | |||
341 | rpage = virt_to_abs(vpage); | ||
342 | |||
343 | h_ret = hipz_h_register_rpage_qp(ipz_hca_handle, | ||
344 | my_qp->ipz_qp_handle, | ||
345 | &my_qp->pf, 0, 1, | ||
346 | rpage, 1,my_qp->galpas.kernel); | ||
347 | if (h_ret < H_SUCCESS) { | ||
348 | ehca_err(ib_dev, "RQ hipz_qp_register_rpage() failed " | ||
349 | "rc=%lx", h_ret); | ||
350 | ret = ehca2ib_return_code(h_ret); | ||
351 | goto init_qp_queues1; | ||
352 | } | ||
353 | if (cnt == (nr_rq_pages - 1)) { /* last page! */ | ||
354 | if (h_ret != H_SUCCESS) { | ||
355 | ehca_err(ib_dev, "RQ hipz_qp_register_rpage() " | ||
356 | "h_ret= %lx ", h_ret); | ||
357 | ret = ehca2ib_return_code(h_ret); | ||
358 | goto init_qp_queues1; | ||
359 | } | ||
360 | vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue); | ||
361 | if (vpage) { | ||
362 | ehca_err(ib_dev, "ipz_qpageit_get_inc() " | ||
363 | "should not succeed vpage=%p", vpage); | ||
364 | ret = -EINVAL; | ||
365 | goto init_qp_queues1; | ||
366 | } | ||
367 | } else { | ||
368 | if (h_ret != H_PAGE_REGISTERED) { | ||
369 | ehca_err(ib_dev, "RQ hipz_qp_register_rpage() " | ||
370 | "h_ret= %lx ", h_ret); | ||
371 | ret = ehca2ib_return_code(h_ret); | ||
372 | goto init_qp_queues1; | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | |||
377 | ipz_qeit_reset(&my_qp->ipz_rqueue); | ||
378 | |||
379 | return 0; | ||
380 | |||
381 | init_qp_queues1: | ||
382 | ipz_queue_dtor(&my_qp->ipz_rqueue); | ||
383 | init_qp_queues0: | ||
384 | ipz_queue_dtor(&my_qp->ipz_squeue); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | struct ib_qp *ehca_create_qp(struct ib_pd *pd, | ||
389 | struct ib_qp_init_attr *init_attr, | ||
390 | struct ib_udata *udata) | ||
391 | { | ||
392 | static int da_rc_msg_size[]={ 128, 256, 512, 1024, 2048, 4096 }; | ||
393 | static int da_ud_sq_msg_size[]={ 128, 384, 896, 1920, 3968 }; | ||
394 | struct ehca_qp *my_qp; | ||
395 | struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd); | ||
396 | struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, | ||
397 | ib_device); | ||
398 | struct ib_ucontext *context = NULL; | ||
399 | u64 h_ret; | ||
400 | int max_send_sge, max_recv_sge, ret; | ||
401 | |||
402 | /* h_call's out parameters */ | ||
403 | struct ehca_alloc_qp_parms parms; | ||
404 | u32 swqe_size = 0, rwqe_size = 0; | ||
405 | u8 daqp_completion, isdaqp; | ||
406 | unsigned long flags; | ||
407 | |||
408 | if (init_attr->sq_sig_type != IB_SIGNAL_REQ_WR && | ||
409 | init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) { | ||
410 | ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed", | ||
411 | init_attr->sq_sig_type); | ||
412 | return ERR_PTR(-EINVAL); | ||
413 | } | ||
414 | |||
415 | /* save daqp completion bits */ | ||
416 | daqp_completion = init_attr->qp_type & 0x60; | ||
417 | /* save daqp bit */ | ||
418 | isdaqp = (init_attr->qp_type & 0x80) ? 1 : 0; | ||
419 | init_attr->qp_type = init_attr->qp_type & 0x1F; | ||
420 | |||
421 | if (init_attr->qp_type != IB_QPT_UD && | ||
422 | init_attr->qp_type != IB_QPT_SMI && | ||
423 | init_attr->qp_type != IB_QPT_GSI && | ||
424 | init_attr->qp_type != IB_QPT_UC && | ||
425 | init_attr->qp_type != IB_QPT_RC) { | ||
426 | ehca_err(pd->device, "wrong QP Type=%x", init_attr->qp_type); | ||
427 | return ERR_PTR(-EINVAL); | ||
428 | } | ||
429 | if ((init_attr->qp_type != IB_QPT_RC && init_attr->qp_type != IB_QPT_UD) | ||
430 | && isdaqp) { | ||
431 | ehca_err(pd->device, "unsupported LL QP Type=%x", | ||
432 | init_attr->qp_type); | ||
433 | return ERR_PTR(-EINVAL); | ||
434 | } else if (init_attr->qp_type == IB_QPT_RC && isdaqp && | ||
435 | (init_attr->cap.max_send_wr > 255 || | ||
436 | init_attr->cap.max_recv_wr > 255 )) { | ||
437 | ehca_err(pd->device, "Invalid Number of max_sq_wr =%x " | ||
438 | "or max_rq_wr=%x for QP Type=%x", | ||
439 | init_attr->cap.max_send_wr, | ||
440 | init_attr->cap.max_recv_wr,init_attr->qp_type); | ||
441 | return ERR_PTR(-EINVAL); | ||
442 | } else if (init_attr->qp_type == IB_QPT_UD && isdaqp && | ||
443 | init_attr->cap.max_send_wr > 255) { | ||
444 | ehca_err(pd->device, | ||
445 | "Invalid Number of max_send_wr=%x for UD QP_TYPE=%x", | ||
446 | init_attr->cap.max_send_wr, init_attr->qp_type); | ||
447 | return ERR_PTR(-EINVAL); | ||
448 | } | ||
449 | |||
450 | if (pd->uobject && udata) | ||
451 | context = pd->uobject->context; | ||
452 | |||
453 | my_qp = kmem_cache_alloc(qp_cache, SLAB_KERNEL); | ||
454 | if (!my_qp) { | ||
455 | ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); | ||
456 | return ERR_PTR(-ENOMEM); | ||
457 | } | ||
458 | |||
459 | memset(my_qp, 0, sizeof(struct ehca_qp)); | ||
460 | memset (&parms, 0, sizeof(struct ehca_alloc_qp_parms)); | ||
461 | spin_lock_init(&my_qp->spinlock_s); | ||
462 | spin_lock_init(&my_qp->spinlock_r); | ||
463 | |||
464 | my_qp->recv_cq = | ||
465 | container_of(init_attr->recv_cq, struct ehca_cq, ib_cq); | ||
466 | my_qp->send_cq = | ||
467 | container_of(init_attr->send_cq, struct ehca_cq, ib_cq); | ||
468 | |||
469 | my_qp->init_attr = *init_attr; | ||
470 | |||
471 | do { | ||
472 | if (!idr_pre_get(&ehca_qp_idr, GFP_KERNEL)) { | ||
473 | ret = -ENOMEM; | ||
474 | ehca_err(pd->device, "Can't reserve idr resources."); | ||
475 | goto create_qp_exit0; | ||
476 | } | ||
477 | |||
478 | spin_lock_irqsave(&ehca_qp_idr_lock, flags); | ||
479 | ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token); | ||
480 | spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); | ||
481 | |||
482 | } while (ret == -EAGAIN); | ||
483 | |||
484 | if (ret) { | ||
485 | ret = -ENOMEM; | ||
486 | ehca_err(pd->device, "Can't allocate new idr entry."); | ||
487 | goto create_qp_exit0; | ||
488 | } | ||
489 | |||
490 | parms.servicetype = ibqptype2servicetype(init_attr->qp_type); | ||
491 | if (parms.servicetype < 0) { | ||
492 | ret = -EINVAL; | ||
493 | ehca_err(pd->device, "Invalid qp_type=%x", init_attr->qp_type); | ||
494 | goto create_qp_exit0; | ||
495 | } | ||
496 | |||
497 | if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) | ||
498 | parms.sigtype = HCALL_SIGT_EVERY; | ||
499 | else | ||
500 | parms.sigtype = HCALL_SIGT_BY_WQE; | ||
501 | |||
502 | /* UD_AV CIRCUMVENTION */ | ||
503 | max_send_sge = init_attr->cap.max_send_sge; | ||
504 | max_recv_sge = init_attr->cap.max_recv_sge; | ||
505 | if (IB_QPT_UD == init_attr->qp_type || | ||
506 | IB_QPT_GSI == init_attr->qp_type || | ||
507 | IB_QPT_SMI == init_attr->qp_type) { | ||
508 | max_send_sge += 2; | ||
509 | max_recv_sge += 2; | ||
510 | } | ||
511 | |||
512 | parms.ipz_eq_handle = shca->eq.ipz_eq_handle; | ||
513 | parms.daqp_ctrl = isdaqp | daqp_completion; | ||
514 | parms.pd = my_pd->fw_pd; | ||
515 | parms.max_recv_sge = max_recv_sge; | ||
516 | parms.max_send_sge = max_send_sge; | ||
517 | |||
518 | h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, my_qp, &parms); | ||
519 | |||
520 | if (h_ret != H_SUCCESS) { | ||
521 | ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx", | ||
522 | h_ret); | ||
523 | ret = ehca2ib_return_code(h_ret); | ||
524 | goto create_qp_exit1; | ||
525 | } | ||
526 | |||
527 | switch (init_attr->qp_type) { | ||
528 | case IB_QPT_RC: | ||
529 | if (isdaqp == 0) { | ||
530 | swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[ | ||
531 | (parms.act_nr_send_sges)]); | ||
532 | rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[ | ||
533 | (parms.act_nr_recv_sges)]); | ||
534 | } else { /* for daqp we need to use msg size, not wqe size */ | ||
535 | swqe_size = da_rc_msg_size[max_send_sge]; | ||
536 | rwqe_size = da_rc_msg_size[max_recv_sge]; | ||
537 | parms.act_nr_send_sges = 1; | ||
538 | parms.act_nr_recv_sges = 1; | ||
539 | } | ||
540 | break; | ||
541 | case IB_QPT_UC: | ||
542 | swqe_size = offsetof(struct ehca_wqe, | ||
543 | u.nud.sg_list[parms.act_nr_send_sges]); | ||
544 | rwqe_size = offsetof(struct ehca_wqe, | ||
545 | u.nud.sg_list[parms.act_nr_recv_sges]); | ||
546 | break; | ||
547 | |||
548 | case IB_QPT_UD: | ||
549 | case IB_QPT_GSI: | ||
550 | case IB_QPT_SMI: | ||
551 | /* UD circumvention */ | ||
552 | parms.act_nr_recv_sges -= 2; | ||
553 | parms.act_nr_send_sges -= 2; | ||
554 | if (isdaqp) { | ||
555 | swqe_size = da_ud_sq_msg_size[max_send_sge]; | ||
556 | rwqe_size = da_rc_msg_size[max_recv_sge]; | ||
557 | parms.act_nr_send_sges = 1; | ||
558 | parms.act_nr_recv_sges = 1; | ||
559 | } else { | ||
560 | swqe_size = offsetof(struct ehca_wqe, | ||
561 | u.ud_av.sg_list[parms.act_nr_send_sges]); | ||
562 | rwqe_size = offsetof(struct ehca_wqe, | ||
563 | u.ud_av.sg_list[parms.act_nr_recv_sges]); | ||
564 | } | ||
565 | |||
566 | if (IB_QPT_GSI == init_attr->qp_type || | ||
567 | IB_QPT_SMI == init_attr->qp_type) { | ||
568 | parms.act_nr_send_wqes = init_attr->cap.max_send_wr; | ||
569 | parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr; | ||
570 | parms.act_nr_send_sges = init_attr->cap.max_send_sge; | ||
571 | parms.act_nr_recv_sges = init_attr->cap.max_recv_sge; | ||
572 | my_qp->real_qp_num = | ||
573 | (init_attr->qp_type == IB_QPT_SMI) ? 0 : 1; | ||
574 | } | ||
575 | |||
576 | break; | ||
577 | |||
578 | default: | ||
579 | break; | ||
580 | } | ||
581 | |||
582 | /* initializes r/squeue and registers queue pages */ | ||
583 | ret = init_qp_queues(shca, my_qp, | ||
584 | parms.nr_sq_pages, parms.nr_rq_pages, | ||
585 | swqe_size, rwqe_size, | ||
586 | parms.act_nr_send_sges, parms.act_nr_recv_sges); | ||
587 | if (ret) { | ||
588 | ehca_err(pd->device, | ||
589 | "Couldn't initialize r/squeue and pages ret=%x", ret); | ||
590 | goto create_qp_exit2; | ||
591 | } | ||
592 | |||
593 | my_qp->ib_qp.pd = &my_pd->ib_pd; | ||
594 | my_qp->ib_qp.device = my_pd->ib_pd.device; | ||
595 | |||
596 | my_qp->ib_qp.recv_cq = init_attr->recv_cq; | ||
597 | my_qp->ib_qp.send_cq = init_attr->send_cq; | ||
598 | |||
599 | my_qp->ib_qp.qp_num = my_qp->real_qp_num; | ||
600 | my_qp->ib_qp.qp_type = init_attr->qp_type; | ||
601 | |||
602 | my_qp->qp_type = init_attr->qp_type; | ||
603 | my_qp->ib_qp.srq = init_attr->srq; | ||
604 | |||
605 | my_qp->ib_qp.qp_context = init_attr->qp_context; | ||
606 | my_qp->ib_qp.event_handler = init_attr->event_handler; | ||
607 | |||
608 | init_attr->cap.max_inline_data = 0; /* not supported yet */ | ||
609 | init_attr->cap.max_recv_sge = parms.act_nr_recv_sges; | ||
610 | init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes; | ||
611 | init_attr->cap.max_send_sge = parms.act_nr_send_sges; | ||
612 | init_attr->cap.max_send_wr = parms.act_nr_send_wqes; | ||
613 | |||
614 | /* NOTE: define_apq0() not supported yet */ | ||
615 | if (init_attr->qp_type == IB_QPT_GSI) { | ||
616 | h_ret = ehca_define_sqp(shca, my_qp, init_attr); | ||
617 | if (h_ret != H_SUCCESS) { | ||
618 | ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx", | ||
619 | h_ret); | ||
620 | ret = ehca2ib_return_code(h_ret); | ||
621 | goto create_qp_exit3; | ||
622 | } | ||
623 | } | ||
624 | if (init_attr->send_cq) { | ||
625 | struct ehca_cq *cq = container_of(init_attr->send_cq, | ||
626 | struct ehca_cq, ib_cq); | ||
627 | ret = ehca_cq_assign_qp(cq, my_qp); | ||
628 | if (ret) { | ||
629 | ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x", | ||
630 | ret); | ||
631 | goto create_qp_exit3; | ||
632 | } | ||
633 | my_qp->send_cq = cq; | ||
634 | } | ||
635 | /* copy queues, galpa data to user space */ | ||
636 | if (context && udata) { | ||
637 | struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue; | ||
638 | struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue; | ||
639 | struct ehca_create_qp_resp resp; | ||
640 | struct vm_area_struct * vma; | ||
641 | memset(&resp, 0, sizeof(resp)); | ||
642 | |||
643 | resp.qp_num = my_qp->real_qp_num; | ||
644 | resp.token = my_qp->token; | ||
645 | resp.qp_type = my_qp->qp_type; | ||
646 | resp.qkey = my_qp->qkey; | ||
647 | resp.real_qp_num = my_qp->real_qp_num; | ||
648 | /* rqueue properties */ | ||
649 | resp.ipz_rqueue.qe_size = ipz_rqueue->qe_size; | ||
650 | resp.ipz_rqueue.act_nr_of_sg = ipz_rqueue->act_nr_of_sg; | ||
651 | resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length; | ||
652 | resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize; | ||
653 | resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state; | ||
654 | ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000, | ||
655 | ipz_rqueue->queue_length, | ||
656 | (void**)&resp.ipz_rqueue.queue, | ||
657 | &vma); | ||
658 | if (ret) { | ||
659 | ehca_err(pd->device, "Could not mmap rqueue pages"); | ||
660 | goto create_qp_exit3; | ||
661 | } | ||
662 | my_qp->uspace_rqueue = resp.ipz_rqueue.queue; | ||
663 | /* squeue properties */ | ||
664 | resp.ipz_squeue.qe_size = ipz_squeue->qe_size; | ||
665 | resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg; | ||
666 | resp.ipz_squeue.queue_length = ipz_squeue->queue_length; | ||
667 | resp.ipz_squeue.pagesize = ipz_squeue->pagesize; | ||
668 | resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state; | ||
669 | ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000, | ||
670 | ipz_squeue->queue_length, | ||
671 | (void**)&resp.ipz_squeue.queue, | ||
672 | &vma); | ||
673 | if (ret) { | ||
674 | ehca_err(pd->device, "Could not mmap squeue pages"); | ||
675 | goto create_qp_exit4; | ||
676 | } | ||
677 | my_qp->uspace_squeue = resp.ipz_squeue.queue; | ||
678 | /* fw_handle */ | ||
679 | resp.galpas = my_qp->galpas; | ||
680 | ret = ehca_mmap_register(my_qp->galpas.user.fw_handle, | ||
681 | (void**)&resp.galpas.kernel.fw_handle, | ||
682 | &vma); | ||
683 | if (ret) { | ||
684 | ehca_err(pd->device, "Could not mmap fw_handle"); | ||
685 | goto create_qp_exit5; | ||
686 | } | ||
687 | my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle; | ||
688 | |||
689 | if (ib_copy_to_udata(udata, &resp, sizeof resp)) { | ||
690 | ehca_err(pd->device, "Copy to udata failed"); | ||
691 | ret = -EINVAL; | ||
692 | goto create_qp_exit6; | ||
693 | } | ||
694 | } | ||
695 | |||
696 | return &my_qp->ib_qp; | ||
697 | |||
698 | create_qp_exit6: | ||
699 | ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE); | ||
700 | |||
701 | create_qp_exit5: | ||
702 | ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length); | ||
703 | |||
704 | create_qp_exit4: | ||
705 | ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length); | ||
706 | |||
707 | create_qp_exit3: | ||
708 | ipz_queue_dtor(&my_qp->ipz_rqueue); | ||
709 | ipz_queue_dtor(&my_qp->ipz_squeue); | ||
710 | |||
711 | create_qp_exit2: | ||
712 | hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); | ||
713 | |||
714 | create_qp_exit1: | ||
715 | spin_lock_irqsave(&ehca_qp_idr_lock, flags); | ||
716 | idr_remove(&ehca_qp_idr, my_qp->token); | ||
717 | spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); | ||
718 | |||
719 | create_qp_exit0: | ||
720 | kmem_cache_free(qp_cache, my_qp); | ||
721 | return ERR_PTR(ret); | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * prepare_sqe_rts called by internal_modify_qp() at trans sqe -> rts | ||
726 | * set purge bit of bad wqe and subsequent wqes to avoid reentering sqe | ||
727 | * returns total number of bad wqes in bad_wqe_cnt | ||
728 | */ | ||
729 | static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, | ||
730 | int *bad_wqe_cnt) | ||
731 | { | ||
732 | u64 h_ret; | ||
733 | struct ipz_queue *squeue; | ||
734 | void *bad_send_wqe_p, *bad_send_wqe_v; | ||
735 | void *squeue_start_p, *squeue_end_p; | ||
736 | void *squeue_start_v, *squeue_end_v; | ||
737 | struct ehca_wqe *wqe; | ||
738 | int qp_num = my_qp->ib_qp.qp_num; | ||
739 | |||
740 | /* get send wqe pointer */ | ||
741 | h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle, | ||
742 | my_qp->ipz_qp_handle, &my_qp->pf, | ||
743 | &bad_send_wqe_p, NULL, 2); | ||
744 | if (h_ret != H_SUCCESS) { | ||
745 | ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed" | ||
746 | " ehca_qp=%p qp_num=%x h_ret=%lx", | ||
747 | my_qp, qp_num, h_ret); | ||
748 | return ehca2ib_return_code(h_ret); | ||
749 | } | ||
750 | bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63))); | ||
751 | ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p", | ||
752 | qp_num, bad_send_wqe_p); | ||
753 | /* convert wqe pointer to vadr */ | ||
754 | bad_send_wqe_v = abs_to_virt((u64)bad_send_wqe_p); | ||
755 | if (ehca_debug_level) | ||
756 | ehca_dmp(bad_send_wqe_v, 32, "qp_num=%x bad_wqe", qp_num); | ||
757 | squeue = &my_qp->ipz_squeue; | ||
758 | squeue_start_p = (void*)virt_to_abs(ipz_qeit_calc(squeue, 0L)); | ||
759 | squeue_end_p = squeue_start_p+squeue->queue_length; | ||
760 | squeue_start_v = abs_to_virt((u64)squeue_start_p); | ||
761 | squeue_end_v = abs_to_virt((u64)squeue_end_p); | ||
762 | ehca_dbg(&shca->ib_device, "qp_num=%x squeue_start_v=%p squeue_end_v=%p", | ||
763 | qp_num, squeue_start_v, squeue_end_v); | ||
764 | |||
765 | /* loop sets wqe's purge bit */ | ||
766 | wqe = (struct ehca_wqe*)bad_send_wqe_v; | ||
767 | *bad_wqe_cnt = 0; | ||
768 | while (wqe->optype != 0xff && wqe->wqef != 0xff) { | ||
769 | if (ehca_debug_level) | ||
770 | ehca_dmp(wqe, 32, "qp_num=%x wqe", qp_num); | ||
771 | wqe->nr_of_data_seg = 0; /* suppress data access */ | ||
772 | wqe->wqef = WQEF_PURGE; /* WQE to be purged */ | ||
773 | wqe = (struct ehca_wqe*)((u8*)wqe+squeue->qe_size); | ||
774 | *bad_wqe_cnt = (*bad_wqe_cnt)+1; | ||
775 | if ((void*)wqe >= squeue_end_v) { | ||
776 | wqe = squeue_start_v; | ||
777 | } | ||
778 | } | ||
779 | /* | ||
780 | * bad wqe will be reprocessed and ignored when pol_cq() is called, | ||
781 | * i.e. nr of wqes with flush error status is one less | ||
782 | */ | ||
783 | ehca_dbg(&shca->ib_device, "qp_num=%x flusherr_wqe_cnt=%x", | ||
784 | qp_num, (*bad_wqe_cnt)-1); | ||
785 | wqe->wqef = 0; | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | /* | ||
791 | * internal_modify_qp with circumvention to handle aqp0 properly | ||
792 | * smi_reset2init indicates if this is an internal reset-to-init-call for | ||
793 | * smi. This flag must always be zero if called from ehca_modify_qp()! | ||
794 | * This internal func was intorduced to avoid recursion of ehca_modify_qp()! | ||
795 | */ | ||
796 | static int internal_modify_qp(struct ib_qp *ibqp, | ||
797 | struct ib_qp_attr *attr, | ||
798 | int attr_mask, int smi_reset2init) | ||
799 | { | ||
800 | enum ib_qp_state qp_cur_state, qp_new_state; | ||
801 | int cnt, qp_attr_idx, ret = 0; | ||
802 | enum ib_qp_statetrans statetrans; | ||
803 | struct hcp_modify_qp_control_block *mqpcb; | ||
804 | struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); | ||
805 | struct ehca_shca *shca = | ||
806 | container_of(ibqp->pd->device, struct ehca_shca, ib_device); | ||
807 | u64 update_mask; | ||
808 | u64 h_ret; | ||
809 | int bad_wqe_cnt = 0; | ||
810 | int squeue_locked = 0; | ||
811 | unsigned long spl_flags = 0; | ||
812 | |||
813 | /* do query_qp to obtain current attr values */ | ||
814 | mqpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); | ||
815 | if (mqpcb == NULL) { | ||
816 | ehca_err(ibqp->device, "Could not get zeroed page for mqpcb " | ||
817 | "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num); | ||
818 | return -ENOMEM; | ||
819 | } | ||
820 | |||
821 | h_ret = hipz_h_query_qp(shca->ipz_hca_handle, | ||
822 | my_qp->ipz_qp_handle, | ||
823 | &my_qp->pf, | ||
824 | mqpcb, my_qp->galpas.kernel); | ||
825 | if (h_ret != H_SUCCESS) { | ||
826 | ehca_err(ibqp->device, "hipz_h_query_qp() failed " | ||
827 | "ehca_qp=%p qp_num=%x h_ret=%lx", | ||
828 | my_qp, ibqp->qp_num, h_ret); | ||
829 | ret = ehca2ib_return_code(h_ret); | ||
830 | goto modify_qp_exit1; | ||
831 | } | ||
832 | |||
833 | qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state); | ||
834 | |||
835 | if (qp_cur_state == -EINVAL) { /* invalid qp state */ | ||
836 | ret = -EINVAL; | ||
837 | ehca_err(ibqp->device, "Invalid current ehca_qp_state=%x " | ||
838 | "ehca_qp=%p qp_num=%x", | ||
839 | mqpcb->qp_state, my_qp, ibqp->qp_num); | ||
840 | goto modify_qp_exit1; | ||
841 | } | ||
842 | /* | ||
843 | * circumvention to set aqp0 initial state to init | ||
844 | * as expected by IB spec | ||
845 | */ | ||
846 | if (smi_reset2init == 0 && | ||
847 | ibqp->qp_type == IB_QPT_SMI && | ||
848 | qp_cur_state == IB_QPS_RESET && | ||
849 | (attr_mask & IB_QP_STATE) && | ||
850 | attr->qp_state == IB_QPS_INIT) { /* RESET -> INIT */ | ||
851 | struct ib_qp_attr smiqp_attr = { | ||
852 | .qp_state = IB_QPS_INIT, | ||
853 | .port_num = my_qp->init_attr.port_num, | ||
854 | .pkey_index = 0, | ||
855 | .qkey = 0 | ||
856 | }; | ||
857 | int smiqp_attr_mask = IB_QP_STATE | IB_QP_PORT | | ||
858 | IB_QP_PKEY_INDEX | IB_QP_QKEY; | ||
859 | int smirc = internal_modify_qp( | ||
860 | ibqp, &smiqp_attr, smiqp_attr_mask, 1); | ||
861 | if (smirc) { | ||
862 | ehca_err(ibqp->device, "SMI RESET -> INIT failed. " | ||
863 | "ehca_modify_qp() rc=%x", smirc); | ||
864 | ret = H_PARAMETER; | ||
865 | goto modify_qp_exit1; | ||
866 | } | ||
867 | qp_cur_state = IB_QPS_INIT; | ||
868 | ehca_dbg(ibqp->device, "SMI RESET -> INIT succeeded"); | ||
869 | } | ||
870 | /* is transmitted current state equal to "real" current state */ | ||
871 | if ((attr_mask & IB_QP_CUR_STATE) && | ||
872 | qp_cur_state != attr->cur_qp_state) { | ||
873 | ret = -EINVAL; | ||
874 | ehca_err(ibqp->device, | ||
875 | "Invalid IB_QP_CUR_STATE attr->curr_qp_state=%x <>" | ||
876 | " actual cur_qp_state=%x. ehca_qp=%p qp_num=%x", | ||
877 | attr->cur_qp_state, qp_cur_state, my_qp, ibqp->qp_num); | ||
878 | goto modify_qp_exit1; | ||
879 | } | ||
880 | |||
881 | ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x " | ||
882 | "new qp_state=%x attribute_mask=%x", | ||
883 | my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask); | ||
884 | |||
885 | qp_new_state = attr_mask & IB_QP_STATE ? attr->qp_state : qp_cur_state; | ||
886 | if (!smi_reset2init && | ||
887 | !ib_modify_qp_is_ok(qp_cur_state, qp_new_state, ibqp->qp_type, | ||
888 | attr_mask)) { | ||
889 | ret = -EINVAL; | ||
890 | ehca_err(ibqp->device, | ||
891 | "Invalid qp transition new_state=%x cur_state=%x " | ||
892 | "ehca_qp=%p qp_num=%x attr_mask=%x", qp_new_state, | ||
893 | qp_cur_state, my_qp, ibqp->qp_num, attr_mask); | ||
894 | goto modify_qp_exit1; | ||
895 | } | ||
896 | |||
897 | if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state))) | ||
898 | update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1); | ||
899 | else { | ||
900 | ret = -EINVAL; | ||
901 | ehca_err(ibqp->device, "Invalid new qp state=%x " | ||
902 | "ehca_qp=%p qp_num=%x", | ||
903 | qp_new_state, my_qp, ibqp->qp_num); | ||
904 | goto modify_qp_exit1; | ||
905 | } | ||
906 | |||
907 | /* retrieve state transition struct to get req and opt attrs */ | ||
908 | statetrans = get_modqp_statetrans(qp_cur_state, qp_new_state); | ||
909 | if (statetrans < 0) { | ||
910 | ret = -EINVAL; | ||
911 | ehca_err(ibqp->device, "<INVALID STATE CHANGE> qp_cur_state=%x " | ||
912 | "new_qp_state=%x State_xsition=%x ehca_qp=%p " | ||
913 | "qp_num=%x", qp_cur_state, qp_new_state, | ||
914 | statetrans, my_qp, ibqp->qp_num); | ||
915 | goto modify_qp_exit1; | ||
916 | } | ||
917 | |||
918 | qp_attr_idx = ib2ehcaqptype(ibqp->qp_type); | ||
919 | |||
920 | if (qp_attr_idx < 0) { | ||
921 | ret = qp_attr_idx; | ||
922 | ehca_err(ibqp->device, | ||
923 | "Invalid QP type=%x ehca_qp=%p qp_num=%x", | ||
924 | ibqp->qp_type, my_qp, ibqp->qp_num); | ||
925 | goto modify_qp_exit1; | ||
926 | } | ||
927 | |||
928 | ehca_dbg(ibqp->device, | ||
929 | "ehca_qp=%p qp_num=%x <VALID STATE CHANGE> qp_state_xsit=%x", | ||
930 | my_qp, ibqp->qp_num, statetrans); | ||
931 | |||
932 | /* sqe -> rts: set purge bit of bad wqe before actual trans */ | ||
933 | if ((my_qp->qp_type == IB_QPT_UD || | ||
934 | my_qp->qp_type == IB_QPT_GSI || | ||
935 | my_qp->qp_type == IB_QPT_SMI) && | ||
936 | statetrans == IB_QPST_SQE2RTS) { | ||
937 | /* mark next free wqe if kernel */ | ||
938 | if (my_qp->uspace_squeue == 0) { | ||
939 | struct ehca_wqe *wqe; | ||
940 | /* lock send queue */ | ||
941 | spin_lock_irqsave(&my_qp->spinlock_s, spl_flags); | ||
942 | squeue_locked = 1; | ||
943 | /* mark next free wqe */ | ||
944 | wqe = (struct ehca_wqe*) | ||
945 | ipz_qeit_get(&my_qp->ipz_squeue); | ||
946 | wqe->optype = wqe->wqef = 0xff; | ||
947 | ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p", | ||
948 | ibqp->qp_num, wqe); | ||
949 | } | ||
950 | ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt); | ||
951 | if (ret) { | ||
952 | ehca_err(ibqp->device, "prepare_sqe_rts() failed " | ||
953 | "ehca_qp=%p qp_num=%x ret=%x", | ||
954 | my_qp, ibqp->qp_num, ret); | ||
955 | goto modify_qp_exit2; | ||
956 | } | ||
957 | } | ||
958 | |||
959 | /* | ||
960 | * enable RDMA_Atomic_Control if reset->init und reliable con | ||
961 | * this is necessary since gen2 does not provide that flag, | ||
962 | * but pHyp requires it | ||
963 | */ | ||
964 | if (statetrans == IB_QPST_RESET2INIT && | ||
965 | (ibqp->qp_type == IB_QPT_RC || ibqp->qp_type == IB_QPT_UC)) { | ||
966 | mqpcb->rdma_atomic_ctrl = 3; | ||
967 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RDMA_ATOMIC_CTRL, 1); | ||
968 | } | ||
969 | /* circ. pHyp requires #RDMA/Atomic Resp Res for UC INIT -> RTR */ | ||
970 | if (statetrans == IB_QPST_INIT2RTR && | ||
971 | (ibqp->qp_type == IB_QPT_UC) && | ||
972 | !(attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)) { | ||
973 | mqpcb->rdma_nr_atomic_resp_res = 1; /* default to 1 */ | ||
974 | update_mask |= | ||
975 | EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1); | ||
976 | } | ||
977 | |||
978 | if (attr_mask & IB_QP_PKEY_INDEX) { | ||
979 | mqpcb->prim_p_key_idx = attr->pkey_index; | ||
980 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1); | ||
981 | } | ||
982 | if (attr_mask & IB_QP_PORT) { | ||
983 | if (attr->port_num < 1 || attr->port_num > shca->num_ports) { | ||
984 | ret = -EINVAL; | ||
985 | ehca_err(ibqp->device, "Invalid port=%x. " | ||
986 | "ehca_qp=%p qp_num=%x num_ports=%x", | ||
987 | attr->port_num, my_qp, ibqp->qp_num, | ||
988 | shca->num_ports); | ||
989 | goto modify_qp_exit2; | ||
990 | } | ||
991 | mqpcb->prim_phys_port = attr->port_num; | ||
992 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1); | ||
993 | } | ||
994 | if (attr_mask & IB_QP_QKEY) { | ||
995 | mqpcb->qkey = attr->qkey; | ||
996 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_QKEY, 1); | ||
997 | } | ||
998 | if (attr_mask & IB_QP_AV) { | ||
999 | int ah_mult = ib_rate_to_mult(attr->ah_attr.static_rate); | ||
1000 | int ehca_mult = ib_rate_to_mult(shca->sport[my_qp-> | ||
1001 | init_attr.port_num].rate); | ||
1002 | |||
1003 | mqpcb->dlid = attr->ah_attr.dlid; | ||
1004 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID, 1); | ||
1005 | mqpcb->source_path_bits = attr->ah_attr.src_path_bits; | ||
1006 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS, 1); | ||
1007 | mqpcb->service_level = attr->ah_attr.sl; | ||
1008 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL, 1); | ||
1009 | |||
1010 | if (ah_mult < ehca_mult) | ||
1011 | mqpcb->max_static_rate = (ah_mult > 0) ? | ||
1012 | ((ehca_mult - 1) / ah_mult) : 0; | ||
1013 | else | ||
1014 | mqpcb->max_static_rate = 0; | ||
1015 | |||
1016 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE, 1); | ||
1017 | |||
1018 | /* | ||
1019 | * only if GRH is TRUE we might consider SOURCE_GID_IDX | ||
1020 | * and DEST_GID otherwise phype will return H_ATTR_PARM!!! | ||
1021 | */ | ||
1022 | if (attr->ah_attr.ah_flags == IB_AH_GRH) { | ||
1023 | mqpcb->send_grh_flag = 1 << 31; | ||
1024 | update_mask |= | ||
1025 | EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG, 1); | ||
1026 | mqpcb->source_gid_idx = attr->ah_attr.grh.sgid_index; | ||
1027 | update_mask |= | ||
1028 | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX, 1); | ||
1029 | |||
1030 | for (cnt = 0; cnt < 16; cnt++) | ||
1031 | mqpcb->dest_gid.byte[cnt] = | ||
1032 | attr->ah_attr.grh.dgid.raw[cnt]; | ||
1033 | |||
1034 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_GID, 1); | ||
1035 | mqpcb->flow_label = attr->ah_attr.grh.flow_label; | ||
1036 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL, 1); | ||
1037 | mqpcb->hop_limit = attr->ah_attr.grh.hop_limit; | ||
1038 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT, 1); | ||
1039 | mqpcb->traffic_class = attr->ah_attr.grh.traffic_class; | ||
1040 | update_mask |= | ||
1041 | EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS, 1); | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | if (attr_mask & IB_QP_PATH_MTU) { | ||
1046 | mqpcb->path_mtu = attr->path_mtu; | ||
1047 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1); | ||
1048 | } | ||
1049 | if (attr_mask & IB_QP_TIMEOUT) { | ||
1050 | mqpcb->timeout = attr->timeout; | ||
1051 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT, 1); | ||
1052 | } | ||
1053 | if (attr_mask & IB_QP_RETRY_CNT) { | ||
1054 | mqpcb->retry_count = attr->retry_cnt; | ||
1055 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT, 1); | ||
1056 | } | ||
1057 | if (attr_mask & IB_QP_RNR_RETRY) { | ||
1058 | mqpcb->rnr_retry_count = attr->rnr_retry; | ||
1059 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT, 1); | ||
1060 | } | ||
1061 | if (attr_mask & IB_QP_RQ_PSN) { | ||
1062 | mqpcb->receive_psn = attr->rq_psn; | ||
1063 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RECEIVE_PSN, 1); | ||
1064 | } | ||
1065 | if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { | ||
1066 | mqpcb->rdma_nr_atomic_resp_res = attr->max_dest_rd_atomic < 3 ? | ||
1067 | attr->max_dest_rd_atomic : 2; | ||
1068 | update_mask |= | ||
1069 | EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1); | ||
1070 | } | ||
1071 | if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { | ||
1072 | mqpcb->rdma_atomic_outst_dest_qp = attr->max_rd_atomic < 3 ? | ||
1073 | attr->max_rd_atomic : 2; | ||
1074 | update_mask |= | ||
1075 | EHCA_BMASK_SET | ||
1076 | (MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP, 1); | ||
1077 | } | ||
1078 | if (attr_mask & IB_QP_ALT_PATH) { | ||
1079 | int ah_mult = ib_rate_to_mult(attr->alt_ah_attr.static_rate); | ||
1080 | int ehca_mult = ib_rate_to_mult( | ||
1081 | shca->sport[my_qp->init_attr.port_num].rate); | ||
1082 | |||
1083 | mqpcb->dlid_al = attr->alt_ah_attr.dlid; | ||
1084 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1); | ||
1085 | mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits; | ||
1086 | update_mask |= | ||
1087 | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1); | ||
1088 | mqpcb->service_level_al = attr->alt_ah_attr.sl; | ||
1089 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1); | ||
1090 | |||
1091 | if (ah_mult < ehca_mult) | ||
1092 | mqpcb->max_static_rate = (ah_mult > 0) ? | ||
1093 | ((ehca_mult - 1) / ah_mult) : 0; | ||
1094 | else | ||
1095 | mqpcb->max_static_rate_al = 0; | ||
1096 | |||
1097 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1); | ||
1098 | |||
1099 | /* | ||
1100 | * only if GRH is TRUE we might consider SOURCE_GID_IDX | ||
1101 | * and DEST_GID otherwise phype will return H_ATTR_PARM!!! | ||
1102 | */ | ||
1103 | if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) { | ||
1104 | mqpcb->send_grh_flag_al = 1 << 31; | ||
1105 | update_mask |= | ||
1106 | EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1); | ||
1107 | mqpcb->source_gid_idx_al = | ||
1108 | attr->alt_ah_attr.grh.sgid_index; | ||
1109 | update_mask |= | ||
1110 | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1); | ||
1111 | |||
1112 | for (cnt = 0; cnt < 16; cnt++) | ||
1113 | mqpcb->dest_gid_al.byte[cnt] = | ||
1114 | attr->alt_ah_attr.grh.dgid.raw[cnt]; | ||
1115 | |||
1116 | update_mask |= | ||
1117 | EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1); | ||
1118 | mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label; | ||
1119 | update_mask |= | ||
1120 | EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1); | ||
1121 | mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit; | ||
1122 | update_mask |= | ||
1123 | EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1); | ||
1124 | mqpcb->traffic_class_al = | ||
1125 | attr->alt_ah_attr.grh.traffic_class; | ||
1126 | update_mask |= | ||
1127 | EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1); | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | if (attr_mask & IB_QP_MIN_RNR_TIMER) { | ||
1132 | mqpcb->min_rnr_nak_timer_field = attr->min_rnr_timer; | ||
1133 | update_mask |= | ||
1134 | EHCA_BMASK_SET(MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD, 1); | ||
1135 | } | ||
1136 | |||
1137 | if (attr_mask & IB_QP_SQ_PSN) { | ||
1138 | mqpcb->send_psn = attr->sq_psn; | ||
1139 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_PSN, 1); | ||
1140 | } | ||
1141 | |||
1142 | if (attr_mask & IB_QP_DEST_QPN) { | ||
1143 | mqpcb->dest_qp_nr = attr->dest_qp_num; | ||
1144 | update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_QP_NR, 1); | ||
1145 | } | ||
1146 | |||
1147 | if (attr_mask & IB_QP_PATH_MIG_STATE) { | ||
1148 | mqpcb->path_migration_state = attr->path_mig_state; | ||
1149 | update_mask |= | ||
1150 | EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1); | ||
1151 | } | ||
1152 | |||
1153 | if (attr_mask & IB_QP_CAP) { | ||
1154 | mqpcb->max_nr_outst_send_wr = attr->cap.max_send_wr+1; | ||
1155 | update_mask |= | ||
1156 | EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_SEND_WR, 1); | ||
1157 | mqpcb->max_nr_outst_recv_wr = attr->cap.max_recv_wr+1; | ||
1158 | update_mask |= | ||
1159 | EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_RECV_WR, 1); | ||
1160 | /* no support for max_send/recv_sge yet */ | ||
1161 | } | ||
1162 | |||
1163 | if (ehca_debug_level) | ||
1164 | ehca_dmp(mqpcb, 4*70, "qp_num=%x", ibqp->qp_num); | ||
1165 | |||
1166 | h_ret = hipz_h_modify_qp(shca->ipz_hca_handle, | ||
1167 | my_qp->ipz_qp_handle, | ||
1168 | &my_qp->pf, | ||
1169 | update_mask, | ||
1170 | mqpcb, my_qp->galpas.kernel); | ||
1171 | |||
1172 | if (h_ret != H_SUCCESS) { | ||
1173 | ret = ehca2ib_return_code(h_ret); | ||
1174 | ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx " | ||
1175 | "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num); | ||
1176 | goto modify_qp_exit2; | ||
1177 | } | ||
1178 | |||
1179 | if ((my_qp->qp_type == IB_QPT_UD || | ||
1180 | my_qp->qp_type == IB_QPT_GSI || | ||
1181 | my_qp->qp_type == IB_QPT_SMI) && | ||
1182 | statetrans == IB_QPST_SQE2RTS) { | ||
1183 | /* doorbell to reprocessing wqes */ | ||
1184 | iosync(); /* serialize GAL register access */ | ||
1185 | hipz_update_sqa(my_qp, bad_wqe_cnt-1); | ||
1186 | ehca_gen_dbg("doorbell for %x wqes", bad_wqe_cnt); | ||
1187 | } | ||
1188 | |||
1189 | if (statetrans == IB_QPST_RESET2INIT || | ||
1190 | statetrans == IB_QPST_INIT2INIT) { | ||
1191 | mqpcb->qp_enable = 1; | ||
1192 | mqpcb->qp_state = EHCA_QPS_INIT; | ||
1193 | update_mask = 0; | ||
1194 | update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_ENABLE, 1); | ||
1195 | |||
1196 | h_ret = hipz_h_modify_qp(shca->ipz_hca_handle, | ||
1197 | my_qp->ipz_qp_handle, | ||
1198 | &my_qp->pf, | ||
1199 | update_mask, | ||
1200 | mqpcb, | ||
1201 | my_qp->galpas.kernel); | ||
1202 | |||
1203 | if (h_ret != H_SUCCESS) { | ||
1204 | ret = ehca2ib_return_code(h_ret); | ||
1205 | ehca_err(ibqp->device, "ENABLE in context of " | ||
1206 | "RESET_2_INIT failed! Maybe you didn't get " | ||
1207 | "a LID h_ret=%lx ehca_qp=%p qp_num=%x", | ||
1208 | h_ret, my_qp, ibqp->qp_num); | ||
1209 | goto modify_qp_exit2; | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1213 | if (statetrans == IB_QPST_ANY2RESET) { | ||
1214 | ipz_qeit_reset(&my_qp->ipz_rqueue); | ||
1215 | ipz_qeit_reset(&my_qp->ipz_squeue); | ||
1216 | } | ||
1217 | |||
1218 | if (attr_mask & IB_QP_QKEY) | ||
1219 | my_qp->qkey = attr->qkey; | ||
1220 | |||
1221 | modify_qp_exit2: | ||
1222 | if (squeue_locked) { /* this means: sqe -> rts */ | ||
1223 | spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags); | ||
1224 | my_qp->sqerr_purgeflag = 1; | ||
1225 | } | ||
1226 | |||
1227 | modify_qp_exit1: | ||
1228 | kfree(mqpcb); | ||
1229 | |||
1230 | return ret; | ||
1231 | } | ||
1232 | |||
1233 | int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, | ||
1234 | struct ib_udata *udata) | ||
1235 | { | ||
1236 | struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); | ||
1237 | struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, | ||
1238 | ib_pd); | ||
1239 | u32 cur_pid = current->tgid; | ||
1240 | |||
1241 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
1242 | my_pd->ownpid != cur_pid) { | ||
1243 | ehca_err(ibqp->pd->device, "Invalid caller pid=%x ownpid=%x", | ||
1244 | cur_pid, my_pd->ownpid); | ||
1245 | return -EINVAL; | ||
1246 | } | ||
1247 | |||
1248 | return internal_modify_qp(ibqp, attr, attr_mask, 0); | ||
1249 | } | ||
1250 | |||
1251 | int ehca_query_qp(struct ib_qp *qp, | ||
1252 | struct ib_qp_attr *qp_attr, | ||
1253 | int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr) | ||
1254 | { | ||
1255 | struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp); | ||
1256 | struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, | ||
1257 | ib_pd); | ||
1258 | struct ehca_shca *shca = container_of(qp->device, struct ehca_shca, | ||
1259 | ib_device); | ||
1260 | struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle; | ||
1261 | struct hcp_modify_qp_control_block *qpcb; | ||
1262 | u32 cur_pid = current->tgid; | ||
1263 | int cnt, ret = 0; | ||
1264 | u64 h_ret; | ||
1265 | |||
1266 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
1267 | my_pd->ownpid != cur_pid) { | ||
1268 | ehca_err(qp->device, "Invalid caller pid=%x ownpid=%x", | ||
1269 | cur_pid, my_pd->ownpid); | ||
1270 | return -EINVAL; | ||
1271 | } | ||
1272 | |||
1273 | if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) { | ||
1274 | ehca_err(qp->device,"Invalid attribute mask " | ||
1275 | "ehca_qp=%p qp_num=%x qp_attr_mask=%x ", | ||
1276 | my_qp, qp->qp_num, qp_attr_mask); | ||
1277 | return -EINVAL; | ||
1278 | } | ||
1279 | |||
1280 | qpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL ); | ||
1281 | if (!qpcb) { | ||
1282 | ehca_err(qp->device,"Out of memory for qpcb " | ||
1283 | "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num); | ||
1284 | return -ENOMEM; | ||
1285 | } | ||
1286 | |||
1287 | h_ret = hipz_h_query_qp(adapter_handle, | ||
1288 | my_qp->ipz_qp_handle, | ||
1289 | &my_qp->pf, | ||
1290 | qpcb, my_qp->galpas.kernel); | ||
1291 | |||
1292 | if (h_ret != H_SUCCESS) { | ||
1293 | ret = ehca2ib_return_code(h_ret); | ||
1294 | ehca_err(qp->device,"hipz_h_query_qp() failed " | ||
1295 | "ehca_qp=%p qp_num=%x h_ret=%lx", | ||
1296 | my_qp, qp->qp_num, h_ret); | ||
1297 | goto query_qp_exit1; | ||
1298 | } | ||
1299 | |||
1300 | qp_attr->cur_qp_state = ehca2ib_qp_state(qpcb->qp_state); | ||
1301 | qp_attr->qp_state = qp_attr->cur_qp_state; | ||
1302 | |||
1303 | if (qp_attr->cur_qp_state == -EINVAL) { | ||
1304 | ret = -EINVAL; | ||
1305 | ehca_err(qp->device,"Got invalid ehca_qp_state=%x " | ||
1306 | "ehca_qp=%p qp_num=%x", | ||
1307 | qpcb->qp_state, my_qp, qp->qp_num); | ||
1308 | goto query_qp_exit1; | ||
1309 | } | ||
1310 | |||
1311 | if (qp_attr->qp_state == IB_QPS_SQD) | ||
1312 | qp_attr->sq_draining = 1; | ||
1313 | |||
1314 | qp_attr->qkey = qpcb->qkey; | ||
1315 | qp_attr->path_mtu = qpcb->path_mtu; | ||
1316 | qp_attr->path_mig_state = qpcb->path_migration_state; | ||
1317 | qp_attr->rq_psn = qpcb->receive_psn; | ||
1318 | qp_attr->sq_psn = qpcb->send_psn; | ||
1319 | qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field; | ||
1320 | qp_attr->cap.max_send_wr = qpcb->max_nr_outst_send_wr-1; | ||
1321 | qp_attr->cap.max_recv_wr = qpcb->max_nr_outst_recv_wr-1; | ||
1322 | /* UD_AV CIRCUMVENTION */ | ||
1323 | if (my_qp->qp_type == IB_QPT_UD) { | ||
1324 | qp_attr->cap.max_send_sge = | ||
1325 | qpcb->actual_nr_sges_in_sq_wqe - 2; | ||
1326 | qp_attr->cap.max_recv_sge = | ||
1327 | qpcb->actual_nr_sges_in_rq_wqe - 2; | ||
1328 | } else { | ||
1329 | qp_attr->cap.max_send_sge = | ||
1330 | qpcb->actual_nr_sges_in_sq_wqe; | ||
1331 | qp_attr->cap.max_recv_sge = | ||
1332 | qpcb->actual_nr_sges_in_rq_wqe; | ||
1333 | } | ||
1334 | |||
1335 | qp_attr->cap.max_inline_data = my_qp->sq_max_inline_data_size; | ||
1336 | qp_attr->dest_qp_num = qpcb->dest_qp_nr; | ||
1337 | |||
1338 | qp_attr->pkey_index = | ||
1339 | EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->prim_p_key_idx); | ||
1340 | |||
1341 | qp_attr->port_num = | ||
1342 | EHCA_BMASK_GET(MQPCB_PRIM_PHYS_PORT, qpcb->prim_phys_port); | ||
1343 | |||
1344 | qp_attr->timeout = qpcb->timeout; | ||
1345 | qp_attr->retry_cnt = qpcb->retry_count; | ||
1346 | qp_attr->rnr_retry = qpcb->rnr_retry_count; | ||
1347 | |||
1348 | qp_attr->alt_pkey_index = | ||
1349 | EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->alt_p_key_idx); | ||
1350 | |||
1351 | qp_attr->alt_port_num = qpcb->alt_phys_port; | ||
1352 | qp_attr->alt_timeout = qpcb->timeout_al; | ||
1353 | |||
1354 | /* primary av */ | ||
1355 | qp_attr->ah_attr.sl = qpcb->service_level; | ||
1356 | |||
1357 | if (qpcb->send_grh_flag) { | ||
1358 | qp_attr->ah_attr.ah_flags = IB_AH_GRH; | ||
1359 | } | ||
1360 | |||
1361 | qp_attr->ah_attr.static_rate = qpcb->max_static_rate; | ||
1362 | qp_attr->ah_attr.dlid = qpcb->dlid; | ||
1363 | qp_attr->ah_attr.src_path_bits = qpcb->source_path_bits; | ||
1364 | qp_attr->ah_attr.port_num = qp_attr->port_num; | ||
1365 | |||
1366 | /* primary GRH */ | ||
1367 | qp_attr->ah_attr.grh.traffic_class = qpcb->traffic_class; | ||
1368 | qp_attr->ah_attr.grh.hop_limit = qpcb->hop_limit; | ||
1369 | qp_attr->ah_attr.grh.sgid_index = qpcb->source_gid_idx; | ||
1370 | qp_attr->ah_attr.grh.flow_label = qpcb->flow_label; | ||
1371 | |||
1372 | for (cnt = 0; cnt < 16; cnt++) | ||
1373 | qp_attr->ah_attr.grh.dgid.raw[cnt] = | ||
1374 | qpcb->dest_gid.byte[cnt]; | ||
1375 | |||
1376 | /* alternate AV */ | ||
1377 | qp_attr->alt_ah_attr.sl = qpcb->service_level_al; | ||
1378 | if (qpcb->send_grh_flag_al) { | ||
1379 | qp_attr->alt_ah_attr.ah_flags = IB_AH_GRH; | ||
1380 | } | ||
1381 | |||
1382 | qp_attr->alt_ah_attr.static_rate = qpcb->max_static_rate_al; | ||
1383 | qp_attr->alt_ah_attr.dlid = qpcb->dlid_al; | ||
1384 | qp_attr->alt_ah_attr.src_path_bits = qpcb->source_path_bits_al; | ||
1385 | |||
1386 | /* alternate GRH */ | ||
1387 | qp_attr->alt_ah_attr.grh.traffic_class = qpcb->traffic_class_al; | ||
1388 | qp_attr->alt_ah_attr.grh.hop_limit = qpcb->hop_limit_al; | ||
1389 | qp_attr->alt_ah_attr.grh.sgid_index = qpcb->source_gid_idx_al; | ||
1390 | qp_attr->alt_ah_attr.grh.flow_label = qpcb->flow_label_al; | ||
1391 | |||
1392 | for (cnt = 0; cnt < 16; cnt++) | ||
1393 | qp_attr->alt_ah_attr.grh.dgid.raw[cnt] = | ||
1394 | qpcb->dest_gid_al.byte[cnt]; | ||
1395 | |||
1396 | /* return init attributes given in ehca_create_qp */ | ||
1397 | if (qp_init_attr) | ||
1398 | *qp_init_attr = my_qp->init_attr; | ||
1399 | |||
1400 | if (ehca_debug_level) | ||
1401 | ehca_dmp(qpcb, 4*70, "qp_num=%x", qp->qp_num); | ||
1402 | |||
1403 | query_qp_exit1: | ||
1404 | kfree(qpcb); | ||
1405 | |||
1406 | return ret; | ||
1407 | } | ||
1408 | |||
1409 | int ehca_destroy_qp(struct ib_qp *ibqp) | ||
1410 | { | ||
1411 | struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); | ||
1412 | struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, | ||
1413 | ib_device); | ||
1414 | struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, | ||
1415 | ib_pd); | ||
1416 | u32 cur_pid = current->tgid; | ||
1417 | u32 qp_num = ibqp->qp_num; | ||
1418 | int ret; | ||
1419 | u64 h_ret; | ||
1420 | u8 port_num; | ||
1421 | enum ib_qp_type qp_type; | ||
1422 | unsigned long flags; | ||
1423 | |||
1424 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | ||
1425 | my_pd->ownpid != cur_pid) { | ||
1426 | ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x", | ||
1427 | cur_pid, my_pd->ownpid); | ||
1428 | return -EINVAL; | ||
1429 | } | ||
1430 | |||
1431 | if (my_qp->send_cq) { | ||
1432 | ret = ehca_cq_unassign_qp(my_qp->send_cq, | ||
1433 | my_qp->real_qp_num); | ||
1434 | if (ret) { | ||
1435 | ehca_err(ibqp->device, "Couldn't unassign qp from " | ||
1436 | "send_cq ret=%x qp_num=%x cq_num=%x", ret, | ||
1437 | my_qp->ib_qp.qp_num, my_qp->send_cq->cq_number); | ||
1438 | return ret; | ||
1439 | } | ||
1440 | } | ||
1441 | |||
1442 | spin_lock_irqsave(&ehca_qp_idr_lock, flags); | ||
1443 | idr_remove(&ehca_qp_idr, my_qp->token); | ||
1444 | spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); | ||
1445 | |||
1446 | /* un-mmap if vma alloc */ | ||
1447 | if (my_qp->uspace_rqueue) { | ||
1448 | ret = ehca_munmap(my_qp->uspace_rqueue, | ||
1449 | my_qp->ipz_rqueue.queue_length); | ||
1450 | if (ret) | ||
1451 | ehca_err(ibqp->device, "Could not munmap rqueue " | ||
1452 | "qp_num=%x", qp_num); | ||
1453 | ret = ehca_munmap(my_qp->uspace_squeue, | ||
1454 | my_qp->ipz_squeue.queue_length); | ||
1455 | if (ret) | ||
1456 | ehca_err(ibqp->device, "Could not munmap squeue " | ||
1457 | "qp_num=%x", qp_num); | ||
1458 | ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE); | ||
1459 | if (ret) | ||
1460 | ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x", | ||
1461 | qp_num); | ||
1462 | } | ||
1463 | |||
1464 | h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); | ||
1465 | if (h_ret != H_SUCCESS) { | ||
1466 | ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx " | ||
1467 | "ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num); | ||
1468 | return ehca2ib_return_code(h_ret); | ||
1469 | } | ||
1470 | |||
1471 | port_num = my_qp->init_attr.port_num; | ||
1472 | qp_type = my_qp->init_attr.qp_type; | ||
1473 | |||
1474 | /* no support for IB_QPT_SMI yet */ | ||
1475 | if (qp_type == IB_QPT_GSI) { | ||
1476 | struct ib_event event; | ||
1477 | ehca_info(ibqp->device, "device %s: port %x is inactive.", | ||
1478 | shca->ib_device.name, port_num); | ||
1479 | event.device = &shca->ib_device; | ||
1480 | event.event = IB_EVENT_PORT_ERR; | ||
1481 | event.element.port_num = port_num; | ||
1482 | shca->sport[port_num - 1].port_state = IB_PORT_DOWN; | ||
1483 | ib_dispatch_event(&event); | ||
1484 | } | ||
1485 | |||
1486 | ipz_queue_dtor(&my_qp->ipz_rqueue); | ||
1487 | ipz_queue_dtor(&my_qp->ipz_squeue); | ||
1488 | kmem_cache_free(qp_cache, my_qp); | ||
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | int ehca_init_qp_cache(void) | ||
1493 | { | ||
1494 | qp_cache = kmem_cache_create("ehca_cache_qp", | ||
1495 | sizeof(struct ehca_qp), 0, | ||
1496 | SLAB_HWCACHE_ALIGN, | ||
1497 | NULL, NULL); | ||
1498 | if (!qp_cache) | ||
1499 | return -ENOMEM; | ||
1500 | return 0; | ||
1501 | } | ||
1502 | |||
1503 | void ehca_cleanup_qp_cache(void) | ||
1504 | { | ||
1505 | if (qp_cache) | ||
1506 | kmem_cache_destroy(qp_cache); | ||
1507 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c new file mode 100644 index 000000000000..b46bda1bf85d --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c | |||
@@ -0,0 +1,653 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * post_send/recv, poll_cq, req_notify | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Reinhard Ernst <rernst@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | |||
44 | #include <asm-powerpc/system.h> | ||
45 | #include "ehca_classes.h" | ||
46 | #include "ehca_tools.h" | ||
47 | #include "ehca_qes.h" | ||
48 | #include "ehca_iverbs.h" | ||
49 | #include "hcp_if.h" | ||
50 | #include "hipz_fns.h" | ||
51 | |||
52 | static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, | ||
53 | struct ehca_wqe *wqe_p, | ||
54 | struct ib_recv_wr *recv_wr) | ||
55 | { | ||
56 | u8 cnt_ds; | ||
57 | if (unlikely((recv_wr->num_sge < 0) || | ||
58 | (recv_wr->num_sge > ipz_rqueue->act_nr_of_sg))) { | ||
59 | ehca_gen_err("Invalid number of WQE SGE. " | ||
60 | "num_sqe=%x max_nr_of_sg=%x", | ||
61 | recv_wr->num_sge, ipz_rqueue->act_nr_of_sg); | ||
62 | return -EINVAL; /* invalid SG list length */ | ||
63 | } | ||
64 | |||
65 | /* clear wqe header until sglist */ | ||
66 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); | ||
67 | |||
68 | wqe_p->work_request_id = recv_wr->wr_id; | ||
69 | wqe_p->nr_of_data_seg = recv_wr->num_sge; | ||
70 | |||
71 | for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) { | ||
72 | wqe_p->u.all_rcv.sg_list[cnt_ds].vaddr = | ||
73 | recv_wr->sg_list[cnt_ds].addr; | ||
74 | wqe_p->u.all_rcv.sg_list[cnt_ds].lkey = | ||
75 | recv_wr->sg_list[cnt_ds].lkey; | ||
76 | wqe_p->u.all_rcv.sg_list[cnt_ds].length = | ||
77 | recv_wr->sg_list[cnt_ds].length; | ||
78 | } | ||
79 | |||
80 | if (ehca_debug_level) { | ||
81 | ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue); | ||
82 | ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe"); | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | #if defined(DEBUG_GSI_SEND_WR) | ||
89 | |||
90 | /* need ib_mad struct */ | ||
91 | #include <rdma/ib_mad.h> | ||
92 | |||
93 | static void trace_send_wr_ud(const struct ib_send_wr *send_wr) | ||
94 | { | ||
95 | int idx; | ||
96 | int j; | ||
97 | while (send_wr) { | ||
98 | struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr; | ||
99 | struct ib_sge *sge = send_wr->sg_list; | ||
100 | ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x " | ||
101 | "send_flags=%x opcode=%x",idx, send_wr->wr_id, | ||
102 | send_wr->num_sge, send_wr->send_flags, | ||
103 | send_wr->opcode); | ||
104 | if (mad_hdr) { | ||
105 | ehca_gen_dbg("send_wr#%x mad_hdr base_version=%x " | ||
106 | "mgmt_class=%x class_version=%x method=%x " | ||
107 | "status=%x class_specific=%x tid=%lx " | ||
108 | "attr_id=%x resv=%x attr_mod=%x", | ||
109 | idx, mad_hdr->base_version, | ||
110 | mad_hdr->mgmt_class, | ||
111 | mad_hdr->class_version, mad_hdr->method, | ||
112 | mad_hdr->status, mad_hdr->class_specific, | ||
113 | mad_hdr->tid, mad_hdr->attr_id, | ||
114 | mad_hdr->resv, | ||
115 | mad_hdr->attr_mod); | ||
116 | } | ||
117 | for (j = 0; j < send_wr->num_sge; j++) { | ||
118 | u8 *data = (u8 *) abs_to_virt(sge->addr); | ||
119 | ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x " | ||
120 | "lkey=%x", | ||
121 | idx, j, data, sge->length, sge->lkey); | ||
122 | /* assume length is n*16 */ | ||
123 | ehca_dmp(data, sge->length, "send_wr#%x sge#%x", | ||
124 | idx, j); | ||
125 | sge++; | ||
126 | } /* eof for j */ | ||
127 | idx++; | ||
128 | send_wr = send_wr->next; | ||
129 | } /* eof while send_wr */ | ||
130 | } | ||
131 | |||
132 | #endif /* DEBUG_GSI_SEND_WR */ | ||
133 | |||
134 | static inline int ehca_write_swqe(struct ehca_qp *qp, | ||
135 | struct ehca_wqe *wqe_p, | ||
136 | const struct ib_send_wr *send_wr) | ||
137 | { | ||
138 | u32 idx; | ||
139 | u64 dma_length; | ||
140 | struct ehca_av *my_av; | ||
141 | u32 remote_qkey = send_wr->wr.ud.remote_qkey; | ||
142 | |||
143 | if (unlikely((send_wr->num_sge < 0) || | ||
144 | (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) { | ||
145 | ehca_gen_err("Invalid number of WQE SGE. " | ||
146 | "num_sqe=%x max_nr_of_sg=%x", | ||
147 | send_wr->num_sge, qp->ipz_squeue.act_nr_of_sg); | ||
148 | return -EINVAL; /* invalid SG list length */ | ||
149 | } | ||
150 | |||
151 | /* clear wqe header until sglist */ | ||
152 | memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); | ||
153 | |||
154 | wqe_p->work_request_id = send_wr->wr_id; | ||
155 | |||
156 | switch (send_wr->opcode) { | ||
157 | case IB_WR_SEND: | ||
158 | case IB_WR_SEND_WITH_IMM: | ||
159 | wqe_p->optype = WQE_OPTYPE_SEND; | ||
160 | break; | ||
161 | case IB_WR_RDMA_WRITE: | ||
162 | case IB_WR_RDMA_WRITE_WITH_IMM: | ||
163 | wqe_p->optype = WQE_OPTYPE_RDMAWRITE; | ||
164 | break; | ||
165 | case IB_WR_RDMA_READ: | ||
166 | wqe_p->optype = WQE_OPTYPE_RDMAREAD; | ||
167 | break; | ||
168 | default: | ||
169 | ehca_gen_err("Invalid opcode=%x", send_wr->opcode); | ||
170 | return -EINVAL; /* invalid opcode */ | ||
171 | } | ||
172 | |||
173 | wqe_p->wqef = (send_wr->opcode) & WQEF_HIGH_NIBBLE; | ||
174 | |||
175 | wqe_p->wr_flag = 0; | ||
176 | |||
177 | if (send_wr->send_flags & IB_SEND_SIGNALED) | ||
178 | wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM; | ||
179 | |||
180 | if (send_wr->opcode == IB_WR_SEND_WITH_IMM || | ||
181 | send_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) { | ||
182 | /* this might not work as long as HW does not support it */ | ||
183 | wqe_p->immediate_data = be32_to_cpu(send_wr->imm_data); | ||
184 | wqe_p->wr_flag |= WQE_WRFLAG_IMM_DATA_PRESENT; | ||
185 | } | ||
186 | |||
187 | wqe_p->nr_of_data_seg = send_wr->num_sge; | ||
188 | |||
189 | switch (qp->qp_type) { | ||
190 | case IB_QPT_SMI: | ||
191 | case IB_QPT_GSI: | ||
192 | /* no break is intential here */ | ||
193 | case IB_QPT_UD: | ||
194 | /* IB 1.2 spec C10-15 compliance */ | ||
195 | if (send_wr->wr.ud.remote_qkey & 0x80000000) | ||
196 | remote_qkey = qp->qkey; | ||
197 | |||
198 | wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8; | ||
199 | wqe_p->local_ee_context_qkey = remote_qkey; | ||
200 | if (!send_wr->wr.ud.ah) { | ||
201 | ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | my_av = container_of(send_wr->wr.ud.ah, struct ehca_av, ib_ah); | ||
205 | wqe_p->u.ud_av.ud_av = my_av->av; | ||
206 | |||
207 | /* | ||
208 | * omitted check of IB_SEND_INLINE | ||
209 | * since HW does not support it | ||
210 | */ | ||
211 | for (idx = 0; idx < send_wr->num_sge; idx++) { | ||
212 | wqe_p->u.ud_av.sg_list[idx].vaddr = | ||
213 | send_wr->sg_list[idx].addr; | ||
214 | wqe_p->u.ud_av.sg_list[idx].lkey = | ||
215 | send_wr->sg_list[idx].lkey; | ||
216 | wqe_p->u.ud_av.sg_list[idx].length = | ||
217 | send_wr->sg_list[idx].length; | ||
218 | } /* eof for idx */ | ||
219 | if (qp->qp_type == IB_QPT_SMI || | ||
220 | qp->qp_type == IB_QPT_GSI) | ||
221 | wqe_p->u.ud_av.ud_av.pmtu = 1; | ||
222 | if (qp->qp_type == IB_QPT_GSI) { | ||
223 | wqe_p->pkeyi = send_wr->wr.ud.pkey_index; | ||
224 | #ifdef DEBUG_GSI_SEND_WR | ||
225 | trace_send_wr_ud(send_wr); | ||
226 | #endif /* DEBUG_GSI_SEND_WR */ | ||
227 | } | ||
228 | break; | ||
229 | |||
230 | case IB_QPT_UC: | ||
231 | if (send_wr->send_flags & IB_SEND_FENCE) | ||
232 | wqe_p->wr_flag |= WQE_WRFLAG_FENCE; | ||
233 | /* no break is intentional here */ | ||
234 | case IB_QPT_RC: | ||
235 | /* TODO: atomic not implemented */ | ||
236 | wqe_p->u.nud.remote_virtual_adress = | ||
237 | send_wr->wr.rdma.remote_addr; | ||
238 | wqe_p->u.nud.rkey = send_wr->wr.rdma.rkey; | ||
239 | |||
240 | /* | ||
241 | * omitted checking of IB_SEND_INLINE | ||
242 | * since HW does not support it | ||
243 | */ | ||
244 | dma_length = 0; | ||
245 | for (idx = 0; idx < send_wr->num_sge; idx++) { | ||
246 | wqe_p->u.nud.sg_list[idx].vaddr = | ||
247 | send_wr->sg_list[idx].addr; | ||
248 | wqe_p->u.nud.sg_list[idx].lkey = | ||
249 | send_wr->sg_list[idx].lkey; | ||
250 | wqe_p->u.nud.sg_list[idx].length = | ||
251 | send_wr->sg_list[idx].length; | ||
252 | dma_length += send_wr->sg_list[idx].length; | ||
253 | } /* eof idx */ | ||
254 | wqe_p->u.nud.atomic_1st_op_dma_len = dma_length; | ||
255 | |||
256 | break; | ||
257 | |||
258 | default: | ||
259 | ehca_gen_err("Invalid qptype=%x", qp->qp_type); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | if (ehca_debug_level) { | ||
264 | ehca_gen_dbg("SEND WQE written into queue qp=%p ", qp); | ||
265 | ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "send wqe"); | ||
266 | } | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | /* map_ib_wc_status converts raw cqe_status to ib_wc_status */ | ||
271 | static inline void map_ib_wc_status(u32 cqe_status, | ||
272 | enum ib_wc_status *wc_status) | ||
273 | { | ||
274 | if (unlikely(cqe_status & WC_STATUS_ERROR_BIT)) { | ||
275 | switch (cqe_status & 0x3F) { | ||
276 | case 0x01: | ||
277 | case 0x21: | ||
278 | *wc_status = IB_WC_LOC_LEN_ERR; | ||
279 | break; | ||
280 | case 0x02: | ||
281 | case 0x22: | ||
282 | *wc_status = IB_WC_LOC_QP_OP_ERR; | ||
283 | break; | ||
284 | case 0x03: | ||
285 | case 0x23: | ||
286 | *wc_status = IB_WC_LOC_EEC_OP_ERR; | ||
287 | break; | ||
288 | case 0x04: | ||
289 | case 0x24: | ||
290 | *wc_status = IB_WC_LOC_PROT_ERR; | ||
291 | break; | ||
292 | case 0x05: | ||
293 | case 0x25: | ||
294 | *wc_status = IB_WC_WR_FLUSH_ERR; | ||
295 | break; | ||
296 | case 0x06: | ||
297 | *wc_status = IB_WC_MW_BIND_ERR; | ||
298 | break; | ||
299 | case 0x07: /* remote error - look into bits 20:24 */ | ||
300 | switch ((cqe_status | ||
301 | & WC_STATUS_REMOTE_ERROR_FLAGS) >> 11) { | ||
302 | case 0x0: | ||
303 | /* | ||
304 | * PSN Sequence Error! | ||
305 | * couldn't find a matching status! | ||
306 | */ | ||
307 | *wc_status = IB_WC_GENERAL_ERR; | ||
308 | break; | ||
309 | case 0x1: | ||
310 | *wc_status = IB_WC_REM_INV_REQ_ERR; | ||
311 | break; | ||
312 | case 0x2: | ||
313 | *wc_status = IB_WC_REM_ACCESS_ERR; | ||
314 | break; | ||
315 | case 0x3: | ||
316 | *wc_status = IB_WC_REM_OP_ERR; | ||
317 | break; | ||
318 | case 0x4: | ||
319 | *wc_status = IB_WC_REM_INV_RD_REQ_ERR; | ||
320 | break; | ||
321 | } | ||
322 | break; | ||
323 | case 0x08: | ||
324 | *wc_status = IB_WC_RETRY_EXC_ERR; | ||
325 | break; | ||
326 | case 0x09: | ||
327 | *wc_status = IB_WC_RNR_RETRY_EXC_ERR; | ||
328 | break; | ||
329 | case 0x0A: | ||
330 | case 0x2D: | ||
331 | *wc_status = IB_WC_REM_ABORT_ERR; | ||
332 | break; | ||
333 | case 0x0B: | ||
334 | case 0x2E: | ||
335 | *wc_status = IB_WC_INV_EECN_ERR; | ||
336 | break; | ||
337 | case 0x0C: | ||
338 | case 0x2F: | ||
339 | *wc_status = IB_WC_INV_EEC_STATE_ERR; | ||
340 | break; | ||
341 | case 0x0D: | ||
342 | *wc_status = IB_WC_BAD_RESP_ERR; | ||
343 | break; | ||
344 | case 0x10: | ||
345 | /* WQE purged */ | ||
346 | *wc_status = IB_WC_WR_FLUSH_ERR; | ||
347 | break; | ||
348 | default: | ||
349 | *wc_status = IB_WC_FATAL_ERR; | ||
350 | |||
351 | } | ||
352 | } else | ||
353 | *wc_status = IB_WC_SUCCESS; | ||
354 | } | ||
355 | |||
356 | int ehca_post_send(struct ib_qp *qp, | ||
357 | struct ib_send_wr *send_wr, | ||
358 | struct ib_send_wr **bad_send_wr) | ||
359 | { | ||
360 | struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp); | ||
361 | struct ib_send_wr *cur_send_wr; | ||
362 | struct ehca_wqe *wqe_p; | ||
363 | int wqe_cnt = 0; | ||
364 | int ret = 0; | ||
365 | unsigned long spl_flags; | ||
366 | |||
367 | /* LOCK the QUEUE */ | ||
368 | spin_lock_irqsave(&my_qp->spinlock_s, spl_flags); | ||
369 | |||
370 | /* loop processes list of send reqs */ | ||
371 | for (cur_send_wr = send_wr; cur_send_wr != NULL; | ||
372 | cur_send_wr = cur_send_wr->next) { | ||
373 | u64 start_offset = my_qp->ipz_squeue.current_q_offset; | ||
374 | /* get pointer next to free WQE */ | ||
375 | wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue); | ||
376 | if (unlikely(!wqe_p)) { | ||
377 | /* too many posted work requests: queue overflow */ | ||
378 | if (bad_send_wr) | ||
379 | *bad_send_wr = cur_send_wr; | ||
380 | if (wqe_cnt == 0) { | ||
381 | ret = -ENOMEM; | ||
382 | ehca_err(qp->device, "Too many posted WQEs " | ||
383 | "qp_num=%x", qp->qp_num); | ||
384 | } | ||
385 | goto post_send_exit0; | ||
386 | } | ||
387 | /* write a SEND WQE into the QUEUE */ | ||
388 | ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr); | ||
389 | /* | ||
390 | * if something failed, | ||
391 | * reset the free entry pointer to the start value | ||
392 | */ | ||
393 | if (unlikely(ret)) { | ||
394 | my_qp->ipz_squeue.current_q_offset = start_offset; | ||
395 | *bad_send_wr = cur_send_wr; | ||
396 | if (wqe_cnt == 0) { | ||
397 | ret = -EINVAL; | ||
398 | ehca_err(qp->device, "Could not write WQE " | ||
399 | "qp_num=%x", qp->qp_num); | ||
400 | } | ||
401 | goto post_send_exit0; | ||
402 | } | ||
403 | wqe_cnt++; | ||
404 | ehca_dbg(qp->device, "ehca_qp=%p qp_num=%x wqe_cnt=%d", | ||
405 | my_qp, qp->qp_num, wqe_cnt); | ||
406 | } /* eof for cur_send_wr */ | ||
407 | |||
408 | post_send_exit0: | ||
409 | /* UNLOCK the QUEUE */ | ||
410 | spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags); | ||
411 | iosync(); /* serialize GAL register access */ | ||
412 | hipz_update_sqa(my_qp, wqe_cnt); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | int ehca_post_recv(struct ib_qp *qp, | ||
417 | struct ib_recv_wr *recv_wr, | ||
418 | struct ib_recv_wr **bad_recv_wr) | ||
419 | { | ||
420 | struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp); | ||
421 | struct ib_recv_wr *cur_recv_wr; | ||
422 | struct ehca_wqe *wqe_p; | ||
423 | int wqe_cnt = 0; | ||
424 | int ret = 0; | ||
425 | unsigned long spl_flags; | ||
426 | |||
427 | /* LOCK the QUEUE */ | ||
428 | spin_lock_irqsave(&my_qp->spinlock_r, spl_flags); | ||
429 | |||
430 | /* loop processes list of send reqs */ | ||
431 | for (cur_recv_wr = recv_wr; cur_recv_wr != NULL; | ||
432 | cur_recv_wr = cur_recv_wr->next) { | ||
433 | u64 start_offset = my_qp->ipz_rqueue.current_q_offset; | ||
434 | /* get pointer next to free WQE */ | ||
435 | wqe_p = ipz_qeit_get_inc(&my_qp->ipz_rqueue); | ||
436 | if (unlikely(!wqe_p)) { | ||
437 | /* too many posted work requests: queue overflow */ | ||
438 | if (bad_recv_wr) | ||
439 | *bad_recv_wr = cur_recv_wr; | ||
440 | if (wqe_cnt == 0) { | ||
441 | ret = -ENOMEM; | ||
442 | ehca_err(qp->device, "Too many posted WQEs " | ||
443 | "qp_num=%x", qp->qp_num); | ||
444 | } | ||
445 | goto post_recv_exit0; | ||
446 | } | ||
447 | /* write a RECV WQE into the QUEUE */ | ||
448 | ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr); | ||
449 | /* | ||
450 | * if something failed, | ||
451 | * reset the free entry pointer to the start value | ||
452 | */ | ||
453 | if (unlikely(ret)) { | ||
454 | my_qp->ipz_rqueue.current_q_offset = start_offset; | ||
455 | *bad_recv_wr = cur_recv_wr; | ||
456 | if (wqe_cnt == 0) { | ||
457 | ret = -EINVAL; | ||
458 | ehca_err(qp->device, "Could not write WQE " | ||
459 | "qp_num=%x", qp->qp_num); | ||
460 | } | ||
461 | goto post_recv_exit0; | ||
462 | } | ||
463 | wqe_cnt++; | ||
464 | ehca_gen_dbg("ehca_qp=%p qp_num=%x wqe_cnt=%d", | ||
465 | my_qp, qp->qp_num, wqe_cnt); | ||
466 | } /* eof for cur_recv_wr */ | ||
467 | |||
468 | post_recv_exit0: | ||
469 | spin_unlock_irqrestore(&my_qp->spinlock_r, spl_flags); | ||
470 | iosync(); /* serialize GAL register access */ | ||
471 | hipz_update_rqa(my_qp, wqe_cnt); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * ib_wc_opcode table converts ehca wc opcode to ib | ||
477 | * Since we use zero to indicate invalid opcode, the actual ib opcode must | ||
478 | * be decremented!!! | ||
479 | */ | ||
480 | static const u8 ib_wc_opcode[255] = { | ||
481 | [0x01] = IB_WC_RECV+1, | ||
482 | [0x02] = IB_WC_RECV_RDMA_WITH_IMM+1, | ||
483 | [0x04] = IB_WC_BIND_MW+1, | ||
484 | [0x08] = IB_WC_FETCH_ADD+1, | ||
485 | [0x10] = IB_WC_COMP_SWAP+1, | ||
486 | [0x20] = IB_WC_RDMA_WRITE+1, | ||
487 | [0x40] = IB_WC_RDMA_READ+1, | ||
488 | [0x80] = IB_WC_SEND+1 | ||
489 | }; | ||
490 | |||
491 | /* internal function to poll one entry of cq */ | ||
492 | static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) | ||
493 | { | ||
494 | int ret = 0; | ||
495 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); | ||
496 | struct ehca_cqe *cqe; | ||
497 | int cqe_count = 0; | ||
498 | |||
499 | poll_cq_one_read_cqe: | ||
500 | cqe = (struct ehca_cqe *) | ||
501 | ipz_qeit_get_inc_valid(&my_cq->ipz_queue); | ||
502 | if (!cqe) { | ||
503 | ret = -EAGAIN; | ||
504 | ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p " | ||
505 | "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret); | ||
506 | goto poll_cq_one_exit0; | ||
507 | } | ||
508 | |||
509 | /* prevents loads being reordered across this point */ | ||
510 | rmb(); | ||
511 | |||
512 | cqe_count++; | ||
513 | if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) { | ||
514 | struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number); | ||
515 | int purgeflag; | ||
516 | unsigned long spl_flags; | ||
517 | if (!qp) { | ||
518 | ehca_err(cq->device, "cq_num=%x qp_num=%x " | ||
519 | "could not find qp -> ignore cqe", | ||
520 | my_cq->cq_number, cqe->local_qp_number); | ||
521 | ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x", | ||
522 | my_cq->cq_number, cqe->local_qp_number); | ||
523 | /* ignore this purged cqe */ | ||
524 | goto poll_cq_one_read_cqe; | ||
525 | } | ||
526 | spin_lock_irqsave(&qp->spinlock_s, spl_flags); | ||
527 | purgeflag = qp->sqerr_purgeflag; | ||
528 | spin_unlock_irqrestore(&qp->spinlock_s, spl_flags); | ||
529 | |||
530 | if (purgeflag) { | ||
531 | ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x " | ||
532 | "src_qp=%x", | ||
533 | cqe->local_qp_number, cqe->remote_qp_number); | ||
534 | if (ehca_debug_level) | ||
535 | ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x", | ||
536 | cqe->local_qp_number, | ||
537 | cqe->remote_qp_number); | ||
538 | /* | ||
539 | * ignore this to avoid double cqes of bad wqe | ||
540 | * that caused sqe and turn off purge flag | ||
541 | */ | ||
542 | qp->sqerr_purgeflag = 0; | ||
543 | goto poll_cq_one_read_cqe; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | /* tracing cqe */ | ||
548 | if (ehca_debug_level) { | ||
549 | ehca_dbg(cq->device, | ||
550 | "Received COMPLETION ehca_cq=%p cq_num=%x -----", | ||
551 | my_cq, my_cq->cq_number); | ||
552 | ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x", | ||
553 | my_cq, my_cq->cq_number); | ||
554 | ehca_dbg(cq->device, | ||
555 | "ehca_cq=%p cq_num=%x -------------------------", | ||
556 | my_cq, my_cq->cq_number); | ||
557 | } | ||
558 | |||
559 | /* we got a completion! */ | ||
560 | wc->wr_id = cqe->work_request_id; | ||
561 | |||
562 | /* eval ib_wc_opcode */ | ||
563 | wc->opcode = ib_wc_opcode[cqe->optype]-1; | ||
564 | if (unlikely(wc->opcode == -1)) { | ||
565 | ehca_err(cq->device, "Invalid cqe->OPType=%x cqe->status=%x " | ||
566 | "ehca_cq=%p cq_num=%x", | ||
567 | cqe->optype, cqe->status, my_cq, my_cq->cq_number); | ||
568 | /* dump cqe for other infos */ | ||
569 | ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x", | ||
570 | my_cq, my_cq->cq_number); | ||
571 | /* update also queue adder to throw away this entry!!! */ | ||
572 | goto poll_cq_one_exit0; | ||
573 | } | ||
574 | /* eval ib_wc_status */ | ||
575 | if (unlikely(cqe->status & WC_STATUS_ERROR_BIT)) { | ||
576 | /* complete with errors */ | ||
577 | map_ib_wc_status(cqe->status, &wc->status); | ||
578 | wc->vendor_err = wc->status; | ||
579 | } else | ||
580 | wc->status = IB_WC_SUCCESS; | ||
581 | |||
582 | wc->qp_num = cqe->local_qp_number; | ||
583 | wc->byte_len = cqe->nr_bytes_transferred; | ||
584 | wc->pkey_index = cqe->pkey_index; | ||
585 | wc->slid = cqe->rlid; | ||
586 | wc->dlid_path_bits = cqe->dlid; | ||
587 | wc->src_qp = cqe->remote_qp_number; | ||
588 | wc->wc_flags = cqe->w_completion_flags; | ||
589 | wc->imm_data = cpu_to_be32(cqe->immediate_data); | ||
590 | wc->sl = cqe->service_level; | ||
591 | |||
592 | if (wc->status != IB_WC_SUCCESS) | ||
593 | ehca_dbg(cq->device, | ||
594 | "ehca_cq=%p cq_num=%x WARNING unsuccessful cqe " | ||
595 | "OPType=%x status=%x qp_num=%x src_qp=%x wr_id=%lx " | ||
596 | "cqe=%p", my_cq, my_cq->cq_number, cqe->optype, | ||
597 | cqe->status, cqe->local_qp_number, | ||
598 | cqe->remote_qp_number, cqe->work_request_id, cqe); | ||
599 | |||
600 | poll_cq_one_exit0: | ||
601 | if (cqe_count > 0) | ||
602 | hipz_update_feca(my_cq, cqe_count); | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) | ||
608 | { | ||
609 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); | ||
610 | int nr; | ||
611 | struct ib_wc *current_wc = wc; | ||
612 | int ret = 0; | ||
613 | unsigned long spl_flags; | ||
614 | |||
615 | if (num_entries < 1) { | ||
616 | ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p " | ||
617 | "cq_num=%x", num_entries, my_cq, my_cq->cq_number); | ||
618 | ret = -EINVAL; | ||
619 | goto poll_cq_exit0; | ||
620 | } | ||
621 | |||
622 | spin_lock_irqsave(&my_cq->spinlock, spl_flags); | ||
623 | for (nr = 0; nr < num_entries; nr++) { | ||
624 | ret = ehca_poll_cq_one(cq, current_wc); | ||
625 | if (ret) | ||
626 | break; | ||
627 | current_wc++; | ||
628 | } /* eof for nr */ | ||
629 | spin_unlock_irqrestore(&my_cq->spinlock, spl_flags); | ||
630 | if (ret == -EAGAIN || !ret) | ||
631 | ret = nr; | ||
632 | |||
633 | poll_cq_exit0: | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify) | ||
638 | { | ||
639 | struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); | ||
640 | |||
641 | switch (cq_notify) { | ||
642 | case IB_CQ_SOLICITED: | ||
643 | hipz_set_cqx_n0(my_cq, 1); | ||
644 | break; | ||
645 | case IB_CQ_NEXT_COMP: | ||
646 | hipz_set_cqx_n1(my_cq, 1); | ||
647 | break; | ||
648 | default: | ||
649 | return -EINVAL; | ||
650 | } | ||
651 | |||
652 | return 0; | ||
653 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c new file mode 100644 index 000000000000..9f16e9c79394 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_sqp.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * SQP functions | ||
5 | * | ||
6 | * Authors: Khadija Souissi <souissi@de.ibm.com> | ||
7 | * Heiko J Schick <schickhj@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | |||
43 | #include <linux/module.h> | ||
44 | #include <linux/err.h> | ||
45 | #include "ehca_classes.h" | ||
46 | #include "ehca_tools.h" | ||
47 | #include "ehca_qes.h" | ||
48 | #include "ehca_iverbs.h" | ||
49 | #include "hcp_if.h" | ||
50 | |||
51 | |||
52 | /** | ||
53 | * ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue | ||
54 | * pair is created successfully, the corresponding port gets active. | ||
55 | * | ||
56 | * Define Special Queue pair 0 (SMI QP) is still not supported. | ||
57 | * | ||
58 | * @qp_init_attr: Queue pair init attributes with port and queue pair type | ||
59 | */ | ||
60 | |||
61 | u64 ehca_define_sqp(struct ehca_shca *shca, | ||
62 | struct ehca_qp *ehca_qp, | ||
63 | struct ib_qp_init_attr *qp_init_attr) | ||
64 | { | ||
65 | u32 pma_qp_nr, bma_qp_nr; | ||
66 | u64 ret; | ||
67 | u8 port = qp_init_attr->port_num; | ||
68 | int counter; | ||
69 | |||
70 | shca->sport[port - 1].port_state = IB_PORT_DOWN; | ||
71 | |||
72 | switch (qp_init_attr->qp_type) { | ||
73 | case IB_QPT_SMI: | ||
74 | /* function not supported yet */ | ||
75 | break; | ||
76 | case IB_QPT_GSI: | ||
77 | ret = hipz_h_define_aqp1(shca->ipz_hca_handle, | ||
78 | ehca_qp->ipz_qp_handle, | ||
79 | ehca_qp->galpas.kernel, | ||
80 | (u32) qp_init_attr->port_num, | ||
81 | &pma_qp_nr, &bma_qp_nr); | ||
82 | |||
83 | if (ret != H_SUCCESS) { | ||
84 | ehca_err(&shca->ib_device, | ||
85 | "Can't define AQP1 for port %x. rc=%lx", | ||
86 | port, ret); | ||
87 | return ret; | ||
88 | } | ||
89 | break; | ||
90 | default: | ||
91 | ehca_err(&shca->ib_device, "invalid qp_type=%x", | ||
92 | qp_init_attr->qp_type); | ||
93 | return H_PARAMETER; | ||
94 | } | ||
95 | |||
96 | for (counter = 0; | ||
97 | shca->sport[port - 1].port_state != IB_PORT_ACTIVE && | ||
98 | counter < ehca_port_act_time; | ||
99 | counter++) { | ||
100 | ehca_dbg(&shca->ib_device, "... wait until port %x is active", | ||
101 | port); | ||
102 | msleep_interruptible(1000); | ||
103 | } | ||
104 | |||
105 | if (counter == ehca_port_act_time) { | ||
106 | ehca_err(&shca->ib_device, "Port %x is not active.", port); | ||
107 | return H_HARDWARE; | ||
108 | } | ||
109 | |||
110 | return H_SUCCESS; | ||
111 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h new file mode 100644 index 000000000000..9f56bb846d93 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_tools.h | |||
@@ -0,0 +1,172 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * auxiliary functions | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Khadija Souissi <souissik@de.ibm.com> | ||
9 | * Waleri Fomin <fomin@de.ibm.com> | ||
10 | * Heiko J Schick <schickhj@de.ibm.com> | ||
11 | * | ||
12 | * Copyright (c) 2005 IBM Corporation | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | |||
44 | #ifndef EHCA_TOOLS_H | ||
45 | #define EHCA_TOOLS_H | ||
46 | |||
47 | #include <linux/kernel.h> | ||
48 | #include <linux/spinlock.h> | ||
49 | #include <linux/delay.h> | ||
50 | #include <linux/idr.h> | ||
51 | #include <linux/kthread.h> | ||
52 | #include <linux/mm.h> | ||
53 | #include <linux/mman.h> | ||
54 | #include <linux/module.h> | ||
55 | #include <linux/moduleparam.h> | ||
56 | #include <linux/vmalloc.h> | ||
57 | #include <linux/version.h> | ||
58 | #include <linux/notifier.h> | ||
59 | #include <linux/cpu.h> | ||
60 | #include <linux/device.h> | ||
61 | |||
62 | #include <asm/abs_addr.h> | ||
63 | #include <asm/ibmebus.h> | ||
64 | #include <asm/io.h> | ||
65 | #include <asm/pgtable.h> | ||
66 | |||
67 | extern int ehca_debug_level; | ||
68 | |||
69 | #define ehca_dbg(ib_dev, format, arg...) \ | ||
70 | do { \ | ||
71 | if (unlikely(ehca_debug_level)) \ | ||
72 | dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \ | ||
73 | "PU%04x EHCA_DBG:%s " format "\n", \ | ||
74 | get_paca()->paca_index, __FUNCTION__, \ | ||
75 | ## arg); \ | ||
76 | } while (0) | ||
77 | |||
78 | #define ehca_info(ib_dev, format, arg...) \ | ||
79 | dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \ | ||
80 | get_paca()->paca_index, __FUNCTION__, ## arg) | ||
81 | |||
82 | #define ehca_warn(ib_dev, format, arg...) \ | ||
83 | dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \ | ||
84 | get_paca()->paca_index, __FUNCTION__, ## arg) | ||
85 | |||
86 | #define ehca_err(ib_dev, format, arg...) \ | ||
87 | dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \ | ||
88 | get_paca()->paca_index, __FUNCTION__, ## arg) | ||
89 | |||
90 | /* use this one only if no ib_dev available */ | ||
91 | #define ehca_gen_dbg(format, arg...) \ | ||
92 | do { \ | ||
93 | if (unlikely(ehca_debug_level)) \ | ||
94 | printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\ | ||
95 | get_paca()->paca_index, __FUNCTION__, ## arg); \ | ||
96 | } while (0) | ||
97 | |||
98 | #define ehca_gen_warn(format, arg...) \ | ||
99 | do { \ | ||
100 | if (unlikely(ehca_debug_level)) \ | ||
101 | printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\ | ||
102 | get_paca()->paca_index, __FUNCTION__, ## arg); \ | ||
103 | } while (0) | ||
104 | |||
105 | #define ehca_gen_err(format, arg...) \ | ||
106 | printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \ | ||
107 | get_paca()->paca_index, __FUNCTION__, ## arg) | ||
108 | |||
109 | /** | ||
110 | * ehca_dmp - printk a memory block, whose length is n*8 bytes. | ||
111 | * Each line has the following layout: | ||
112 | * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex> | ||
113 | */ | ||
114 | #define ehca_dmp(adr, len, format, args...) \ | ||
115 | do { \ | ||
116 | unsigned int x; \ | ||
117 | unsigned int l = (unsigned int)(len); \ | ||
118 | unsigned char *deb = (unsigned char*)(adr); \ | ||
119 | for (x = 0; x < l; x += 16) { \ | ||
120 | printk("EHCA_DMP:%s" format \ | ||
121 | " adr=%p ofs=%04x %016lx %016lx\n", \ | ||
122 | __FUNCTION__, ##args, deb, x, \ | ||
123 | *((u64 *)&deb[0]), *((u64 *)&deb[8])); \ | ||
124 | deb += 16; \ | ||
125 | } \ | ||
126 | } while (0) | ||
127 | |||
128 | /* define a bitmask, little endian version */ | ||
129 | #define EHCA_BMASK(pos,length) (((pos)<<16)+(length)) | ||
130 | |||
131 | /* define a bitmask, the ibm way... */ | ||
132 | #define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1)) | ||
133 | |||
134 | /* internal function, don't use */ | ||
135 | #define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff) | ||
136 | |||
137 | /* internal function, don't use */ | ||
138 | #define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff)) | ||
139 | |||
140 | /** | ||
141 | * EHCA_BMASK_SET - return value shifted and masked by mask | ||
142 | * variable|=EHCA_BMASK_SET(MY_MASK,0x4711) ORs the bits in variable | ||
143 | * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask | ||
144 | * in variable | ||
145 | */ | ||
146 | #define EHCA_BMASK_SET(mask,value) \ | ||
147 | ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask)) | ||
148 | |||
149 | /** | ||
150 | * EHCA_BMASK_GET - extract a parameter from value by mask | ||
151 | */ | ||
152 | #define EHCA_BMASK_GET(mask,value) \ | ||
153 | (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask))) | ||
154 | |||
155 | |||
156 | /* Converts ehca to ib return code */ | ||
157 | static inline int ehca2ib_return_code(u64 ehca_rc) | ||
158 | { | ||
159 | switch (ehca_rc) { | ||
160 | case H_SUCCESS: | ||
161 | return 0; | ||
162 | case H_BUSY: | ||
163 | return -EBUSY; | ||
164 | case H_NO_MEM: | ||
165 | return -ENOMEM; | ||
166 | default: | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | |||
172 | #endif /* EHCA_TOOLS_H */ | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c new file mode 100644 index 000000000000..e08764e4aef2 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * userspace support verbs | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Heiko J Schick <schickhj@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | #include <asm/current.h> | ||
44 | |||
45 | #include "ehca_classes.h" | ||
46 | #include "ehca_iverbs.h" | ||
47 | #include "ehca_mrmw.h" | ||
48 | #include "ehca_tools.h" | ||
49 | #include "hcp_if.h" | ||
50 | |||
51 | struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device, | ||
52 | struct ib_udata *udata) | ||
53 | { | ||
54 | struct ehca_ucontext *my_context; | ||
55 | |||
56 | my_context = kzalloc(sizeof *my_context, GFP_KERNEL); | ||
57 | if (!my_context) { | ||
58 | ehca_err(device, "Out of memory device=%p", device); | ||
59 | return ERR_PTR(-ENOMEM); | ||
60 | } | ||
61 | |||
62 | return &my_context->ib_ucontext; | ||
63 | } | ||
64 | |||
65 | int ehca_dealloc_ucontext(struct ib_ucontext *context) | ||
66 | { | ||
67 | kfree(container_of(context, struct ehca_ucontext, ib_ucontext)); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | struct page *ehca_nopage(struct vm_area_struct *vma, | ||
72 | unsigned long address, int *type) | ||
73 | { | ||
74 | struct page *mypage = NULL; | ||
75 | u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT; | ||
76 | u32 idr_handle = fileoffset >> 32; | ||
77 | u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */ | ||
78 | u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ | ||
79 | u32 cur_pid = current->tgid; | ||
80 | unsigned long flags; | ||
81 | struct ehca_cq *cq; | ||
82 | struct ehca_qp *qp; | ||
83 | struct ehca_pd *pd; | ||
84 | u64 offset; | ||
85 | void *vaddr; | ||
86 | |||
87 | switch (q_type) { | ||
88 | case 1: /* CQ */ | ||
89 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | ||
90 | cq = idr_find(&ehca_cq_idr, idr_handle); | ||
91 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | ||
92 | |||
93 | /* make sure this mmap really belongs to the authorized user */ | ||
94 | if (!cq) { | ||
95 | ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS"); | ||
96 | return NOPAGE_SIGBUS; | ||
97 | } | ||
98 | |||
99 | if (cq->ownpid != cur_pid) { | ||
100 | ehca_err(cq->ib_cq.device, | ||
101 | "Invalid caller pid=%x ownpid=%x", | ||
102 | cur_pid, cq->ownpid); | ||
103 | return NOPAGE_SIGBUS; | ||
104 | } | ||
105 | |||
106 | if (rsrc_type == 2) { | ||
107 | ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq); | ||
108 | offset = address - vma->vm_start; | ||
109 | vaddr = ipz_qeit_calc(&cq->ipz_queue, offset); | ||
110 | ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p", | ||
111 | offset, vaddr); | ||
112 | mypage = virt_to_page(vaddr); | ||
113 | } | ||
114 | break; | ||
115 | |||
116 | case 2: /* QP */ | ||
117 | spin_lock_irqsave(&ehca_qp_idr_lock, flags); | ||
118 | qp = idr_find(&ehca_qp_idr, idr_handle); | ||
119 | spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); | ||
120 | |||
121 | /* make sure this mmap really belongs to the authorized user */ | ||
122 | if (!qp) { | ||
123 | ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS"); | ||
124 | return NOPAGE_SIGBUS; | ||
125 | } | ||
126 | |||
127 | pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd); | ||
128 | if (pd->ownpid != cur_pid) { | ||
129 | ehca_err(qp->ib_qp.device, | ||
130 | "Invalid caller pid=%x ownpid=%x", | ||
131 | cur_pid, pd->ownpid); | ||
132 | return NOPAGE_SIGBUS; | ||
133 | } | ||
134 | |||
135 | if (rsrc_type == 2) { /* rqueue */ | ||
136 | ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp); | ||
137 | offset = address - vma->vm_start; | ||
138 | vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset); | ||
139 | ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p", | ||
140 | offset, vaddr); | ||
141 | mypage = virt_to_page(vaddr); | ||
142 | } else if (rsrc_type == 3) { /* squeue */ | ||
143 | ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp); | ||
144 | offset = address - vma->vm_start; | ||
145 | vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset); | ||
146 | ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p", | ||
147 | offset, vaddr); | ||
148 | mypage = virt_to_page(vaddr); | ||
149 | } | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | ehca_gen_err("bad queue type %x", q_type); | ||
154 | return NOPAGE_SIGBUS; | ||
155 | } | ||
156 | |||
157 | if (!mypage) { | ||
158 | ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS"); | ||
159 | return NOPAGE_SIGBUS; | ||
160 | } | ||
161 | get_page(mypage); | ||
162 | |||
163 | return mypage; | ||
164 | } | ||
165 | |||
166 | static struct vm_operations_struct ehcau_vm_ops = { | ||
167 | .nopage = ehca_nopage, | ||
168 | }; | ||
169 | |||
170 | int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) | ||
171 | { | ||
172 | u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT; | ||
173 | u32 idr_handle = fileoffset >> 32; | ||
174 | u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */ | ||
175 | u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ | ||
176 | u32 cur_pid = current->tgid; | ||
177 | u32 ret; | ||
178 | u64 vsize, physical; | ||
179 | unsigned long flags; | ||
180 | struct ehca_cq *cq; | ||
181 | struct ehca_qp *qp; | ||
182 | struct ehca_pd *pd; | ||
183 | |||
184 | switch (q_type) { | ||
185 | case 1: /* CQ */ | ||
186 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | ||
187 | cq = idr_find(&ehca_cq_idr, idr_handle); | ||
188 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | ||
189 | |||
190 | /* make sure this mmap really belongs to the authorized user */ | ||
191 | if (!cq) | ||
192 | return -EINVAL; | ||
193 | |||
194 | if (cq->ownpid != cur_pid) { | ||
195 | ehca_err(cq->ib_cq.device, | ||
196 | "Invalid caller pid=%x ownpid=%x", | ||
197 | cur_pid, cq->ownpid); | ||
198 | return -ENOMEM; | ||
199 | } | ||
200 | |||
201 | if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context) | ||
202 | return -EINVAL; | ||
203 | |||
204 | switch (rsrc_type) { | ||
205 | case 1: /* galpa fw handle */ | ||
206 | ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq); | ||
207 | vma->vm_flags |= VM_RESERVED; | ||
208 | vsize = vma->vm_end - vma->vm_start; | ||
209 | if (vsize != EHCA_PAGESIZE) { | ||
210 | ehca_err(cq->ib_cq.device, "invalid vsize=%lx", | ||
211 | vma->vm_end - vma->vm_start); | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | physical = cq->galpas.user.fw_handle; | ||
216 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
217 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
218 | |||
219 | ehca_dbg(cq->ib_cq.device, | ||
220 | "vsize=%lx physical=%lx", vsize, physical); | ||
221 | ret = remap_pfn_range(vma, vma->vm_start, | ||
222 | physical >> PAGE_SHIFT, vsize, | ||
223 | vma->vm_page_prot); | ||
224 | if (ret) { | ||
225 | ehca_err(cq->ib_cq.device, | ||
226 | "remap_pfn_range() failed ret=%x", | ||
227 | ret); | ||
228 | return -ENOMEM; | ||
229 | } | ||
230 | break; | ||
231 | |||
232 | case 2: /* cq queue_addr */ | ||
233 | ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq); | ||
234 | vma->vm_flags |= VM_RESERVED; | ||
235 | vma->vm_ops = &ehcau_vm_ops; | ||
236 | break; | ||
237 | |||
238 | default: | ||
239 | ehca_err(cq->ib_cq.device, "bad resource type %x", | ||
240 | rsrc_type); | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | break; | ||
244 | |||
245 | case 2: /* QP */ | ||
246 | spin_lock_irqsave(&ehca_qp_idr_lock, flags); | ||
247 | qp = idr_find(&ehca_qp_idr, idr_handle); | ||
248 | spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); | ||
249 | |||
250 | /* make sure this mmap really belongs to the authorized user */ | ||
251 | if (!qp) | ||
252 | return -EINVAL; | ||
253 | |||
254 | pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd); | ||
255 | if (pd->ownpid != cur_pid) { | ||
256 | ehca_err(qp->ib_qp.device, | ||
257 | "Invalid caller pid=%x ownpid=%x", | ||
258 | cur_pid, pd->ownpid); | ||
259 | return -ENOMEM; | ||
260 | } | ||
261 | |||
262 | if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context) | ||
263 | return -EINVAL; | ||
264 | |||
265 | switch (rsrc_type) { | ||
266 | case 1: /* galpa fw handle */ | ||
267 | ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp); | ||
268 | vma->vm_flags |= VM_RESERVED; | ||
269 | vsize = vma->vm_end - vma->vm_start; | ||
270 | if (vsize != EHCA_PAGESIZE) { | ||
271 | ehca_err(qp->ib_qp.device, "invalid vsize=%lx", | ||
272 | vma->vm_end - vma->vm_start); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | physical = qp->galpas.user.fw_handle; | ||
277 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
278 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
279 | |||
280 | ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx", | ||
281 | vsize, physical); | ||
282 | ret = remap_pfn_range(vma, vma->vm_start, | ||
283 | physical >> PAGE_SHIFT, vsize, | ||
284 | vma->vm_page_prot); | ||
285 | if (ret) { | ||
286 | ehca_err(qp->ib_qp.device, | ||
287 | "remap_pfn_range() failed ret=%x", | ||
288 | ret); | ||
289 | return -ENOMEM; | ||
290 | } | ||
291 | break; | ||
292 | |||
293 | case 2: /* qp rqueue_addr */ | ||
294 | ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp); | ||
295 | vma->vm_flags |= VM_RESERVED; | ||
296 | vma->vm_ops = &ehcau_vm_ops; | ||
297 | break; | ||
298 | |||
299 | case 3: /* qp squeue_addr */ | ||
300 | ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp); | ||
301 | vma->vm_flags |= VM_RESERVED; | ||
302 | vma->vm_ops = &ehcau_vm_ops; | ||
303 | break; | ||
304 | |||
305 | default: | ||
306 | ehca_err(qp->ib_qp.device, "bad resource type %x", | ||
307 | rsrc_type); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | break; | ||
311 | |||
312 | default: | ||
313 | ehca_gen_err("bad queue type %x", q_type); | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped, | ||
321 | struct vm_area_struct **vma) | ||
322 | { | ||
323 | down_write(¤t->mm->mmap_sem); | ||
324 | *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE, | ||
325 | MAP_SHARED | MAP_ANONYMOUS, | ||
326 | foffset); | ||
327 | up_write(¤t->mm->mmap_sem); | ||
328 | if (!(*mapped)) { | ||
329 | ehca_gen_err("couldn't mmap foffset=%lx length=%lx", | ||
330 | foffset, length); | ||
331 | return -EINVAL; | ||
332 | } | ||
333 | |||
334 | *vma = find_vma(current->mm, (u64)*mapped); | ||
335 | if (!(*vma)) { | ||
336 | down_write(¤t->mm->mmap_sem); | ||
337 | do_munmap(current->mm, 0, length); | ||
338 | up_write(¤t->mm->mmap_sem); | ||
339 | ehca_gen_err("couldn't find vma queue=%p", *mapped); | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | (*vma)->vm_flags |= VM_RESERVED; | ||
343 | (*vma)->vm_ops = &ehcau_vm_ops; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | int ehca_mmap_register(u64 physical, void **mapped, | ||
349 | struct vm_area_struct **vma) | ||
350 | { | ||
351 | int ret; | ||
352 | unsigned long vsize; | ||
353 | /* ehca hw supports only 4k page */ | ||
354 | ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma); | ||
355 | if (ret) { | ||
356 | ehca_gen_err("could'nt mmap physical=%lx", physical); | ||
357 | return ret; | ||
358 | } | ||
359 | |||
360 | (*vma)->vm_flags |= VM_RESERVED; | ||
361 | vsize = (*vma)->vm_end - (*vma)->vm_start; | ||
362 | if (vsize != EHCA_PAGESIZE) { | ||
363 | ehca_gen_err("invalid vsize=%lx", | ||
364 | (*vma)->vm_end - (*vma)->vm_start); | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | |||
368 | (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot); | ||
369 | (*vma)->vm_flags |= VM_IO | VM_RESERVED; | ||
370 | |||
371 | ret = remap_pfn_range((*vma), (*vma)->vm_start, | ||
372 | physical >> PAGE_SHIFT, vsize, | ||
373 | (*vma)->vm_page_prot); | ||
374 | if (ret) { | ||
375 | ehca_gen_err("remap_pfn_range() failed ret=%x", ret); | ||
376 | return -ENOMEM; | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | |||
381 | } | ||
382 | |||
383 | int ehca_munmap(unsigned long addr, size_t len) { | ||
384 | int ret = 0; | ||
385 | struct mm_struct *mm = current->mm; | ||
386 | if (mm) { | ||
387 | down_write(&mm->mmap_sem); | ||
388 | ret = do_munmap(mm, addr, len); | ||
389 | up_write(&mm->mmap_sem); | ||
390 | } | ||
391 | return ret; | ||
392 | } | ||
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c new file mode 100644 index 000000000000..3fb46e67df87 --- /dev/null +++ b/drivers/infiniband/hw/ehca/hcp_if.c | |||
@@ -0,0 +1,874 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Firmware Infiniband Interface code for POWER | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Gerd Bayer <gerd.bayer@de.ibm.com> | ||
9 | * Waleri Fomin <fomin@de.ibm.com> | ||
10 | * | ||
11 | * Copyright (c) 2005 IBM Corporation | ||
12 | * | ||
13 | * All rights reserved. | ||
14 | * | ||
15 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
16 | * BSD. | ||
17 | * | ||
18 | * OpenIB BSD License | ||
19 | * | ||
20 | * Redistribution and use in source and binary forms, with or without | ||
21 | * modification, are permitted provided that the following conditions are met: | ||
22 | * | ||
23 | * Redistributions of source code must retain the above copyright notice, this | ||
24 | * list of conditions and the following disclaimer. | ||
25 | * | ||
26 | * Redistributions in binary form must reproduce the above copyright notice, | ||
27 | * this list of conditions and the following disclaimer in the documentation | ||
28 | * and/or other materials | ||
29 | * provided with the distribution. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
32 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
34 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
35 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
36 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
37 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
38 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
39 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | */ | ||
43 | |||
44 | #include <asm/hvcall.h> | ||
45 | #include "ehca_tools.h" | ||
46 | #include "hcp_if.h" | ||
47 | #include "hcp_phyp.h" | ||
48 | #include "hipz_fns.h" | ||
49 | #include "ipz_pt_fn.h" | ||
50 | |||
51 | #define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11) | ||
52 | #define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12) | ||
53 | #define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15) | ||
54 | #define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18) | ||
55 | #define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21) | ||
56 | #define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23) | ||
57 | #define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31) | ||
58 | #define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63) | ||
59 | |||
60 | #define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15) | ||
61 | #define H_ALL_RES_QP_MAX_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31) | ||
62 | #define H_ALL_RES_QP_MAX_SEND_SGE EHCA_BMASK_IBM(32, 39) | ||
63 | #define H_ALL_RES_QP_MAX_RECV_SGE EHCA_BMASK_IBM(40, 47) | ||
64 | |||
65 | #define H_ALL_RES_QP_ACT_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31) | ||
66 | #define H_ALL_RES_QP_ACT_OUTST_RECV_WR EHCA_BMASK_IBM(48, 63) | ||
67 | #define H_ALL_RES_QP_ACT_SEND_SGE EHCA_BMASK_IBM(8, 15) | ||
68 | #define H_ALL_RES_QP_ACT_RECV_SGE EHCA_BMASK_IBM(24, 31) | ||
69 | |||
70 | #define H_ALL_RES_QP_SQUEUE_SIZE_PAGES EHCA_BMASK_IBM(0, 31) | ||
71 | #define H_ALL_RES_QP_RQUEUE_SIZE_PAGES EHCA_BMASK_IBM(32, 63) | ||
72 | |||
73 | /* direct access qp controls */ | ||
74 | #define DAQP_CTRL_ENABLE 0x01 | ||
75 | #define DAQP_CTRL_SEND_COMP 0x20 | ||
76 | #define DAQP_CTRL_RECV_COMP 0x40 | ||
77 | |||
78 | static u32 get_longbusy_msecs(int longbusy_rc) | ||
79 | { | ||
80 | switch (longbusy_rc) { | ||
81 | case H_LONG_BUSY_ORDER_1_MSEC: | ||
82 | return 1; | ||
83 | case H_LONG_BUSY_ORDER_10_MSEC: | ||
84 | return 10; | ||
85 | case H_LONG_BUSY_ORDER_100_MSEC: | ||
86 | return 100; | ||
87 | case H_LONG_BUSY_ORDER_1_SEC: | ||
88 | return 1000; | ||
89 | case H_LONG_BUSY_ORDER_10_SEC: | ||
90 | return 10000; | ||
91 | case H_LONG_BUSY_ORDER_100_SEC: | ||
92 | return 100000; | ||
93 | default: | ||
94 | return 1; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static long ehca_plpar_hcall_norets(unsigned long opcode, | ||
99 | unsigned long arg1, | ||
100 | unsigned long arg2, | ||
101 | unsigned long arg3, | ||
102 | unsigned long arg4, | ||
103 | unsigned long arg5, | ||
104 | unsigned long arg6, | ||
105 | unsigned long arg7) | ||
106 | { | ||
107 | long ret; | ||
108 | int i, sleep_msecs; | ||
109 | |||
110 | ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx " | ||
111 | "arg5=%lx arg6=%lx arg7=%lx", | ||
112 | opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); | ||
113 | |||
114 | for (i = 0; i < 5; i++) { | ||
115 | ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, | ||
116 | arg5, arg6, arg7); | ||
117 | |||
118 | if (H_IS_LONG_BUSY(ret)) { | ||
119 | sleep_msecs = get_longbusy_msecs(ret); | ||
120 | msleep_interruptible(sleep_msecs); | ||
121 | continue; | ||
122 | } | ||
123 | |||
124 | if (ret < H_SUCCESS) | ||
125 | ehca_gen_err("opcode=%lx ret=%lx" | ||
126 | " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" | ||
127 | " arg5=%lx arg6=%lx arg7=%lx ", | ||
128 | opcode, ret, | ||
129 | arg1, arg2, arg3, arg4, arg5, | ||
130 | arg6, arg7); | ||
131 | |||
132 | ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret); | ||
133 | return ret; | ||
134 | |||
135 | } | ||
136 | |||
137 | return H_BUSY; | ||
138 | } | ||
139 | |||
140 | static long ehca_plpar_hcall9(unsigned long opcode, | ||
141 | unsigned long *outs, /* array of 9 outputs */ | ||
142 | unsigned long arg1, | ||
143 | unsigned long arg2, | ||
144 | unsigned long arg3, | ||
145 | unsigned long arg4, | ||
146 | unsigned long arg5, | ||
147 | unsigned long arg6, | ||
148 | unsigned long arg7, | ||
149 | unsigned long arg8, | ||
150 | unsigned long arg9) | ||
151 | { | ||
152 | long ret; | ||
153 | int i, sleep_msecs; | ||
154 | |||
155 | ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx " | ||
156 | "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx", | ||
157 | opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, | ||
158 | arg8, arg9); | ||
159 | |||
160 | for (i = 0; i < 5; i++) { | ||
161 | ret = plpar_hcall9(opcode, outs, | ||
162 | arg1, arg2, arg3, arg4, arg5, | ||
163 | arg6, arg7, arg8, arg9); | ||
164 | |||
165 | if (H_IS_LONG_BUSY(ret)) { | ||
166 | sleep_msecs = get_longbusy_msecs(ret); | ||
167 | msleep_interruptible(sleep_msecs); | ||
168 | continue; | ||
169 | } | ||
170 | |||
171 | if (ret < H_SUCCESS) | ||
172 | ehca_gen_err("opcode=%lx ret=%lx" | ||
173 | " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" | ||
174 | " arg5=%lx arg6=%lx arg7=%lx arg8=%lx" | ||
175 | " arg9=%lx" | ||
176 | " out1=%lx out2=%lx out3=%lx out4=%lx" | ||
177 | " out5=%lx out6=%lx out7=%lx out8=%lx" | ||
178 | " out9=%lx", | ||
179 | opcode, ret, | ||
180 | arg1, arg2, arg3, arg4, arg5, | ||
181 | arg6, arg7, arg8, arg9, | ||
182 | outs[0], outs[1], outs[2], outs[3], | ||
183 | outs[4], outs[5], outs[6], outs[7], | ||
184 | outs[8]); | ||
185 | |||
186 | ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx " | ||
187 | "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx " | ||
188 | "out9=%lx", | ||
189 | opcode, ret, outs[0], outs[1], outs[2], outs[3], | ||
190 | outs[4], outs[5], outs[6], outs[7], outs[8]); | ||
191 | return ret; | ||
192 | |||
193 | } | ||
194 | |||
195 | return H_BUSY; | ||
196 | } | ||
197 | u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle, | ||
198 | struct ehca_pfeq *pfeq, | ||
199 | const u32 neq_control, | ||
200 | const u32 number_of_entries, | ||
201 | struct ipz_eq_handle *eq_handle, | ||
202 | u32 *act_nr_of_entries, | ||
203 | u32 *act_pages, | ||
204 | u32 *eq_ist) | ||
205 | { | ||
206 | u64 ret; | ||
207 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
208 | u64 allocate_controls; | ||
209 | |||
210 | /* resource type */ | ||
211 | allocate_controls = 3ULL; | ||
212 | |||
213 | /* ISN is associated */ | ||
214 | if (neq_control != 1) | ||
215 | allocate_controls = (1ULL << (63 - 7)) | allocate_controls; | ||
216 | else /* notification event queue */ | ||
217 | allocate_controls = (1ULL << 63) | allocate_controls; | ||
218 | |||
219 | ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, | ||
220 | adapter_handle.handle, /* r4 */ | ||
221 | allocate_controls, /* r5 */ | ||
222 | number_of_entries, /* r6 */ | ||
223 | 0, 0, 0, 0, 0, 0); | ||
224 | eq_handle->handle = outs[0]; | ||
225 | *act_nr_of_entries = (u32)outs[3]; | ||
226 | *act_pages = (u32)outs[4]; | ||
227 | *eq_ist = (u32)outs[5]; | ||
228 | |||
229 | if (ret == H_NOT_ENOUGH_RESOURCES) | ||
230 | ehca_gen_err("Not enough resource - ret=%lx ", ret); | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle, | ||
236 | struct ipz_eq_handle eq_handle, | ||
237 | const u64 event_mask) | ||
238 | { | ||
239 | return ehca_plpar_hcall_norets(H_RESET_EVENTS, | ||
240 | adapter_handle.handle, /* r4 */ | ||
241 | eq_handle.handle, /* r5 */ | ||
242 | event_mask, /* r6 */ | ||
243 | 0, 0, 0, 0); | ||
244 | } | ||
245 | |||
246 | u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, | ||
247 | struct ehca_cq *cq, | ||
248 | struct ehca_alloc_cq_parms *param) | ||
249 | { | ||
250 | u64 ret; | ||
251 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
252 | |||
253 | ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, | ||
254 | adapter_handle.handle, /* r4 */ | ||
255 | 2, /* r5 */ | ||
256 | param->eq_handle.handle, /* r6 */ | ||
257 | cq->token, /* r7 */ | ||
258 | param->nr_cqe, /* r8 */ | ||
259 | 0, 0, 0, 0); | ||
260 | cq->ipz_cq_handle.handle = outs[0]; | ||
261 | param->act_nr_of_entries = (u32)outs[3]; | ||
262 | param->act_pages = (u32)outs[4]; | ||
263 | |||
264 | if (ret == H_SUCCESS) | ||
265 | hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]); | ||
266 | |||
267 | if (ret == H_NOT_ENOUGH_RESOURCES) | ||
268 | ehca_gen_err("Not enough resources. ret=%lx", ret); | ||
269 | |||
270 | return ret; | ||
271 | } | ||
272 | |||
273 | u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, | ||
274 | struct ehca_qp *qp, | ||
275 | struct ehca_alloc_qp_parms *parms) | ||
276 | { | ||
277 | u64 ret; | ||
278 | u64 allocate_controls; | ||
279 | u64 max_r10_reg; | ||
280 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
281 | u16 max_nr_receive_wqes = qp->init_attr.cap.max_recv_wr + 1; | ||
282 | u16 max_nr_send_wqes = qp->init_attr.cap.max_send_wr + 1; | ||
283 | int daqp_ctrl = parms->daqp_ctrl; | ||
284 | |||
285 | allocate_controls = | ||
286 | EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS, | ||
287 | (daqp_ctrl & DAQP_CTRL_ENABLE) ? 1 : 0) | ||
288 | | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0) | ||
289 | | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype) | ||
290 | | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype) | ||
291 | | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING, | ||
292 | (daqp_ctrl & DAQP_CTRL_RECV_COMP) ? 1 : 0) | ||
293 | | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING, | ||
294 | (daqp_ctrl & DAQP_CTRL_SEND_COMP) ? 1 : 0) | ||
295 | | EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL, | ||
296 | parms->ud_av_l_key_ctl) | ||
297 | | EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1); | ||
298 | |||
299 | max_r10_reg = | ||
300 | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR, | ||
301 | max_nr_send_wqes) | ||
302 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR, | ||
303 | max_nr_receive_wqes) | ||
304 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE, | ||
305 | parms->max_send_sge) | ||
306 | | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE, | ||
307 | parms->max_recv_sge); | ||
308 | |||
309 | ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, | ||
310 | adapter_handle.handle, /* r4 */ | ||
311 | allocate_controls, /* r5 */ | ||
312 | qp->send_cq->ipz_cq_handle.handle, | ||
313 | qp->recv_cq->ipz_cq_handle.handle, | ||
314 | parms->ipz_eq_handle.handle, | ||
315 | ((u64)qp->token << 32) | parms->pd.value, | ||
316 | max_r10_reg, /* r10 */ | ||
317 | parms->ud_av_l_key_ctl, /* r11 */ | ||
318 | 0); | ||
319 | qp->ipz_qp_handle.handle = outs[0]; | ||
320 | qp->real_qp_num = (u32)outs[1]; | ||
321 | parms->act_nr_send_sges = | ||
322 | (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]); | ||
323 | parms->act_nr_recv_wqes = | ||
324 | (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]); | ||
325 | parms->act_nr_send_sges = | ||
326 | (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]); | ||
327 | parms->act_nr_recv_sges = | ||
328 | (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]); | ||
329 | parms->nr_sq_pages = | ||
330 | (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]); | ||
331 | parms->nr_rq_pages = | ||
332 | (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]); | ||
333 | |||
334 | if (ret == H_SUCCESS) | ||
335 | hcp_galpas_ctor(&qp->galpas, outs[6], outs[6]); | ||
336 | |||
337 | if (ret == H_NOT_ENOUGH_RESOURCES) | ||
338 | ehca_gen_err("Not enough resources. ret=%lx", ret); | ||
339 | |||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, | ||
344 | const u8 port_id, | ||
345 | struct hipz_query_port *query_port_response_block) | ||
346 | { | ||
347 | u64 ret; | ||
348 | u64 r_cb = virt_to_abs(query_port_response_block); | ||
349 | |||
350 | if (r_cb & (EHCA_PAGESIZE-1)) { | ||
351 | ehca_gen_err("response block not page aligned"); | ||
352 | return H_PARAMETER; | ||
353 | } | ||
354 | |||
355 | ret = ehca_plpar_hcall_norets(H_QUERY_PORT, | ||
356 | adapter_handle.handle, /* r4 */ | ||
357 | port_id, /* r5 */ | ||
358 | r_cb, /* r6 */ | ||
359 | 0, 0, 0, 0); | ||
360 | |||
361 | if (ehca_debug_level) | ||
362 | ehca_dmp(query_port_response_block, 64, "response_block"); | ||
363 | |||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle, | ||
368 | struct hipz_query_hca *query_hca_rblock) | ||
369 | { | ||
370 | u64 r_cb = virt_to_abs(query_hca_rblock); | ||
371 | |||
372 | if (r_cb & (EHCA_PAGESIZE-1)) { | ||
373 | ehca_gen_err("response_block=%p not page aligned", | ||
374 | query_hca_rblock); | ||
375 | return H_PARAMETER; | ||
376 | } | ||
377 | |||
378 | return ehca_plpar_hcall_norets(H_QUERY_HCA, | ||
379 | adapter_handle.handle, /* r4 */ | ||
380 | r_cb, /* r5 */ | ||
381 | 0, 0, 0, 0, 0); | ||
382 | } | ||
383 | |||
384 | u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle, | ||
385 | const u8 pagesize, | ||
386 | const u8 queue_type, | ||
387 | const u64 resource_handle, | ||
388 | const u64 logical_address_of_page, | ||
389 | u64 count) | ||
390 | { | ||
391 | return ehca_plpar_hcall_norets(H_REGISTER_RPAGES, | ||
392 | adapter_handle.handle, /* r4 */ | ||
393 | queue_type | pagesize << 8, /* r5 */ | ||
394 | resource_handle, /* r6 */ | ||
395 | logical_address_of_page, /* r7 */ | ||
396 | count, /* r8 */ | ||
397 | 0, 0); | ||
398 | } | ||
399 | |||
400 | u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle, | ||
401 | const struct ipz_eq_handle eq_handle, | ||
402 | struct ehca_pfeq *pfeq, | ||
403 | const u8 pagesize, | ||
404 | const u8 queue_type, | ||
405 | const u64 logical_address_of_page, | ||
406 | const u64 count) | ||
407 | { | ||
408 | if (count != 1) { | ||
409 | ehca_gen_err("Ppage counter=%lx", count); | ||
410 | return H_PARAMETER; | ||
411 | } | ||
412 | return hipz_h_register_rpage(adapter_handle, | ||
413 | pagesize, | ||
414 | queue_type, | ||
415 | eq_handle.handle, | ||
416 | logical_address_of_page, count); | ||
417 | } | ||
418 | |||
419 | u64 hipz_h_query_int_state(const struct ipz_adapter_handle adapter_handle, | ||
420 | u32 ist) | ||
421 | { | ||
422 | u64 ret; | ||
423 | ret = ehca_plpar_hcall_norets(H_QUERY_INT_STATE, | ||
424 | adapter_handle.handle, /* r4 */ | ||
425 | ist, /* r5 */ | ||
426 | 0, 0, 0, 0, 0); | ||
427 | |||
428 | if (ret != H_SUCCESS && ret != H_BUSY) | ||
429 | ehca_gen_err("Could not query interrupt state."); | ||
430 | |||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle, | ||
435 | const struct ipz_cq_handle cq_handle, | ||
436 | struct ehca_pfcq *pfcq, | ||
437 | const u8 pagesize, | ||
438 | const u8 queue_type, | ||
439 | const u64 logical_address_of_page, | ||
440 | const u64 count, | ||
441 | const struct h_galpa gal) | ||
442 | { | ||
443 | if (count != 1) { | ||
444 | ehca_gen_err("Page counter=%lx", count); | ||
445 | return H_PARAMETER; | ||
446 | } | ||
447 | |||
448 | return hipz_h_register_rpage(adapter_handle, pagesize, queue_type, | ||
449 | cq_handle.handle, logical_address_of_page, | ||
450 | count); | ||
451 | } | ||
452 | |||
453 | u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle, | ||
454 | const struct ipz_qp_handle qp_handle, | ||
455 | struct ehca_pfqp *pfqp, | ||
456 | const u8 pagesize, | ||
457 | const u8 queue_type, | ||
458 | const u64 logical_address_of_page, | ||
459 | const u64 count, | ||
460 | const struct h_galpa galpa) | ||
461 | { | ||
462 | if (count != 1) { | ||
463 | ehca_gen_err("Page counter=%lx", count); | ||
464 | return H_PARAMETER; | ||
465 | } | ||
466 | |||
467 | return hipz_h_register_rpage(adapter_handle,pagesize,queue_type, | ||
468 | qp_handle.handle,logical_address_of_page, | ||
469 | count); | ||
470 | } | ||
471 | |||
472 | u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle, | ||
473 | const struct ipz_qp_handle qp_handle, | ||
474 | struct ehca_pfqp *pfqp, | ||
475 | void **log_addr_next_sq_wqe2processed, | ||
476 | void **log_addr_next_rq_wqe2processed, | ||
477 | int dis_and_get_function_code) | ||
478 | { | ||
479 | u64 ret; | ||
480 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
481 | |||
482 | ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs, | ||
483 | adapter_handle.handle, /* r4 */ | ||
484 | dis_and_get_function_code, /* r5 */ | ||
485 | qp_handle.handle, /* r6 */ | ||
486 | 0, 0, 0, 0, 0, 0); | ||
487 | if (log_addr_next_sq_wqe2processed) | ||
488 | *log_addr_next_sq_wqe2processed = (void*)outs[0]; | ||
489 | if (log_addr_next_rq_wqe2processed) | ||
490 | *log_addr_next_rq_wqe2processed = (void*)outs[1]; | ||
491 | |||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle, | ||
496 | const struct ipz_qp_handle qp_handle, | ||
497 | struct ehca_pfqp *pfqp, | ||
498 | const u64 update_mask, | ||
499 | struct hcp_modify_qp_control_block *mqpcb, | ||
500 | struct h_galpa gal) | ||
501 | { | ||
502 | u64 ret; | ||
503 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
504 | ret = ehca_plpar_hcall9(H_MODIFY_QP, outs, | ||
505 | adapter_handle.handle, /* r4 */ | ||
506 | qp_handle.handle, /* r5 */ | ||
507 | update_mask, /* r6 */ | ||
508 | virt_to_abs(mqpcb), /* r7 */ | ||
509 | 0, 0, 0, 0, 0); | ||
510 | |||
511 | if (ret == H_NOT_ENOUGH_RESOURCES) | ||
512 | ehca_gen_err("Insufficient resources ret=%lx", ret); | ||
513 | |||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle, | ||
518 | const struct ipz_qp_handle qp_handle, | ||
519 | struct ehca_pfqp *pfqp, | ||
520 | struct hcp_modify_qp_control_block *qqpcb, | ||
521 | struct h_galpa gal) | ||
522 | { | ||
523 | return ehca_plpar_hcall_norets(H_QUERY_QP, | ||
524 | adapter_handle.handle, /* r4 */ | ||
525 | qp_handle.handle, /* r5 */ | ||
526 | virt_to_abs(qqpcb), /* r6 */ | ||
527 | 0, 0, 0, 0); | ||
528 | } | ||
529 | |||
530 | u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle, | ||
531 | struct ehca_qp *qp) | ||
532 | { | ||
533 | u64 ret; | ||
534 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
535 | |||
536 | ret = hcp_galpas_dtor(&qp->galpas); | ||
537 | if (ret) { | ||
538 | ehca_gen_err("Could not destruct qp->galpas"); | ||
539 | return H_RESOURCE; | ||
540 | } | ||
541 | ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs, | ||
542 | adapter_handle.handle, /* r4 */ | ||
543 | /* function code */ | ||
544 | 1, /* r5 */ | ||
545 | qp->ipz_qp_handle.handle, /* r6 */ | ||
546 | 0, 0, 0, 0, 0, 0); | ||
547 | if (ret == H_HARDWARE) | ||
548 | ehca_gen_err("HCA not operational. ret=%lx", ret); | ||
549 | |||
550 | ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE, | ||
551 | adapter_handle.handle, /* r4 */ | ||
552 | qp->ipz_qp_handle.handle, /* r5 */ | ||
553 | 0, 0, 0, 0, 0); | ||
554 | |||
555 | if (ret == H_RESOURCE) | ||
556 | ehca_gen_err("Resource still in use. ret=%lx", ret); | ||
557 | |||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle, | ||
562 | const struct ipz_qp_handle qp_handle, | ||
563 | struct h_galpa gal, | ||
564 | u32 port) | ||
565 | { | ||
566 | return ehca_plpar_hcall_norets(H_DEFINE_AQP0, | ||
567 | adapter_handle.handle, /* r4 */ | ||
568 | qp_handle.handle, /* r5 */ | ||
569 | port, /* r6 */ | ||
570 | 0, 0, 0, 0); | ||
571 | } | ||
572 | |||
573 | u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle, | ||
574 | const struct ipz_qp_handle qp_handle, | ||
575 | struct h_galpa gal, | ||
576 | u32 port, u32 * pma_qp_nr, | ||
577 | u32 * bma_qp_nr) | ||
578 | { | ||
579 | u64 ret; | ||
580 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
581 | |||
582 | ret = ehca_plpar_hcall9(H_DEFINE_AQP1, outs, | ||
583 | adapter_handle.handle, /* r4 */ | ||
584 | qp_handle.handle, /* r5 */ | ||
585 | port, /* r6 */ | ||
586 | 0, 0, 0, 0, 0, 0); | ||
587 | *pma_qp_nr = (u32)outs[0]; | ||
588 | *bma_qp_nr = (u32)outs[1]; | ||
589 | |||
590 | if (ret == H_ALIAS_EXIST) | ||
591 | ehca_gen_err("AQP1 already exists. ret=%lx", ret); | ||
592 | |||
593 | return ret; | ||
594 | } | ||
595 | |||
596 | u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle, | ||
597 | const struct ipz_qp_handle qp_handle, | ||
598 | struct h_galpa gal, | ||
599 | u16 mcg_dlid, | ||
600 | u64 subnet_prefix, u64 interface_id) | ||
601 | { | ||
602 | u64 ret; | ||
603 | |||
604 | ret = ehca_plpar_hcall_norets(H_ATTACH_MCQP, | ||
605 | adapter_handle.handle, /* r4 */ | ||
606 | qp_handle.handle, /* r5 */ | ||
607 | mcg_dlid, /* r6 */ | ||
608 | interface_id, /* r7 */ | ||
609 | subnet_prefix, /* r8 */ | ||
610 | 0, 0); | ||
611 | |||
612 | if (ret == H_NOT_ENOUGH_RESOURCES) | ||
613 | ehca_gen_err("Not enough resources. ret=%lx", ret); | ||
614 | |||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle, | ||
619 | const struct ipz_qp_handle qp_handle, | ||
620 | struct h_galpa gal, | ||
621 | u16 mcg_dlid, | ||
622 | u64 subnet_prefix, u64 interface_id) | ||
623 | { | ||
624 | return ehca_plpar_hcall_norets(H_DETACH_MCQP, | ||
625 | adapter_handle.handle, /* r4 */ | ||
626 | qp_handle.handle, /* r5 */ | ||
627 | mcg_dlid, /* r6 */ | ||
628 | interface_id, /* r7 */ | ||
629 | subnet_prefix, /* r8 */ | ||
630 | 0, 0); | ||
631 | } | ||
632 | |||
633 | u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle, | ||
634 | struct ehca_cq *cq, | ||
635 | u8 force_flag) | ||
636 | { | ||
637 | u64 ret; | ||
638 | |||
639 | ret = hcp_galpas_dtor(&cq->galpas); | ||
640 | if (ret) { | ||
641 | ehca_gen_err("Could not destruct cp->galpas"); | ||
642 | return H_RESOURCE; | ||
643 | } | ||
644 | |||
645 | ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE, | ||
646 | adapter_handle.handle, /* r4 */ | ||
647 | cq->ipz_cq_handle.handle, /* r5 */ | ||
648 | force_flag != 0 ? 1L : 0L, /* r6 */ | ||
649 | 0, 0, 0, 0); | ||
650 | |||
651 | if (ret == H_RESOURCE) | ||
652 | ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret); | ||
653 | |||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle, | ||
658 | struct ehca_eq *eq) | ||
659 | { | ||
660 | u64 ret; | ||
661 | |||
662 | ret = hcp_galpas_dtor(&eq->galpas); | ||
663 | if (ret) { | ||
664 | ehca_gen_err("Could not destruct eq->galpas"); | ||
665 | return H_RESOURCE; | ||
666 | } | ||
667 | |||
668 | ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE, | ||
669 | adapter_handle.handle, /* r4 */ | ||
670 | eq->ipz_eq_handle.handle, /* r5 */ | ||
671 | 0, 0, 0, 0, 0); | ||
672 | |||
673 | if (ret == H_RESOURCE) | ||
674 | ehca_gen_err("Resource in use. ret=%lx ", ret); | ||
675 | |||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle, | ||
680 | const struct ehca_mr *mr, | ||
681 | const u64 vaddr, | ||
682 | const u64 length, | ||
683 | const u32 access_ctrl, | ||
684 | const struct ipz_pd pd, | ||
685 | struct ehca_mr_hipzout_parms *outparms) | ||
686 | { | ||
687 | u64 ret; | ||
688 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
689 | |||
690 | ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, | ||
691 | adapter_handle.handle, /* r4 */ | ||
692 | 5, /* r5 */ | ||
693 | vaddr, /* r6 */ | ||
694 | length, /* r7 */ | ||
695 | (((u64)access_ctrl) << 32ULL), /* r8 */ | ||
696 | pd.value, /* r9 */ | ||
697 | 0, 0, 0); | ||
698 | outparms->handle.handle = outs[0]; | ||
699 | outparms->lkey = (u32)outs[2]; | ||
700 | outparms->rkey = (u32)outs[3]; | ||
701 | |||
702 | return ret; | ||
703 | } | ||
704 | |||
705 | u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle, | ||
706 | const struct ehca_mr *mr, | ||
707 | const u8 pagesize, | ||
708 | const u8 queue_type, | ||
709 | const u64 logical_address_of_page, | ||
710 | const u64 count) | ||
711 | { | ||
712 | u64 ret; | ||
713 | |||
714 | if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) { | ||
715 | ehca_gen_err("logical_address_of_page not on a 4k boundary " | ||
716 | "adapter_handle=%lx mr=%p mr_handle=%lx " | ||
717 | "pagesize=%x queue_type=%x " | ||
718 | "logical_address_of_page=%lx count=%lx", | ||
719 | adapter_handle.handle, mr, | ||
720 | mr->ipz_mr_handle.handle, pagesize, queue_type, | ||
721 | logical_address_of_page, count); | ||
722 | ret = H_PARAMETER; | ||
723 | } else | ||
724 | ret = hipz_h_register_rpage(adapter_handle, pagesize, | ||
725 | queue_type, | ||
726 | mr->ipz_mr_handle.handle, | ||
727 | logical_address_of_page, count); | ||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle, | ||
732 | const struct ehca_mr *mr, | ||
733 | struct ehca_mr_hipzout_parms *outparms) | ||
734 | { | ||
735 | u64 ret; | ||
736 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
737 | |||
738 | ret = ehca_plpar_hcall9(H_QUERY_MR, outs, | ||
739 | adapter_handle.handle, /* r4 */ | ||
740 | mr->ipz_mr_handle.handle, /* r5 */ | ||
741 | 0, 0, 0, 0, 0, 0, 0); | ||
742 | outparms->len = outs[0]; | ||
743 | outparms->vaddr = outs[1]; | ||
744 | outparms->acl = outs[4] >> 32; | ||
745 | outparms->lkey = (u32)(outs[5] >> 32); | ||
746 | outparms->rkey = (u32)(outs[5] & (0xffffffff)); | ||
747 | |||
748 | return ret; | ||
749 | } | ||
750 | |||
751 | u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle, | ||
752 | const struct ehca_mr *mr) | ||
753 | { | ||
754 | return ehca_plpar_hcall_norets(H_FREE_RESOURCE, | ||
755 | adapter_handle.handle, /* r4 */ | ||
756 | mr->ipz_mr_handle.handle, /* r5 */ | ||
757 | 0, 0, 0, 0, 0); | ||
758 | } | ||
759 | |||
760 | u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, | ||
761 | const struct ehca_mr *mr, | ||
762 | const u64 vaddr_in, | ||
763 | const u64 length, | ||
764 | const u32 access_ctrl, | ||
765 | const struct ipz_pd pd, | ||
766 | const u64 mr_addr_cb, | ||
767 | struct ehca_mr_hipzout_parms *outparms) | ||
768 | { | ||
769 | u64 ret; | ||
770 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
771 | |||
772 | ret = ehca_plpar_hcall9(H_REREGISTER_PMR, outs, | ||
773 | adapter_handle.handle, /* r4 */ | ||
774 | mr->ipz_mr_handle.handle, /* r5 */ | ||
775 | vaddr_in, /* r6 */ | ||
776 | length, /* r7 */ | ||
777 | /* r8 */ | ||
778 | ((((u64)access_ctrl) << 32ULL) | pd.value), | ||
779 | mr_addr_cb, /* r9 */ | ||
780 | 0, 0, 0); | ||
781 | outparms->vaddr = outs[1]; | ||
782 | outparms->lkey = (u32)outs[2]; | ||
783 | outparms->rkey = (u32)outs[3]; | ||
784 | |||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle, | ||
789 | const struct ehca_mr *mr, | ||
790 | const struct ehca_mr *orig_mr, | ||
791 | const u64 vaddr_in, | ||
792 | const u32 access_ctrl, | ||
793 | const struct ipz_pd pd, | ||
794 | struct ehca_mr_hipzout_parms *outparms) | ||
795 | { | ||
796 | u64 ret; | ||
797 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
798 | |||
799 | ret = ehca_plpar_hcall9(H_REGISTER_SMR, outs, | ||
800 | adapter_handle.handle, /* r4 */ | ||
801 | orig_mr->ipz_mr_handle.handle, /* r5 */ | ||
802 | vaddr_in, /* r6 */ | ||
803 | (((u64)access_ctrl) << 32ULL), /* r7 */ | ||
804 | pd.value, /* r8 */ | ||
805 | 0, 0, 0, 0); | ||
806 | outparms->handle.handle = outs[0]; | ||
807 | outparms->lkey = (u32)outs[2]; | ||
808 | outparms->rkey = (u32)outs[3]; | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle, | ||
814 | const struct ehca_mw *mw, | ||
815 | const struct ipz_pd pd, | ||
816 | struct ehca_mw_hipzout_parms *outparms) | ||
817 | { | ||
818 | u64 ret; | ||
819 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
820 | |||
821 | ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, | ||
822 | adapter_handle.handle, /* r4 */ | ||
823 | 6, /* r5 */ | ||
824 | pd.value, /* r6 */ | ||
825 | 0, 0, 0, 0, 0, 0); | ||
826 | outparms->handle.handle = outs[0]; | ||
827 | outparms->rkey = (u32)outs[3]; | ||
828 | |||
829 | return ret; | ||
830 | } | ||
831 | |||
832 | u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle, | ||
833 | const struct ehca_mw *mw, | ||
834 | struct ehca_mw_hipzout_parms *outparms) | ||
835 | { | ||
836 | u64 ret; | ||
837 | u64 outs[PLPAR_HCALL9_BUFSIZE]; | ||
838 | |||
839 | ret = ehca_plpar_hcall9(H_QUERY_MW, outs, | ||
840 | adapter_handle.handle, /* r4 */ | ||
841 | mw->ipz_mw_handle.handle, /* r5 */ | ||
842 | 0, 0, 0, 0, 0, 0, 0); | ||
843 | outparms->rkey = (u32)outs[3]; | ||
844 | |||
845 | return ret; | ||
846 | } | ||
847 | |||
848 | u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle, | ||
849 | const struct ehca_mw *mw) | ||
850 | { | ||
851 | return ehca_plpar_hcall_norets(H_FREE_RESOURCE, | ||
852 | adapter_handle.handle, /* r4 */ | ||
853 | mw->ipz_mw_handle.handle, /* r5 */ | ||
854 | 0, 0, 0, 0, 0); | ||
855 | } | ||
856 | |||
857 | u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle, | ||
858 | const u64 ressource_handle, | ||
859 | void *rblock, | ||
860 | unsigned long *byte_count) | ||
861 | { | ||
862 | u64 r_cb = virt_to_abs(rblock); | ||
863 | |||
864 | if (r_cb & (EHCA_PAGESIZE-1)) { | ||
865 | ehca_gen_err("rblock not page aligned."); | ||
866 | return H_PARAMETER; | ||
867 | } | ||
868 | |||
869 | return ehca_plpar_hcall_norets(H_ERROR_DATA, | ||
870 | adapter_handle.handle, | ||
871 | ressource_handle, | ||
872 | r_cb, | ||
873 | 0, 0, 0, 0); | ||
874 | } | ||
diff --git a/drivers/infiniband/hw/ehca/hcp_if.h b/drivers/infiniband/hw/ehca/hcp_if.h new file mode 100644 index 000000000000..587ebd470959 --- /dev/null +++ b/drivers/infiniband/hw/ehca/hcp_if.h | |||
@@ -0,0 +1,261 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Firmware Infiniband Interface code for POWER | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Gerd Bayer <gerd.bayer@de.ibm.com> | ||
9 | * Waleri Fomin <fomin@de.ibm.com> | ||
10 | * | ||
11 | * Copyright (c) 2005 IBM Corporation | ||
12 | * | ||
13 | * All rights reserved. | ||
14 | * | ||
15 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
16 | * BSD. | ||
17 | * | ||
18 | * OpenIB BSD License | ||
19 | * | ||
20 | * Redistribution and use in source and binary forms, with or without | ||
21 | * modification, are permitted provided that the following conditions are met: | ||
22 | * | ||
23 | * Redistributions of source code must retain the above copyright notice, this | ||
24 | * list of conditions and the following disclaimer. | ||
25 | * | ||
26 | * Redistributions in binary form must reproduce the above copyright notice, | ||
27 | * this list of conditions and the following disclaimer in the documentation | ||
28 | * and/or other materials | ||
29 | * provided with the distribution. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
32 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
34 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
35 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
36 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
37 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
38 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
39 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | */ | ||
43 | |||
44 | #ifndef __HCP_IF_H__ | ||
45 | #define __HCP_IF_H__ | ||
46 | |||
47 | #include "ehca_classes.h" | ||
48 | #include "ehca_tools.h" | ||
49 | #include "hipz_hw.h" | ||
50 | |||
51 | /* | ||
52 | * hipz_h_alloc_resource_eq allocates EQ resources in HW and FW, initalize | ||
53 | * resources, create the empty EQPT (ring). | ||
54 | */ | ||
55 | u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle, | ||
56 | struct ehca_pfeq *pfeq, | ||
57 | const u32 neq_control, | ||
58 | const u32 number_of_entries, | ||
59 | struct ipz_eq_handle *eq_handle, | ||
60 | u32 * act_nr_of_entries, | ||
61 | u32 * act_pages, | ||
62 | u32 * eq_ist); | ||
63 | |||
64 | u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle, | ||
65 | struct ipz_eq_handle eq_handle, | ||
66 | const u64 event_mask); | ||
67 | /* | ||
68 | * hipz_h_allocate_resource_cq allocates CQ resources in HW and FW, initialize | ||
69 | * resources, create the empty CQPT (ring). | ||
70 | */ | ||
71 | u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, | ||
72 | struct ehca_cq *cq, | ||
73 | struct ehca_alloc_cq_parms *param); | ||
74 | |||
75 | |||
76 | /* | ||
77 | * hipz_h_alloc_resource_qp allocates QP resources in HW and FW, | ||
78 | * initialize resources, create empty QPPTs (2 rings). | ||
79 | */ | ||
80 | u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, | ||
81 | struct ehca_qp *qp, | ||
82 | struct ehca_alloc_qp_parms *parms); | ||
83 | |||
84 | u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, | ||
85 | const u8 port_id, | ||
86 | struct hipz_query_port *query_port_response_block); | ||
87 | |||
88 | u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle, | ||
89 | struct hipz_query_hca *query_hca_rblock); | ||
90 | |||
91 | /* | ||
92 | * hipz_h_register_rpage internal function in hcp_if.h for all | ||
93 | * hcp_H_REGISTER_RPAGE calls. | ||
94 | */ | ||
95 | u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle, | ||
96 | const u8 pagesize, | ||
97 | const u8 queue_type, | ||
98 | const u64 resource_handle, | ||
99 | const u64 logical_address_of_page, | ||
100 | u64 count); | ||
101 | |||
102 | u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle, | ||
103 | const struct ipz_eq_handle eq_handle, | ||
104 | struct ehca_pfeq *pfeq, | ||
105 | const u8 pagesize, | ||
106 | const u8 queue_type, | ||
107 | const u64 logical_address_of_page, | ||
108 | const u64 count); | ||
109 | |||
110 | u64 hipz_h_query_int_state(const struct ipz_adapter_handle | ||
111 | hcp_adapter_handle, | ||
112 | u32 ist); | ||
113 | |||
114 | u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle, | ||
115 | const struct ipz_cq_handle cq_handle, | ||
116 | struct ehca_pfcq *pfcq, | ||
117 | const u8 pagesize, | ||
118 | const u8 queue_type, | ||
119 | const u64 logical_address_of_page, | ||
120 | const u64 count, | ||
121 | const struct h_galpa gal); | ||
122 | |||
123 | u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle, | ||
124 | const struct ipz_qp_handle qp_handle, | ||
125 | struct ehca_pfqp *pfqp, | ||
126 | const u8 pagesize, | ||
127 | const u8 queue_type, | ||
128 | const u64 logical_address_of_page, | ||
129 | const u64 count, | ||
130 | const struct h_galpa galpa); | ||
131 | |||
132 | u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle, | ||
133 | const struct ipz_qp_handle qp_handle, | ||
134 | struct ehca_pfqp *pfqp, | ||
135 | void **log_addr_next_sq_wqe_tb_processed, | ||
136 | void **log_addr_next_rq_wqe_tb_processed, | ||
137 | int dis_and_get_function_code); | ||
138 | enum hcall_sigt { | ||
139 | HCALL_SIGT_NO_CQE = 0, | ||
140 | HCALL_SIGT_BY_WQE = 1, | ||
141 | HCALL_SIGT_EVERY = 2 | ||
142 | }; | ||
143 | |||
144 | u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle, | ||
145 | const struct ipz_qp_handle qp_handle, | ||
146 | struct ehca_pfqp *pfqp, | ||
147 | const u64 update_mask, | ||
148 | struct hcp_modify_qp_control_block *mqpcb, | ||
149 | struct h_galpa gal); | ||
150 | |||
151 | u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle, | ||
152 | const struct ipz_qp_handle qp_handle, | ||
153 | struct ehca_pfqp *pfqp, | ||
154 | struct hcp_modify_qp_control_block *qqpcb, | ||
155 | struct h_galpa gal); | ||
156 | |||
157 | u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle, | ||
158 | struct ehca_qp *qp); | ||
159 | |||
160 | u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle, | ||
161 | const struct ipz_qp_handle qp_handle, | ||
162 | struct h_galpa gal, | ||
163 | u32 port); | ||
164 | |||
165 | u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle, | ||
166 | const struct ipz_qp_handle qp_handle, | ||
167 | struct h_galpa gal, | ||
168 | u32 port, u32 * pma_qp_nr, | ||
169 | u32 * bma_qp_nr); | ||
170 | |||
171 | u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle, | ||
172 | const struct ipz_qp_handle qp_handle, | ||
173 | struct h_galpa gal, | ||
174 | u16 mcg_dlid, | ||
175 | u64 subnet_prefix, u64 interface_id); | ||
176 | |||
177 | u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle, | ||
178 | const struct ipz_qp_handle qp_handle, | ||
179 | struct h_galpa gal, | ||
180 | u16 mcg_dlid, | ||
181 | u64 subnet_prefix, u64 interface_id); | ||
182 | |||
183 | u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle, | ||
184 | struct ehca_cq *cq, | ||
185 | u8 force_flag); | ||
186 | |||
187 | u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle, | ||
188 | struct ehca_eq *eq); | ||
189 | |||
190 | /* | ||
191 | * hipz_h_alloc_resource_mr allocates MR resources in HW and FW, initialize | ||
192 | * resources. | ||
193 | */ | ||
194 | u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle, | ||
195 | const struct ehca_mr *mr, | ||
196 | const u64 vaddr, | ||
197 | const u64 length, | ||
198 | const u32 access_ctrl, | ||
199 | const struct ipz_pd pd, | ||
200 | struct ehca_mr_hipzout_parms *outparms); | ||
201 | |||
202 | /* hipz_h_register_rpage_mr registers MR resource pages in HW and FW */ | ||
203 | u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle, | ||
204 | const struct ehca_mr *mr, | ||
205 | const u8 pagesize, | ||
206 | const u8 queue_type, | ||
207 | const u64 logical_address_of_page, | ||
208 | const u64 count); | ||
209 | |||
210 | /* hipz_h_query_mr queries MR in HW and FW */ | ||
211 | u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle, | ||
212 | const struct ehca_mr *mr, | ||
213 | struct ehca_mr_hipzout_parms *outparms); | ||
214 | |||
215 | /* hipz_h_free_resource_mr frees MR resources in HW and FW */ | ||
216 | u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle, | ||
217 | const struct ehca_mr *mr); | ||
218 | |||
219 | /* hipz_h_reregister_pmr reregisters MR in HW and FW */ | ||
220 | u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, | ||
221 | const struct ehca_mr *mr, | ||
222 | const u64 vaddr_in, | ||
223 | const u64 length, | ||
224 | const u32 access_ctrl, | ||
225 | const struct ipz_pd pd, | ||
226 | const u64 mr_addr_cb, | ||
227 | struct ehca_mr_hipzout_parms *outparms); | ||
228 | |||
229 | /* hipz_h_register_smr register shared MR in HW and FW */ | ||
230 | u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle, | ||
231 | const struct ehca_mr *mr, | ||
232 | const struct ehca_mr *orig_mr, | ||
233 | const u64 vaddr_in, | ||
234 | const u32 access_ctrl, | ||
235 | const struct ipz_pd pd, | ||
236 | struct ehca_mr_hipzout_parms *outparms); | ||
237 | |||
238 | /* | ||
239 | * hipz_h_alloc_resource_mw allocates MW resources in HW and FW, initialize | ||
240 | * resources. | ||
241 | */ | ||
242 | u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle, | ||
243 | const struct ehca_mw *mw, | ||
244 | const struct ipz_pd pd, | ||
245 | struct ehca_mw_hipzout_parms *outparms); | ||
246 | |||
247 | /* hipz_h_query_mw queries MW in HW and FW */ | ||
248 | u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle, | ||
249 | const struct ehca_mw *mw, | ||
250 | struct ehca_mw_hipzout_parms *outparms); | ||
251 | |||
252 | /* hipz_h_free_resource_mw frees MW resources in HW and FW */ | ||
253 | u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle, | ||
254 | const struct ehca_mw *mw); | ||
255 | |||
256 | u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle, | ||
257 | const u64 ressource_handle, | ||
258 | void *rblock, | ||
259 | unsigned long *byte_count); | ||
260 | |||
261 | #endif /* __HCP_IF_H__ */ | ||
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c new file mode 100644 index 000000000000..0b1a4772c78a --- /dev/null +++ b/drivers/infiniband/hw/ehca/hcp_phyp.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * load store abstraction for ehca register access with tracing | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #include "ehca_classes.h" | ||
43 | #include "hipz_hw.h" | ||
44 | |||
45 | int hcall_map_page(u64 physaddr, u64 *mapaddr) | ||
46 | { | ||
47 | *mapaddr = (u64)(ioremap(physaddr, EHCA_PAGESIZE)); | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | int hcall_unmap_page(u64 mapaddr) | ||
52 | { | ||
53 | iounmap((volatile void __iomem*)mapaddr); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | int hcp_galpas_ctor(struct h_galpas *galpas, | ||
58 | u64 paddr_kernel, u64 paddr_user) | ||
59 | { | ||
60 | int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle); | ||
61 | if (ret) | ||
62 | return ret; | ||
63 | |||
64 | galpas->user.fw_handle = paddr_user; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | int hcp_galpas_dtor(struct h_galpas *galpas) | ||
70 | { | ||
71 | if (galpas->kernel.fw_handle) { | ||
72 | int ret = hcall_unmap_page(galpas->kernel.fw_handle); | ||
73 | if (ret) | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | galpas->user.fw_handle = galpas->kernel.fw_handle = 0; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.h b/drivers/infiniband/hw/ehca/hcp_phyp.h new file mode 100644 index 000000000000..5305c2a3ed94 --- /dev/null +++ b/drivers/infiniband/hw/ehca/hcp_phyp.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * Firmware calls | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
8 | * Waleri Fomin <fomin@de.ibm.com> | ||
9 | * Gerd Bayer <gerd.bayer@de.ibm.com> | ||
10 | * | ||
11 | * Copyright (c) 2005 IBM Corporation | ||
12 | * | ||
13 | * All rights reserved. | ||
14 | * | ||
15 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
16 | * BSD. | ||
17 | * | ||
18 | * OpenIB BSD License | ||
19 | * | ||
20 | * Redistribution and use in source and binary forms, with or without | ||
21 | * modification, are permitted provided that the following conditions are met: | ||
22 | * | ||
23 | * Redistributions of source code must retain the above copyright notice, this | ||
24 | * list of conditions and the following disclaimer. | ||
25 | * | ||
26 | * Redistributions in binary form must reproduce the above copyright notice, | ||
27 | * this list of conditions and the following disclaimer in the documentation | ||
28 | * and/or other materials | ||
29 | * provided with the distribution. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
32 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
34 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
35 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
36 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
37 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
38 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
39 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | */ | ||
43 | |||
44 | #ifndef __HCP_PHYP_H__ | ||
45 | #define __HCP_PHYP_H__ | ||
46 | |||
47 | |||
48 | /* | ||
49 | * eHCA page (mapped into memory) | ||
50 | * resource to access eHCA register pages in CPU address space | ||
51 | */ | ||
52 | struct h_galpa { | ||
53 | u64 fw_handle; | ||
54 | /* for pSeries this is a 64bit memory address where | ||
55 | I/O memory is mapped into CPU address space (kv) */ | ||
56 | }; | ||
57 | |||
58 | /* | ||
59 | * resource to access eHCA address space registers, all types | ||
60 | */ | ||
61 | struct h_galpas { | ||
62 | u32 pid; /*PID of userspace galpa checking */ | ||
63 | struct h_galpa user; /* user space accessible resource, | ||
64 | set to 0 if unused */ | ||
65 | struct h_galpa kernel; /* kernel space accessible resource, | ||
66 | set to 0 if unused */ | ||
67 | }; | ||
68 | |||
69 | static inline u64 hipz_galpa_load(struct h_galpa galpa, u32 offset) | ||
70 | { | ||
71 | u64 addr = galpa.fw_handle + offset; | ||
72 | return *(volatile u64 __force *)addr; | ||
73 | } | ||
74 | |||
75 | static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value) | ||
76 | { | ||
77 | u64 addr = galpa.fw_handle + offset; | ||
78 | *(volatile u64 __force *)addr = value; | ||
79 | } | ||
80 | |||
81 | int hcp_galpas_ctor(struct h_galpas *galpas, | ||
82 | u64 paddr_kernel, u64 paddr_user); | ||
83 | |||
84 | int hcp_galpas_dtor(struct h_galpas *galpas); | ||
85 | |||
86 | int hcall_map_page(u64 physaddr, u64 * mapaddr); | ||
87 | |||
88 | int hcall_unmap_page(u64 mapaddr); | ||
89 | |||
90 | #endif | ||
diff --git a/drivers/infiniband/hw/ehca/hipz_fns.h b/drivers/infiniband/hw/ehca/hipz_fns.h new file mode 100644 index 000000000000..9dac93d02140 --- /dev/null +++ b/drivers/infiniband/hw/ehca/hipz_fns.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * HW abstraction register functions | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Reinhard Ernst <rernst@de.ibm.com> | ||
8 | * | ||
9 | * Copyright (c) 2005 IBM Corporation | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
14 | * BSD. | ||
15 | * | ||
16 | * OpenIB BSD License | ||
17 | * | ||
18 | * Redistribution and use in source and binary forms, with or without | ||
19 | * modification, are permitted provided that the following conditions are met: | ||
20 | * | ||
21 | * Redistributions of source code must retain the above copyright notice, this | ||
22 | * list of conditions and the following disclaimer. | ||
23 | * | ||
24 | * Redistributions in binary form must reproduce the above copyright notice, | ||
25 | * this list of conditions and the following disclaimer in the documentation | ||
26 | * and/or other materials | ||
27 | * provided with the distribution. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
30 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
33 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
34 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
35 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
36 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
37 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
38 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | */ | ||
41 | |||
42 | #ifndef __HIPZ_FNS_H__ | ||
43 | #define __HIPZ_FNS_H__ | ||
44 | |||
45 | #include "ehca_classes.h" | ||
46 | #include "hipz_hw.h" | ||
47 | |||
48 | #include "hipz_fns_core.h" | ||
49 | |||
50 | #define hipz_galpa_store_eq(gal, offset, value) \ | ||
51 | hipz_galpa_store(gal, EQTEMM_OFFSET(offset), value) | ||
52 | |||
53 | #define hipz_galpa_load_eq(gal, offset) \ | ||
54 | hipz_galpa_load(gal, EQTEMM_OFFSET(offset)) | ||
55 | |||
56 | #define hipz_galpa_store_qped(gal, offset, value) \ | ||
57 | hipz_galpa_store(gal, QPEDMM_OFFSET(offset), value) | ||
58 | |||
59 | #define hipz_galpa_load_qped(gal, offset) \ | ||
60 | hipz_galpa_load(gal, QPEDMM_OFFSET(offset)) | ||
61 | |||
62 | #define hipz_galpa_store_mrmw(gal, offset, value) \ | ||
63 | hipz_galpa_store(gal, MRMWMM_OFFSET(offset), value) | ||
64 | |||
65 | #define hipz_galpa_load_mrmw(gal, offset) \ | ||
66 | hipz_galpa_load(gal, MRMWMM_OFFSET(offset)) | ||
67 | |||
68 | #endif | ||
diff --git a/drivers/infiniband/hw/ehca/hipz_fns_core.h b/drivers/infiniband/hw/ehca/hipz_fns_core.h new file mode 100644 index 000000000000..20898a153446 --- /dev/null +++ b/drivers/infiniband/hw/ehca/hipz_fns_core.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * HW abstraction register functions | ||
5 | * | ||
6 | * Authors: Christoph Raisch <raisch@de.ibm.com> | ||
7 | * Heiko J Schick <schickhj@de.ibm.com> | ||
8 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
9 | * Reinhard Ernst <rernst@de.ibm.com> | ||
10 | * | ||
11 | * Copyright (c) 2005 IBM Corporation | ||
12 | * | ||
13 | * All rights reserved. | ||
14 | * | ||
15 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
16 | * BSD. | ||
17 | * | ||
18 | * OpenIB BSD License | ||
19 | * | ||
20 | * Redistribution and use in source and binary forms, with or without | ||
21 | * modification, are permitted provided that the following conditions are met: | ||
22 | * | ||
23 | * Redistributions of source code must retain the above copyright notice, this | ||
24 | * list of conditions and the following disclaimer. | ||
25 | * | ||
26 | * Redistributions in binary form must reproduce the above copyright notice, | ||
27 | * this list of conditions and the following disclaimer in the documentation | ||
28 | * and/or other materials | ||
29 | * provided with the distribution. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
32 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
34 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
35 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
36 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
37 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
38 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
39 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | */ | ||
43 | |||
44 | #ifndef __HIPZ_FNS_CORE_H__ | ||
45 | #define __HIPZ_FNS_CORE_H__ | ||
46 | |||
47 | #include "hcp_phyp.h" | ||
48 | #include "hipz_hw.h" | ||
49 | |||
50 | #define hipz_galpa_store_cq(gal, offset, value) \ | ||
51 | hipz_galpa_store(gal, CQTEMM_OFFSET(offset), value) | ||
52 | |||
53 | #define hipz_galpa_load_cq(gal, offset) \ | ||
54 | hipz_galpa_load(gal, CQTEMM_OFFSET(offset)) | ||
55 | |||
56 | #define hipz_galpa_store_qp(gal,offset, value) \ | ||
57 | hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value) | ||
58 | #define hipz_galpa_load_qp(gal, offset) \ | ||
59 | hipz_galpa_load(gal,QPTEMM_OFFSET(offset)) | ||
60 | |||
61 | static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes) | ||
62 | { | ||
63 | /* ringing doorbell :-) */ | ||
64 | hipz_galpa_store_qp(qp->galpas.kernel, qpx_sqa, | ||
65 | EHCA_BMASK_SET(QPX_SQADDER, nr_wqes)); | ||
66 | } | ||
67 | |||
68 | static inline void hipz_update_rqa(struct ehca_qp *qp, u16 nr_wqes) | ||
69 | { | ||
70 | /* ringing doorbell :-) */ | ||
71 | hipz_galpa_store_qp(qp->galpas.kernel, qpx_rqa, | ||
72 | EHCA_BMASK_SET(QPX_RQADDER, nr_wqes)); | ||
73 | } | ||
74 | |||
75 | static inline void hipz_update_feca(struct ehca_cq *cq, u32 nr_cqes) | ||
76 | { | ||
77 | hipz_galpa_store_cq(cq->galpas.kernel, cqx_feca, | ||
78 | EHCA_BMASK_SET(CQX_FECADDER, nr_cqes)); | ||
79 | } | ||
80 | |||
81 | static inline void hipz_set_cqx_n0(struct ehca_cq *cq, u32 value) | ||
82 | { | ||
83 | u64 cqx_n0_reg; | ||
84 | |||
85 | hipz_galpa_store_cq(cq->galpas.kernel, cqx_n0, | ||
86 | EHCA_BMASK_SET(CQX_N0_GENERATE_SOLICITED_COMP_EVENT, | ||
87 | value)); | ||
88 | cqx_n0_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n0); | ||
89 | } | ||
90 | |||
91 | static inline void hipz_set_cqx_n1(struct ehca_cq *cq, u32 value) | ||
92 | { | ||
93 | u64 cqx_n1_reg; | ||
94 | |||
95 | hipz_galpa_store_cq(cq->galpas.kernel, cqx_n1, | ||
96 | EHCA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, value)); | ||
97 | cqx_n1_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n1); | ||
98 | } | ||
99 | |||
100 | #endif /* __HIPZ_FNC_CORE_H__ */ | ||
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h new file mode 100644 index 000000000000..3fc92b031c50 --- /dev/null +++ b/drivers/infiniband/hw/ehca/hipz_hw.h | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * eHCA register definitions | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Christoph Raisch <raisch@de.ibm.com> | ||
8 | * Reinhard Ernst <rernst@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | #ifndef __HIPZ_HW_H__ | ||
44 | #define __HIPZ_HW_H__ | ||
45 | |||
46 | #include "ehca_tools.h" | ||
47 | |||
48 | /* QP Table Entry Memory Map */ | ||
49 | struct hipz_qptemm { | ||
50 | u64 qpx_hcr; | ||
51 | u64 qpx_c; | ||
52 | u64 qpx_herr; | ||
53 | u64 qpx_aer; | ||
54 | /* 0x20*/ | ||
55 | u64 qpx_sqa; | ||
56 | u64 qpx_sqc; | ||
57 | u64 qpx_rqa; | ||
58 | u64 qpx_rqc; | ||
59 | /* 0x40*/ | ||
60 | u64 qpx_st; | ||
61 | u64 qpx_pmstate; | ||
62 | u64 qpx_pmfa; | ||
63 | u64 qpx_pkey; | ||
64 | /* 0x60*/ | ||
65 | u64 qpx_pkeya; | ||
66 | u64 qpx_pkeyb; | ||
67 | u64 qpx_pkeyc; | ||
68 | u64 qpx_pkeyd; | ||
69 | /* 0x80*/ | ||
70 | u64 qpx_qkey; | ||
71 | u64 qpx_dqp; | ||
72 | u64 qpx_dlidp; | ||
73 | u64 qpx_portp; | ||
74 | /* 0xa0*/ | ||
75 | u64 qpx_slidp; | ||
76 | u64 qpx_slidpp; | ||
77 | u64 qpx_dlida; | ||
78 | u64 qpx_porta; | ||
79 | /* 0xc0*/ | ||
80 | u64 qpx_slida; | ||
81 | u64 qpx_slidpa; | ||
82 | u64 qpx_slvl; | ||
83 | u64 qpx_ipd; | ||
84 | /* 0xe0*/ | ||
85 | u64 qpx_mtu; | ||
86 | u64 qpx_lato; | ||
87 | u64 qpx_rlimit; | ||
88 | u64 qpx_rnrlimit; | ||
89 | /* 0x100*/ | ||
90 | u64 qpx_t; | ||
91 | u64 qpx_sqhp; | ||
92 | u64 qpx_sqptp; | ||
93 | u64 qpx_nspsn; | ||
94 | /* 0x120*/ | ||
95 | u64 qpx_nspsnhwm; | ||
96 | u64 reserved1; | ||
97 | u64 qpx_sdsi; | ||
98 | u64 qpx_sdsbc; | ||
99 | /* 0x140*/ | ||
100 | u64 qpx_sqwsize; | ||
101 | u64 qpx_sqwts; | ||
102 | u64 qpx_lsn; | ||
103 | u64 qpx_nssn; | ||
104 | /* 0x160 */ | ||
105 | u64 qpx_mor; | ||
106 | u64 qpx_cor; | ||
107 | u64 qpx_sqsize; | ||
108 | u64 qpx_erc; | ||
109 | /* 0x180*/ | ||
110 | u64 qpx_rnrrc; | ||
111 | u64 qpx_ernrwt; | ||
112 | u64 qpx_rnrresp; | ||
113 | u64 qpx_lmsna; | ||
114 | /* 0x1a0 */ | ||
115 | u64 qpx_sqhpc; | ||
116 | u64 qpx_sqcptp; | ||
117 | u64 qpx_sigt; | ||
118 | u64 qpx_wqecnt; | ||
119 | /* 0x1c0*/ | ||
120 | u64 qpx_rqhp; | ||
121 | u64 qpx_rqptp; | ||
122 | u64 qpx_rqsize; | ||
123 | u64 qpx_nrr; | ||
124 | /* 0x1e0*/ | ||
125 | u64 qpx_rdmac; | ||
126 | u64 qpx_nrpsn; | ||
127 | u64 qpx_lapsn; | ||
128 | u64 qpx_lcr; | ||
129 | /* 0x200*/ | ||
130 | u64 qpx_rwc; | ||
131 | u64 qpx_rwva; | ||
132 | u64 qpx_rdsi; | ||
133 | u64 qpx_rdsbc; | ||
134 | /* 0x220*/ | ||
135 | u64 qpx_rqwsize; | ||
136 | u64 qpx_crmsn; | ||
137 | u64 qpx_rdd; | ||
138 | u64 qpx_larpsn; | ||
139 | /* 0x240*/ | ||
140 | u64 qpx_pd; | ||
141 | u64 qpx_scqn; | ||
142 | u64 qpx_rcqn; | ||
143 | u64 qpx_aeqn; | ||
144 | /* 0x260*/ | ||
145 | u64 qpx_aaelog; | ||
146 | u64 qpx_ram; | ||
147 | u64 qpx_rdmaqe0; | ||
148 | u64 qpx_rdmaqe1; | ||
149 | /* 0x280*/ | ||
150 | u64 qpx_rdmaqe2; | ||
151 | u64 qpx_rdmaqe3; | ||
152 | u64 qpx_nrpsnhwm; | ||
153 | /* 0x298*/ | ||
154 | u64 reserved[(0x400 - 0x298) / 8]; | ||
155 | /* 0x400 extended data */ | ||
156 | u64 reserved_ext[(0x500 - 0x400) / 8]; | ||
157 | /* 0x500 */ | ||
158 | u64 reserved2[(0x1000 - 0x500) / 8]; | ||
159 | /* 0x1000 */ | ||
160 | }; | ||
161 | |||
162 | #define QPX_SQADDER EHCA_BMASK_IBM(48,63) | ||
163 | #define QPX_RQADDER EHCA_BMASK_IBM(48,63) | ||
164 | |||
165 | #define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x) | ||
166 | |||
167 | /* MRMWPT Entry Memory Map */ | ||
168 | struct hipz_mrmwmm { | ||
169 | /* 0x00 */ | ||
170 | u64 mrx_hcr; | ||
171 | |||
172 | u64 mrx_c; | ||
173 | u64 mrx_herr; | ||
174 | u64 mrx_aer; | ||
175 | /* 0x20 */ | ||
176 | u64 mrx_pp; | ||
177 | u64 reserved1; | ||
178 | u64 reserved2; | ||
179 | u64 reserved3; | ||
180 | /* 0x40 */ | ||
181 | u64 reserved4[(0x200 - 0x40) / 8]; | ||
182 | /* 0x200 */ | ||
183 | u64 mrx_ctl[64]; | ||
184 | |||
185 | }; | ||
186 | |||
187 | #define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x) | ||
188 | |||
189 | struct hipz_qpedmm { | ||
190 | /* 0x00 */ | ||
191 | u64 reserved0[(0x400) / 8]; | ||
192 | /* 0x400 */ | ||
193 | u64 qpedx_phh; | ||
194 | u64 qpedx_ppsgp; | ||
195 | /* 0x410 */ | ||
196 | u64 qpedx_ppsgu; | ||
197 | u64 qpedx_ppdgp; | ||
198 | /* 0x420 */ | ||
199 | u64 qpedx_ppdgu; | ||
200 | u64 qpedx_aph; | ||
201 | /* 0x430 */ | ||
202 | u64 qpedx_apsgp; | ||
203 | u64 qpedx_apsgu; | ||
204 | /* 0x440 */ | ||
205 | u64 qpedx_apdgp; | ||
206 | u64 qpedx_apdgu; | ||
207 | /* 0x450 */ | ||
208 | u64 qpedx_apav; | ||
209 | u64 qpedx_apsav; | ||
210 | /* 0x460 */ | ||
211 | u64 qpedx_hcr; | ||
212 | u64 reserved1[4]; | ||
213 | /* 0x488 */ | ||
214 | u64 qpedx_rrl0; | ||
215 | /* 0x490 */ | ||
216 | u64 qpedx_rrrkey0; | ||
217 | u64 qpedx_rrva0; | ||
218 | /* 0x4a0 */ | ||
219 | u64 reserved2; | ||
220 | u64 qpedx_rrl1; | ||
221 | /* 0x4b0 */ | ||
222 | u64 qpedx_rrrkey1; | ||
223 | u64 qpedx_rrva1; | ||
224 | /* 0x4c0 */ | ||
225 | u64 reserved3; | ||
226 | u64 qpedx_rrl2; | ||
227 | /* 0x4d0 */ | ||
228 | u64 qpedx_rrrkey2; | ||
229 | u64 qpedx_rrva2; | ||
230 | /* 0x4e0 */ | ||
231 | u64 reserved4; | ||
232 | u64 qpedx_rrl3; | ||
233 | /* 0x4f0 */ | ||
234 | u64 qpedx_rrrkey3; | ||
235 | u64 qpedx_rrva3; | ||
236 | }; | ||
237 | |||
238 | #define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x) | ||
239 | |||
240 | /* CQ Table Entry Memory Map */ | ||
241 | struct hipz_cqtemm { | ||
242 | u64 cqx_hcr; | ||
243 | u64 cqx_c; | ||
244 | u64 cqx_herr; | ||
245 | u64 cqx_aer; | ||
246 | /* 0x20 */ | ||
247 | u64 cqx_ptp; | ||
248 | u64 cqx_tp; | ||
249 | u64 cqx_fec; | ||
250 | u64 cqx_feca; | ||
251 | /* 0x40 */ | ||
252 | u64 cqx_ep; | ||
253 | u64 cqx_eq; | ||
254 | /* 0x50 */ | ||
255 | u64 reserved1; | ||
256 | u64 cqx_n0; | ||
257 | /* 0x60 */ | ||
258 | u64 cqx_n1; | ||
259 | u64 reserved2[(0x1000 - 0x60) / 8]; | ||
260 | /* 0x1000 */ | ||
261 | }; | ||
262 | |||
263 | #define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32,63) | ||
264 | #define CQX_FECADDER EHCA_BMASK_IBM(32,63) | ||
265 | #define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0) | ||
266 | #define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0) | ||
267 | |||
268 | #define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x) | ||
269 | |||
270 | /* EQ Table Entry Memory Map */ | ||
271 | struct hipz_eqtemm { | ||
272 | u64 eqx_hcr; | ||
273 | u64 eqx_c; | ||
274 | |||
275 | u64 eqx_herr; | ||
276 | u64 eqx_aer; | ||
277 | /* 0x20 */ | ||
278 | u64 eqx_ptp; | ||
279 | u64 eqx_tp; | ||
280 | u64 eqx_ssba; | ||
281 | u64 eqx_psba; | ||
282 | |||
283 | /* 0x40 */ | ||
284 | u64 eqx_cec; | ||
285 | u64 eqx_meql; | ||
286 | u64 eqx_xisbi; | ||
287 | u64 eqx_xisc; | ||
288 | /* 0x60 */ | ||
289 | u64 eqx_it; | ||
290 | |||
291 | }; | ||
292 | |||
293 | #define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x) | ||
294 | |||
295 | /* access control defines for MR/MW */ | ||
296 | #define HIPZ_ACCESSCTRL_L_WRITE 0x00800000 | ||
297 | #define HIPZ_ACCESSCTRL_R_WRITE 0x00400000 | ||
298 | #define HIPZ_ACCESSCTRL_R_READ 0x00200000 | ||
299 | #define HIPZ_ACCESSCTRL_R_ATOMIC 0x00100000 | ||
300 | #define HIPZ_ACCESSCTRL_MW_BIND 0x00080000 | ||
301 | |||
302 | /* query hca response block */ | ||
303 | struct hipz_query_hca { | ||
304 | u32 cur_reliable_dg; | ||
305 | u32 cur_qp; | ||
306 | u32 cur_cq; | ||
307 | u32 cur_eq; | ||
308 | u32 cur_mr; | ||
309 | u32 cur_mw; | ||
310 | u32 cur_ee_context; | ||
311 | u32 cur_mcast_grp; | ||
312 | u32 cur_qp_attached_mcast_grp; | ||
313 | u32 reserved1; | ||
314 | u32 cur_ipv6_qp; | ||
315 | u32 cur_eth_qp; | ||
316 | u32 cur_hp_mr; | ||
317 | u32 reserved2[3]; | ||
318 | u32 max_rd_domain; | ||
319 | u32 max_qp; | ||
320 | u32 max_cq; | ||
321 | u32 max_eq; | ||
322 | u32 max_mr; | ||
323 | u32 max_hp_mr; | ||
324 | u32 max_mw; | ||
325 | u32 max_mrwpte; | ||
326 | u32 max_special_mrwpte; | ||
327 | u32 max_rd_ee_context; | ||
328 | u32 max_mcast_grp; | ||
329 | u32 max_total_mcast_qp_attach; | ||
330 | u32 max_mcast_qp_attach; | ||
331 | u32 max_raw_ipv6_qp; | ||
332 | u32 max_raw_ethy_qp; | ||
333 | u32 internal_clock_frequency; | ||
334 | u32 max_pd; | ||
335 | u32 max_ah; | ||
336 | u32 max_cqe; | ||
337 | u32 max_wqes_wq; | ||
338 | u32 max_partitions; | ||
339 | u32 max_rr_ee_context; | ||
340 | u32 max_rr_qp; | ||
341 | u32 max_rr_hca; | ||
342 | u32 max_act_wqs_ee_context; | ||
343 | u32 max_act_wqs_qp; | ||
344 | u32 max_sge; | ||
345 | u32 max_sge_rd; | ||
346 | u32 memory_page_size_supported; | ||
347 | u64 max_mr_size; | ||
348 | u32 local_ca_ack_delay; | ||
349 | u32 num_ports; | ||
350 | u32 vendor_id; | ||
351 | u32 vendor_part_id; | ||
352 | u32 hw_ver; | ||
353 | u64 node_guid; | ||
354 | u64 hca_cap_indicators; | ||
355 | u32 data_counter_register_size; | ||
356 | u32 max_shared_rq; | ||
357 | u32 max_isns_eq; | ||
358 | u32 max_neq; | ||
359 | } __attribute__ ((packed)); | ||
360 | |||
361 | /* query port response block */ | ||
362 | struct hipz_query_port { | ||
363 | u32 state; | ||
364 | u32 bad_pkey_cntr; | ||
365 | u32 lmc; | ||
366 | u32 lid; | ||
367 | u32 subnet_timeout; | ||
368 | u32 qkey_viol_cntr; | ||
369 | u32 sm_sl; | ||
370 | u32 sm_lid; | ||
371 | u32 capability_mask; | ||
372 | u32 init_type_reply; | ||
373 | u32 pkey_tbl_len; | ||
374 | u32 gid_tbl_len; | ||
375 | u64 gid_prefix; | ||
376 | u32 port_nr; | ||
377 | u16 pkey_entries[16]; | ||
378 | u8 reserved1[32]; | ||
379 | u32 trent_size; | ||
380 | u32 trbuf_size; | ||
381 | u64 max_msg_sz; | ||
382 | u32 max_mtu; | ||
383 | u32 vl_cap; | ||
384 | u8 reserved2[1900]; | ||
385 | u64 guid_entries[255]; | ||
386 | } __attribute__ ((packed)); | ||
387 | |||
388 | #endif | ||
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c new file mode 100644 index 000000000000..e028ff1588cc --- /dev/null +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * internal queue handling | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Reinhard Ernst <rernst@de.ibm.com> | ||
8 | * Christoph Raisch <raisch@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
13 | * BSD. | ||
14 | * | ||
15 | * OpenIB BSD License | ||
16 | * | ||
17 | * Redistribution and use in source and binary forms, with or without | ||
18 | * modification, are permitted provided that the following conditions are met: | ||
19 | * | ||
20 | * Redistributions of source code must retain the above copyright notice, this | ||
21 | * list of conditions and the following disclaimer. | ||
22 | * | ||
23 | * Redistributions in binary form must reproduce the above copyright notice, | ||
24 | * this list of conditions and the following disclaimer in the documentation | ||
25 | * and/or other materials | ||
26 | * provided with the distribution. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
29 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
32 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
33 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
34 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
35 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
36 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
37 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | */ | ||
40 | |||
41 | #include "ehca_tools.h" | ||
42 | #include "ipz_pt_fn.h" | ||
43 | |||
44 | void *ipz_qpageit_get_inc(struct ipz_queue *queue) | ||
45 | { | ||
46 | void *ret = ipz_qeit_get(queue); | ||
47 | queue->current_q_offset += queue->pagesize; | ||
48 | if (queue->current_q_offset > queue->queue_length) { | ||
49 | queue->current_q_offset -= queue->pagesize; | ||
50 | ret = NULL; | ||
51 | } | ||
52 | if (((u64)ret) % EHCA_PAGESIZE) { | ||
53 | ehca_gen_err("ERROR!! not at PAGE-Boundary"); | ||
54 | return NULL; | ||
55 | } | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | void *ipz_qeit_eq_get_inc(struct ipz_queue *queue) | ||
60 | { | ||
61 | void *ret = ipz_qeit_get(queue); | ||
62 | u64 last_entry_in_q = queue->queue_length - queue->qe_size; | ||
63 | |||
64 | queue->current_q_offset += queue->qe_size; | ||
65 | if (queue->current_q_offset > last_entry_in_q) { | ||
66 | queue->current_q_offset = 0; | ||
67 | queue->toggle_state = (~queue->toggle_state) & 1; | ||
68 | } | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | int ipz_queue_ctor(struct ipz_queue *queue, | ||
74 | const u32 nr_of_pages, | ||
75 | const u32 pagesize, const u32 qe_size, const u32 nr_of_sg) | ||
76 | { | ||
77 | int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT; | ||
78 | int f; | ||
79 | |||
80 | if (pagesize > PAGE_SIZE) { | ||
81 | ehca_gen_err("FATAL ERROR: pagesize=%x is greater " | ||
82 | "than kernel page size", pagesize); | ||
83 | return 0; | ||
84 | } | ||
85 | if (!pages_per_kpage) { | ||
86 | ehca_gen_err("FATAL ERROR: invalid kernel page size. " | ||
87 | "pages_per_kpage=%x", pages_per_kpage); | ||
88 | return 0; | ||
89 | } | ||
90 | queue->queue_length = nr_of_pages * pagesize; | ||
91 | queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); | ||
92 | if (!queue->queue_pages) { | ||
93 | ehca_gen_err("ERROR!! didn't get the memory"); | ||
94 | return 0; | ||
95 | } | ||
96 | memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *)); | ||
97 | /* | ||
98 | * allocate pages for queue: | ||
99 | * outer loop allocates whole kernel pages (page aligned) and | ||
100 | * inner loop divides a kernel page into smaller hca queue pages | ||
101 | */ | ||
102 | f = 0; | ||
103 | while (f < nr_of_pages) { | ||
104 | u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL); | ||
105 | int k; | ||
106 | if (!kpage) | ||
107 | goto ipz_queue_ctor_exit0; /*NOMEM*/ | ||
108 | for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) { | ||
109 | (queue->queue_pages)[f] = (struct ipz_page *)kpage; | ||
110 | kpage += EHCA_PAGESIZE; | ||
111 | f++; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | queue->current_q_offset = 0; | ||
116 | queue->qe_size = qe_size; | ||
117 | queue->act_nr_of_sg = nr_of_sg; | ||
118 | queue->pagesize = pagesize; | ||
119 | queue->toggle_state = 1; | ||
120 | return 1; | ||
121 | |||
122 | ipz_queue_ctor_exit0: | ||
123 | ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x", | ||
124 | queue, f, nr_of_pages); | ||
125 | for (f = 0; f < nr_of_pages; f += pages_per_kpage) { | ||
126 | if (!(queue->queue_pages)[f]) | ||
127 | break; | ||
128 | free_page((unsigned long)(queue->queue_pages)[f]); | ||
129 | } | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | int ipz_queue_dtor(struct ipz_queue *queue) | ||
134 | { | ||
135 | int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT; | ||
136 | int g; | ||
137 | int nr_pages; | ||
138 | |||
139 | if (!queue || !queue->queue_pages) { | ||
140 | ehca_gen_dbg("queue or queue_pages is NULL"); | ||
141 | return 0; | ||
142 | } | ||
143 | nr_pages = queue->queue_length / queue->pagesize; | ||
144 | for (g = 0; g < nr_pages; g += pages_per_kpage) | ||
145 | free_page((unsigned long)(queue->queue_pages)[g]); | ||
146 | vfree(queue->queue_pages); | ||
147 | |||
148 | return 1; | ||
149 | } | ||
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h new file mode 100644 index 000000000000..2f13509d5257 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * internal queue handling | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Reinhard Ernst <rernst@de.ibm.com> | ||
8 | * Christoph Raisch <raisch@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | #ifndef __IPZ_PT_FN_H__ | ||
44 | #define __IPZ_PT_FN_H__ | ||
45 | |||
46 | #define EHCA_PAGESHIFT 12 | ||
47 | #define EHCA_PAGESIZE 4096UL | ||
48 | #define EHCA_PAGEMASK (~(EHCA_PAGESIZE-1)) | ||
49 | #define EHCA_PT_ENTRIES 512UL | ||
50 | |||
51 | #include "ehca_tools.h" | ||
52 | #include "ehca_qes.h" | ||
53 | |||
54 | /* struct generic ehca page */ | ||
55 | struct ipz_page { | ||
56 | u8 entries[EHCA_PAGESIZE]; | ||
57 | }; | ||
58 | |||
59 | /* struct generic queue in linux kernel virtual memory (kv) */ | ||
60 | struct ipz_queue { | ||
61 | u64 current_q_offset; /* current queue entry */ | ||
62 | |||
63 | struct ipz_page **queue_pages; /* array of pages belonging to queue */ | ||
64 | u32 qe_size; /* queue entry size */ | ||
65 | u32 act_nr_of_sg; | ||
66 | u32 queue_length; /* queue length allocated in bytes */ | ||
67 | u32 pagesize; | ||
68 | u32 toggle_state; /* toggle flag - per page */ | ||
69 | u32 dummy3; /* 64 bit alignment */ | ||
70 | }; | ||
71 | |||
72 | /* | ||
73 | * return current Queue Entry for a certain q_offset | ||
74 | * returns address (kv) of Queue Entry | ||
75 | */ | ||
76 | static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset) | ||
77 | { | ||
78 | struct ipz_page *current_page; | ||
79 | if (q_offset >= queue->queue_length) | ||
80 | return NULL; | ||
81 | current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT]; | ||
82 | return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)]; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * return current Queue Entry | ||
87 | * returns address (kv) of Queue Entry | ||
88 | */ | ||
89 | static inline void *ipz_qeit_get(struct ipz_queue *queue) | ||
90 | { | ||
91 | return ipz_qeit_calc(queue, queue->current_q_offset); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * return current Queue Page , increment Queue Page iterator from | ||
96 | * page to page in struct ipz_queue, last increment will return 0! and | ||
97 | * NOT wrap | ||
98 | * returns address (kv) of Queue Page | ||
99 | * warning don't use in parallel with ipz_QE_get_inc() | ||
100 | */ | ||
101 | void *ipz_qpageit_get_inc(struct ipz_queue *queue); | ||
102 | |||
103 | /* | ||
104 | * return current Queue Entry, increment Queue Entry iterator by one | ||
105 | * step in struct ipz_queue, will wrap in ringbuffer | ||
106 | * returns address (kv) of Queue Entry BEFORE increment | ||
107 | * warning don't use in parallel with ipz_qpageit_get_inc() | ||
108 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
109 | */ | ||
110 | static inline void *ipz_qeit_get_inc(struct ipz_queue *queue) | ||
111 | { | ||
112 | void *ret = ipz_qeit_get(queue); | ||
113 | queue->current_q_offset += queue->qe_size; | ||
114 | if (queue->current_q_offset >= queue->queue_length) { | ||
115 | queue->current_q_offset = 0; | ||
116 | /* toggle the valid flag */ | ||
117 | queue->toggle_state = (~queue->toggle_state) & 1; | ||
118 | } | ||
119 | |||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * return current Queue Entry, increment Queue Entry iterator by one | ||
125 | * step in struct ipz_queue, will wrap in ringbuffer | ||
126 | * returns address (kv) of Queue Entry BEFORE increment | ||
127 | * returns 0 and does not increment, if wrong valid state | ||
128 | * warning don't use in parallel with ipz_qpageit_get_inc() | ||
129 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
130 | */ | ||
131 | static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue) | ||
132 | { | ||
133 | struct ehca_cqe *cqe = ipz_qeit_get(queue); | ||
134 | u32 cqe_flags = cqe->cqe_flags; | ||
135 | |||
136 | if ((cqe_flags >> 7) != (queue->toggle_state & 1)) | ||
137 | return NULL; | ||
138 | |||
139 | ipz_qeit_get_inc(queue); | ||
140 | return cqe; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * returns and resets Queue Entry iterator | ||
145 | * returns address (kv) of first Queue Entry | ||
146 | */ | ||
147 | static inline void *ipz_qeit_reset(struct ipz_queue *queue) | ||
148 | { | ||
149 | queue->current_q_offset = 0; | ||
150 | return ipz_qeit_get(queue); | ||
151 | } | ||
152 | |||
153 | /* struct generic page table */ | ||
154 | struct ipz_pt { | ||
155 | u64 entries[EHCA_PT_ENTRIES]; | ||
156 | }; | ||
157 | |||
158 | /* struct page table for a queue, only to be used in pf */ | ||
159 | struct ipz_qpt { | ||
160 | /* queue page tables (kv), use u64 because we know the element length */ | ||
161 | u64 *qpts; | ||
162 | u32 n_qpts; | ||
163 | u32 n_ptes; /* number of page table entries */ | ||
164 | u64 *current_pte_addr; | ||
165 | }; | ||
166 | |||
167 | /* | ||
168 | * constructor for a ipz_queue_t, placement new for ipz_queue_t, | ||
169 | * new for all dependent datastructors | ||
170 | * all QP Tables are the same | ||
171 | * flow: | ||
172 | * allocate+pin queue | ||
173 | * see ipz_qpt_ctor() | ||
174 | * returns true if ok, false if out of memory | ||
175 | */ | ||
176 | int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages, | ||
177 | const u32 pagesize, const u32 qe_size, | ||
178 | const u32 nr_of_sg); | ||
179 | |||
180 | /* | ||
181 | * destructor for a ipz_queue_t | ||
182 | * -# free queue | ||
183 | * see ipz_queue_ctor() | ||
184 | * returns true if ok, false if queue was NULL-ptr of free failed | ||
185 | */ | ||
186 | int ipz_queue_dtor(struct ipz_queue *queue); | ||
187 | |||
188 | /* | ||
189 | * constructor for a ipz_qpt_t, | ||
190 | * placement new for struct ipz_queue, new for all dependent datastructors | ||
191 | * all QP Tables are the same, | ||
192 | * flow: | ||
193 | * -# allocate+pin queue | ||
194 | * -# initialise ptcb | ||
195 | * -# allocate+pin PTs | ||
196 | * -# link PTs to a ring, according to HCA Arch, set bit62 id needed | ||
197 | * -# the ring must have room for exactly nr_of_PTEs | ||
198 | * see ipz_qpt_ctor() | ||
199 | */ | ||
200 | void ipz_qpt_ctor(struct ipz_qpt *qpt, | ||
201 | const u32 nr_of_qes, | ||
202 | const u32 pagesize, | ||
203 | const u32 qe_size, | ||
204 | const u8 lowbyte, const u8 toggle, | ||
205 | u32 * act_nr_of_QEs, u32 * act_nr_of_pages); | ||
206 | |||
207 | /* | ||
208 | * return current Queue Entry, increment Queue Entry iterator by one | ||
209 | * step in struct ipz_queue, will wrap in ringbuffer | ||
210 | * returns address (kv) of Queue Entry BEFORE increment | ||
211 | * warning don't use in parallel with ipz_qpageit_get_inc() | ||
212 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
213 | * fix EQ page problems | ||
214 | */ | ||
215 | void *ipz_qeit_eq_get_inc(struct ipz_queue *queue); | ||
216 | |||
217 | /* | ||
218 | * return current Event Queue Entry, increment Queue Entry iterator | ||
219 | * by one step in struct ipz_queue if valid, will wrap in ringbuffer | ||
220 | * returns address (kv) of Queue Entry BEFORE increment | ||
221 | * returns 0 and does not increment, if wrong valid state | ||
222 | * warning don't use in parallel with ipz_queue_QPageit_get_inc() | ||
223 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
224 | */ | ||
225 | static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) | ||
226 | { | ||
227 | void *ret = ipz_qeit_get(queue); | ||
228 | u32 qe = *(u8 *) ret; | ||
229 | if ((qe >> 7) != (queue->toggle_state & 1)) | ||
230 | return NULL; | ||
231 | ipz_qeit_eq_get_inc(queue); /* this is a good one */ | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | /* returns address (GX) of first queue entry */ | ||
236 | static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt) | ||
237 | { | ||
238 | return be64_to_cpu(qpt->qpts[0]); | ||
239 | } | ||
240 | |||
241 | /* returns address (kv) of first page of queue page table */ | ||
242 | static inline void *ipz_qpt_get_qpt(struct ipz_qpt *qpt) | ||
243 | { | ||
244 | return qpt->qpts; | ||
245 | } | ||
246 | |||
247 | #endif /* __IPZ_PT_FN_H__ */ | ||
diff --git a/drivers/infiniband/hw/ipath/Kconfig b/drivers/infiniband/hw/ipath/Kconfig index 1db9489f1e82..574a678e7fdd 100644 --- a/drivers/infiniband/hw/ipath/Kconfig +++ b/drivers/infiniband/hw/ipath/Kconfig | |||
@@ -1,16 +1,9 @@ | |||
1 | config IPATH_CORE | ||
2 | tristate "QLogic InfiniPath Driver" | ||
3 | depends on 64BIT && PCI_MSI && NET | ||
4 | ---help--- | ||
5 | This is a low-level driver for QLogic InfiniPath host channel | ||
6 | adapters (HCAs) based on the HT-400 and PE-800 chips. | ||
7 | |||
8 | config INFINIBAND_IPATH | 1 | config INFINIBAND_IPATH |
9 | tristate "QLogic InfiniPath Verbs Driver" | 2 | tristate "QLogic InfiniPath Driver" |
10 | depends on IPATH_CORE && INFINIBAND | 3 | depends on PCI_MSI && 64BIT && INFINIBAND |
11 | ---help--- | 4 | ---help--- |
12 | This is a driver that provides InfiniBand verbs support for | 5 | This is a driver for QLogic InfiniPath host channel adapters, |
13 | QLogic InfiniPath host channel adapters (HCAs). This | 6 | including InfiniBand verbs support. This driver allows these |
14 | allows these devices to be used with both kernel upper level | 7 | devices to be used with both kernel upper level protocols such |
15 | protocols such as IP-over-InfiniBand as well as with userspace | 8 | as IP-over-InfiniBand as well as with userspace applications |
16 | applications (in conjunction with InfiniBand userspace access). | 9 | (in conjunction with InfiniBand userspace access). |
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile index b0bf72864130..5e29cb0095e5 100644 --- a/drivers/infiniband/hw/ipath/Makefile +++ b/drivers/infiniband/hw/ipath/Makefile | |||
@@ -1,36 +1,35 @@ | |||
1 | EXTRA_CFLAGS += -DIPATH_IDSTR='"QLogic kernel.org driver"' \ | 1 | EXTRA_CFLAGS += -DIPATH_IDSTR='"QLogic kernel.org driver"' \ |
2 | -DIPATH_KERN_TYPE=0 | 2 | -DIPATH_KERN_TYPE=0 |
3 | 3 | ||
4 | obj-$(CONFIG_IPATH_CORE) += ipath_core.o | ||
5 | obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o | 4 | obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o |
6 | 5 | ||
7 | ipath_core-y := \ | 6 | ib_ipath-y := \ |
7 | ipath_cq.o \ | ||
8 | ipath_diag.o \ | 8 | ipath_diag.o \ |
9 | ipath_driver.o \ | 9 | ipath_driver.o \ |
10 | ipath_eeprom.o \ | 10 | ipath_eeprom.o \ |
11 | ipath_file_ops.o \ | 11 | ipath_file_ops.o \ |
12 | ipath_fs.o \ | 12 | ipath_fs.o \ |
13 | ipath_ht400.o \ | 13 | ipath_iba6110.o \ |
14 | ipath_iba6120.o \ | ||
14 | ipath_init_chip.o \ | 15 | ipath_init_chip.o \ |
15 | ipath_intr.o \ | 16 | ipath_intr.o \ |
16 | ipath_layer.o \ | ||
17 | ipath_pe800.o \ | ||
18 | ipath_stats.o \ | ||
19 | ipath_sysfs.o \ | ||
20 | ipath_user_pages.o | ||
21 | |||
22 | ipath_core-$(CONFIG_X86_64) += ipath_wc_x86_64.o | ||
23 | |||
24 | ib_ipath-y := \ | ||
25 | ipath_cq.o \ | ||
26 | ipath_keys.o \ | 17 | ipath_keys.o \ |
18 | ipath_layer.o \ | ||
27 | ipath_mad.o \ | 19 | ipath_mad.o \ |
20 | ipath_mmap.o \ | ||
28 | ipath_mr.o \ | 21 | ipath_mr.o \ |
29 | ipath_qp.o \ | 22 | ipath_qp.o \ |
30 | ipath_rc.o \ | 23 | ipath_rc.o \ |
31 | ipath_ruc.o \ | 24 | ipath_ruc.o \ |
32 | ipath_srq.o \ | 25 | ipath_srq.o \ |
26 | ipath_stats.o \ | ||
27 | ipath_sysfs.o \ | ||
33 | ipath_uc.o \ | 28 | ipath_uc.o \ |
34 | ipath_ud.o \ | 29 | ipath_ud.o \ |
35 | ipath_verbs.o \ | 30 | ipath_user_pages.o \ |
36 | ipath_verbs_mcast.o | 31 | ipath_verbs_mcast.o \ |
32 | ipath_verbs.o | ||
33 | |||
34 | ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o | ||
35 | ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index 062bd392e7e5..f577905e3aca 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h | |||
@@ -106,9 +106,9 @@ struct infinipath_stats { | |||
106 | __u64 sps_ether_spkts; | 106 | __u64 sps_ether_spkts; |
107 | /* number of "ethernet" packets received by driver */ | 107 | /* number of "ethernet" packets received by driver */ |
108 | __u64 sps_ether_rpkts; | 108 | __u64 sps_ether_rpkts; |
109 | /* number of SMA packets sent by driver */ | 109 | /* number of SMA packets sent by driver. Obsolete. */ |
110 | __u64 sps_sma_spkts; | 110 | __u64 sps_sma_spkts; |
111 | /* number of SMA packets received by driver */ | 111 | /* number of SMA packets received by driver. Obsolete. */ |
112 | __u64 sps_sma_rpkts; | 112 | __u64 sps_sma_rpkts; |
113 | /* number of times all ports rcvhdrq was full and packet dropped */ | 113 | /* number of times all ports rcvhdrq was full and packet dropped */ |
114 | __u64 sps_hdrqfull; | 114 | __u64 sps_hdrqfull; |
@@ -138,7 +138,7 @@ struct infinipath_stats { | |||
138 | __u64 sps_pageunlocks; | 138 | __u64 sps_pageunlocks; |
139 | /* | 139 | /* |
140 | * Number of packets dropped in kernel other than errors (ether | 140 | * Number of packets dropped in kernel other than errors (ether |
141 | * packets if ipath not configured, sma/mad, etc.) | 141 | * packets if ipath not configured, etc.) |
142 | */ | 142 | */ |
143 | __u64 sps_krdrops; | 143 | __u64 sps_krdrops; |
144 | /* pad for future growth */ | 144 | /* pad for future growth */ |
@@ -153,8 +153,6 @@ struct infinipath_stats { | |||
153 | #define IPATH_STATUS_DISABLED 0x2 /* hardware disabled */ | 153 | #define IPATH_STATUS_DISABLED 0x2 /* hardware disabled */ |
154 | /* Device has been disabled via admin request */ | 154 | /* Device has been disabled via admin request */ |
155 | #define IPATH_STATUS_ADMIN_DISABLED 0x4 | 155 | #define IPATH_STATUS_ADMIN_DISABLED 0x4 |
156 | #define IPATH_STATUS_OIB_SMA 0x8 /* ipath_mad kernel SMA running */ | ||
157 | #define IPATH_STATUS_SMA 0x10 /* user SMA running */ | ||
158 | /* Chip has been found and initted */ | 156 | /* Chip has been found and initted */ |
159 | #define IPATH_STATUS_CHIP_PRESENT 0x20 | 157 | #define IPATH_STATUS_CHIP_PRESENT 0x20 |
160 | /* IB link is at ACTIVE, usable for data traffic */ | 158 | /* IB link is at ACTIVE, usable for data traffic */ |
@@ -465,12 +463,11 @@ struct __ipath_sendpkt { | |||
465 | struct ipath_iovec sps_iov[4]; | 463 | struct ipath_iovec sps_iov[4]; |
466 | }; | 464 | }; |
467 | 465 | ||
468 | /* Passed into SMA special file's ->read and ->write methods. */ | 466 | /* Passed into diag data special file's ->write method. */ |
469 | struct ipath_sma_pkt | 467 | struct ipath_diag_pkt { |
470 | { | 468 | __u32 unit; |
471 | __u32 unit; /* unit on which to send packet */ | 469 | __u64 data; |
472 | __u64 data; /* address of payload in userspace */ | 470 | __u32 len; |
473 | __u32 len; /* length of payload */ | ||
474 | }; | 471 | }; |
475 | 472 | ||
476 | /* | 473 | /* |
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c index 3efee341c9bc..049221bc590e 100644 --- a/drivers/infiniband/hw/ipath/ipath_cq.c +++ b/drivers/infiniband/hw/ipath/ipath_cq.c | |||
@@ -42,20 +42,28 @@ | |||
42 | * @entry: work completion entry to add | 42 | * @entry: work completion entry to add |
43 | * @sig: true if @entry is a solicitated entry | 43 | * @sig: true if @entry is a solicitated entry |
44 | * | 44 | * |
45 | * This may be called with one of the qp->s_lock or qp->r_rq.lock held. | 45 | * This may be called with qp->s_lock held. |
46 | */ | 46 | */ |
47 | void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) | 47 | void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) |
48 | { | 48 | { |
49 | struct ipath_cq_wc *wc = cq->queue; | ||
49 | unsigned long flags; | 50 | unsigned long flags; |
51 | u32 head; | ||
50 | u32 next; | 52 | u32 next; |
51 | 53 | ||
52 | spin_lock_irqsave(&cq->lock, flags); | 54 | spin_lock_irqsave(&cq->lock, flags); |
53 | 55 | ||
54 | if (cq->head == cq->ibcq.cqe) | 56 | /* |
57 | * Note that the head pointer might be writable by user processes. | ||
58 | * Take care to verify it is a sane value. | ||
59 | */ | ||
60 | head = wc->head; | ||
61 | if (head >= (unsigned) cq->ibcq.cqe) { | ||
62 | head = cq->ibcq.cqe; | ||
55 | next = 0; | 63 | next = 0; |
56 | else | 64 | } else |
57 | next = cq->head + 1; | 65 | next = head + 1; |
58 | if (unlikely(next == cq->tail)) { | 66 | if (unlikely(next == wc->tail)) { |
59 | spin_unlock_irqrestore(&cq->lock, flags); | 67 | spin_unlock_irqrestore(&cq->lock, flags); |
60 | if (cq->ibcq.event_handler) { | 68 | if (cq->ibcq.event_handler) { |
61 | struct ib_event ev; | 69 | struct ib_event ev; |
@@ -67,8 +75,8 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) | |||
67 | } | 75 | } |
68 | return; | 76 | return; |
69 | } | 77 | } |
70 | cq->queue[cq->head] = *entry; | 78 | wc->queue[head] = *entry; |
71 | cq->head = next; | 79 | wc->head = next; |
72 | 80 | ||
73 | if (cq->notify == IB_CQ_NEXT_COMP || | 81 | if (cq->notify == IB_CQ_NEXT_COMP || |
74 | (cq->notify == IB_CQ_SOLICITED && solicited)) { | 82 | (cq->notify == IB_CQ_SOLICITED && solicited)) { |
@@ -101,19 +109,20 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) | |||
101 | int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) | 109 | int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) |
102 | { | 110 | { |
103 | struct ipath_cq *cq = to_icq(ibcq); | 111 | struct ipath_cq *cq = to_icq(ibcq); |
112 | struct ipath_cq_wc *wc = cq->queue; | ||
104 | unsigned long flags; | 113 | unsigned long flags; |
105 | int npolled; | 114 | int npolled; |
106 | 115 | ||
107 | spin_lock_irqsave(&cq->lock, flags); | 116 | spin_lock_irqsave(&cq->lock, flags); |
108 | 117 | ||
109 | for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { | 118 | for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { |
110 | if (cq->tail == cq->head) | 119 | if (wc->tail == wc->head) |
111 | break; | 120 | break; |
112 | *entry = cq->queue[cq->tail]; | 121 | *entry = wc->queue[wc->tail]; |
113 | if (cq->tail == cq->ibcq.cqe) | 122 | if (wc->tail >= cq->ibcq.cqe) |
114 | cq->tail = 0; | 123 | wc->tail = 0; |
115 | else | 124 | else |
116 | cq->tail++; | 125 | wc->tail++; |
117 | } | 126 | } |
118 | 127 | ||
119 | spin_unlock_irqrestore(&cq->lock, flags); | 128 | spin_unlock_irqrestore(&cq->lock, flags); |
@@ -160,38 +169,74 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, | |||
160 | { | 169 | { |
161 | struct ipath_ibdev *dev = to_idev(ibdev); | 170 | struct ipath_ibdev *dev = to_idev(ibdev); |
162 | struct ipath_cq *cq; | 171 | struct ipath_cq *cq; |
163 | struct ib_wc *wc; | 172 | struct ipath_cq_wc *wc; |
164 | struct ib_cq *ret; | 173 | struct ib_cq *ret; |
165 | 174 | ||
166 | if (entries > ib_ipath_max_cqes) { | 175 | if (entries < 1 || entries > ib_ipath_max_cqes) { |
167 | ret = ERR_PTR(-EINVAL); | 176 | ret = ERR_PTR(-EINVAL); |
168 | goto bail; | 177 | goto done; |
169 | } | 178 | } |
170 | 179 | ||
171 | if (dev->n_cqs_allocated == ib_ipath_max_cqs) { | 180 | if (dev->n_cqs_allocated == ib_ipath_max_cqs) { |
172 | ret = ERR_PTR(-ENOMEM); | 181 | ret = ERR_PTR(-ENOMEM); |
173 | goto bail; | 182 | goto done; |
174 | } | 183 | } |
175 | 184 | ||
176 | /* | 185 | /* Allocate the completion queue structure. */ |
177 | * Need to use vmalloc() if we want to support large #s of | ||
178 | * entries. | ||
179 | */ | ||
180 | cq = kmalloc(sizeof(*cq), GFP_KERNEL); | 186 | cq = kmalloc(sizeof(*cq), GFP_KERNEL); |
181 | if (!cq) { | 187 | if (!cq) { |
182 | ret = ERR_PTR(-ENOMEM); | 188 | ret = ERR_PTR(-ENOMEM); |
183 | goto bail; | 189 | goto done; |
184 | } | 190 | } |
185 | 191 | ||
186 | /* | 192 | /* |
187 | * Need to use vmalloc() if we want to support large #s of entries. | 193 | * Allocate the completion queue entries and head/tail pointers. |
194 | * This is allocated separately so that it can be resized and | ||
195 | * also mapped into user space. | ||
196 | * We need to use vmalloc() in order to support mmap and large | ||
197 | * numbers of entries. | ||
188 | */ | 198 | */ |
189 | wc = vmalloc(sizeof(*wc) * (entries + 1)); | 199 | wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries); |
190 | if (!wc) { | 200 | if (!wc) { |
191 | kfree(cq); | ||
192 | ret = ERR_PTR(-ENOMEM); | 201 | ret = ERR_PTR(-ENOMEM); |
193 | goto bail; | 202 | goto bail_cq; |
194 | } | 203 | } |
204 | |||
205 | /* | ||
206 | * Return the address of the WC as the offset to mmap. | ||
207 | * See ipath_mmap() for details. | ||
208 | */ | ||
209 | if (udata && udata->outlen >= sizeof(__u64)) { | ||
210 | struct ipath_mmap_info *ip; | ||
211 | __u64 offset = (__u64) wc; | ||
212 | int err; | ||
213 | |||
214 | err = ib_copy_to_udata(udata, &offset, sizeof(offset)); | ||
215 | if (err) { | ||
216 | ret = ERR_PTR(err); | ||
217 | goto bail_wc; | ||
218 | } | ||
219 | |||
220 | /* Allocate info for ipath_mmap(). */ | ||
221 | ip = kmalloc(sizeof(*ip), GFP_KERNEL); | ||
222 | if (!ip) { | ||
223 | ret = ERR_PTR(-ENOMEM); | ||
224 | goto bail_wc; | ||
225 | } | ||
226 | cq->ip = ip; | ||
227 | ip->context = context; | ||
228 | ip->obj = wc; | ||
229 | kref_init(&ip->ref); | ||
230 | ip->mmap_cnt = 0; | ||
231 | ip->size = PAGE_ALIGN(sizeof(*wc) + | ||
232 | sizeof(struct ib_wc) * entries); | ||
233 | spin_lock_irq(&dev->pending_lock); | ||
234 | ip->next = dev->pending_mmaps; | ||
235 | dev->pending_mmaps = ip; | ||
236 | spin_unlock_irq(&dev->pending_lock); | ||
237 | } else | ||
238 | cq->ip = NULL; | ||
239 | |||
195 | /* | 240 | /* |
196 | * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe. | 241 | * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe. |
197 | * The number of entries should be >= the number requested or return | 242 | * The number of entries should be >= the number requested or return |
@@ -202,15 +247,22 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, | |||
202 | cq->triggered = 0; | 247 | cq->triggered = 0; |
203 | spin_lock_init(&cq->lock); | 248 | spin_lock_init(&cq->lock); |
204 | tasklet_init(&cq->comptask, send_complete, (unsigned long)cq); | 249 | tasklet_init(&cq->comptask, send_complete, (unsigned long)cq); |
205 | cq->head = 0; | 250 | wc->head = 0; |
206 | cq->tail = 0; | 251 | wc->tail = 0; |
207 | cq->queue = wc; | 252 | cq->queue = wc; |
208 | 253 | ||
209 | ret = &cq->ibcq; | 254 | ret = &cq->ibcq; |
210 | 255 | ||
211 | dev->n_cqs_allocated++; | 256 | dev->n_cqs_allocated++; |
257 | goto done; | ||
212 | 258 | ||
213 | bail: | 259 | bail_wc: |
260 | vfree(wc); | ||
261 | |||
262 | bail_cq: | ||
263 | kfree(cq); | ||
264 | |||
265 | done: | ||
214 | return ret; | 266 | return ret; |
215 | } | 267 | } |
216 | 268 | ||
@@ -229,7 +281,10 @@ int ipath_destroy_cq(struct ib_cq *ibcq) | |||
229 | 281 | ||
230 | tasklet_kill(&cq->comptask); | 282 | tasklet_kill(&cq->comptask); |
231 | dev->n_cqs_allocated--; | 283 | dev->n_cqs_allocated--; |
232 | vfree(cq->queue); | 284 | if (cq->ip) |
285 | kref_put(&cq->ip->ref, ipath_release_mmap_info); | ||
286 | else | ||
287 | vfree(cq->queue); | ||
233 | kfree(cq); | 288 | kfree(cq); |
234 | 289 | ||
235 | return 0; | 290 | return 0; |
@@ -253,7 +308,7 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) | |||
253 | spin_lock_irqsave(&cq->lock, flags); | 308 | spin_lock_irqsave(&cq->lock, flags); |
254 | /* | 309 | /* |
255 | * Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow | 310 | * Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow |
256 | * any other transitions. | 311 | * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2). |
257 | */ | 312 | */ |
258 | if (cq->notify != IB_CQ_NEXT_COMP) | 313 | if (cq->notify != IB_CQ_NEXT_COMP) |
259 | cq->notify = notify; | 314 | cq->notify = notify; |
@@ -264,46 +319,86 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) | |||
264 | int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) | 319 | int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) |
265 | { | 320 | { |
266 | struct ipath_cq *cq = to_icq(ibcq); | 321 | struct ipath_cq *cq = to_icq(ibcq); |
267 | struct ib_wc *wc, *old_wc; | 322 | struct ipath_cq_wc *old_wc = cq->queue; |
268 | u32 n; | 323 | struct ipath_cq_wc *wc; |
324 | u32 head, tail, n; | ||
269 | int ret; | 325 | int ret; |
270 | 326 | ||
327 | if (cqe < 1 || cqe > ib_ipath_max_cqes) { | ||
328 | ret = -EINVAL; | ||
329 | goto bail; | ||
330 | } | ||
331 | |||
271 | /* | 332 | /* |
272 | * Need to use vmalloc() if we want to support large #s of entries. | 333 | * Need to use vmalloc() if we want to support large #s of entries. |
273 | */ | 334 | */ |
274 | wc = vmalloc(sizeof(*wc) * (cqe + 1)); | 335 | wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe); |
275 | if (!wc) { | 336 | if (!wc) { |
276 | ret = -ENOMEM; | 337 | ret = -ENOMEM; |
277 | goto bail; | 338 | goto bail; |
278 | } | 339 | } |
279 | 340 | ||
341 | /* | ||
342 | * Return the address of the WC as the offset to mmap. | ||
343 | * See ipath_mmap() for details. | ||
344 | */ | ||
345 | if (udata && udata->outlen >= sizeof(__u64)) { | ||
346 | __u64 offset = (__u64) wc; | ||
347 | |||
348 | ret = ib_copy_to_udata(udata, &offset, sizeof(offset)); | ||
349 | if (ret) | ||
350 | goto bail; | ||
351 | } | ||
352 | |||
280 | spin_lock_irq(&cq->lock); | 353 | spin_lock_irq(&cq->lock); |
281 | if (cq->head < cq->tail) | 354 | /* |
282 | n = cq->ibcq.cqe + 1 + cq->head - cq->tail; | 355 | * Make sure head and tail are sane since they |
356 | * might be user writable. | ||
357 | */ | ||
358 | head = old_wc->head; | ||
359 | if (head > (u32) cq->ibcq.cqe) | ||
360 | head = (u32) cq->ibcq.cqe; | ||
361 | tail = old_wc->tail; | ||
362 | if (tail > (u32) cq->ibcq.cqe) | ||
363 | tail = (u32) cq->ibcq.cqe; | ||
364 | if (head < tail) | ||
365 | n = cq->ibcq.cqe + 1 + head - tail; | ||
283 | else | 366 | else |
284 | n = cq->head - cq->tail; | 367 | n = head - tail; |
285 | if (unlikely((u32)cqe < n)) { | 368 | if (unlikely((u32)cqe < n)) { |
286 | spin_unlock_irq(&cq->lock); | 369 | spin_unlock_irq(&cq->lock); |
287 | vfree(wc); | 370 | vfree(wc); |
288 | ret = -EOVERFLOW; | 371 | ret = -EOVERFLOW; |
289 | goto bail; | 372 | goto bail; |
290 | } | 373 | } |
291 | for (n = 0; cq->tail != cq->head; n++) { | 374 | for (n = 0; tail != head; n++) { |
292 | wc[n] = cq->queue[cq->tail]; | 375 | wc->queue[n] = old_wc->queue[tail]; |
293 | if (cq->tail == cq->ibcq.cqe) | 376 | if (tail == (u32) cq->ibcq.cqe) |
294 | cq->tail = 0; | 377 | tail = 0; |
295 | else | 378 | else |
296 | cq->tail++; | 379 | tail++; |
297 | } | 380 | } |
298 | cq->ibcq.cqe = cqe; | 381 | cq->ibcq.cqe = cqe; |
299 | cq->head = n; | 382 | wc->head = n; |
300 | cq->tail = 0; | 383 | wc->tail = 0; |
301 | old_wc = cq->queue; | ||
302 | cq->queue = wc; | 384 | cq->queue = wc; |
303 | spin_unlock_irq(&cq->lock); | 385 | spin_unlock_irq(&cq->lock); |
304 | 386 | ||
305 | vfree(old_wc); | 387 | vfree(old_wc); |
306 | 388 | ||
389 | if (cq->ip) { | ||
390 | struct ipath_ibdev *dev = to_idev(ibcq->device); | ||
391 | struct ipath_mmap_info *ip = cq->ip; | ||
392 | |||
393 | ip->obj = wc; | ||
394 | ip->size = PAGE_ALIGN(sizeof(*wc) + | ||
395 | sizeof(struct ib_wc) * cqe); | ||
396 | spin_lock_irq(&dev->pending_lock); | ||
397 | ip->next = dev->pending_mmaps; | ||
398 | dev->pending_mmaps = ip; | ||
399 | spin_unlock_irq(&dev->pending_lock); | ||
400 | } | ||
401 | |||
307 | ret = 0; | 402 | ret = 0; |
308 | 403 | ||
309 | bail: | 404 | bail: |
diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h index f415beda0d32..df69f0d80b8b 100644 --- a/drivers/infiniband/hw/ipath/ipath_debug.h +++ b/drivers/infiniband/hw/ipath/ipath_debug.h | |||
@@ -60,7 +60,6 @@ | |||
60 | #define __IPATH_USER_SEND 0x1000 /* use user mode send */ | 60 | #define __IPATH_USER_SEND 0x1000 /* use user mode send */ |
61 | #define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */ | 61 | #define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */ |
62 | #define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */ | 62 | #define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */ |
63 | #define __IPATH_SMADBG 0x8000 /* sma packet debug */ | ||
64 | #define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) gen debug */ | 63 | #define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) gen debug */ |
65 | #define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings */ | 64 | #define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings */ |
66 | #define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors */ | 65 | #define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors */ |
@@ -84,7 +83,6 @@ | |||
84 | /* print mmap/nopage stuff, not using VDBG any more */ | 83 | /* print mmap/nopage stuff, not using VDBG any more */ |
85 | #define __IPATH_MMDBG 0x0 | 84 | #define __IPATH_MMDBG 0x0 |
86 | #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ | 85 | #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ |
87 | #define __IPATH_SMADBG 0x0 /* process startup (init)/exit messages */ | ||
88 | #define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ | 86 | #define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ |
89 | #define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */ | 87 | #define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */ |
90 | #define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */ | 88 | #define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 147dd89e21c9..29958b6e0214 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c | |||
@@ -41,11 +41,12 @@ | |||
41 | * through the /sys/bus/pci resource mmap interface. | 41 | * through the /sys/bus/pci resource mmap interface. |
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include <linux/io.h> | ||
44 | #include <linux/pci.h> | 45 | #include <linux/pci.h> |
46 | #include <linux/vmalloc.h> | ||
45 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
46 | 48 | ||
47 | #include "ipath_kernel.h" | 49 | #include "ipath_kernel.h" |
48 | #include "ipath_layer.h" | ||
49 | #include "ipath_common.h" | 50 | #include "ipath_common.h" |
50 | 51 | ||
51 | int ipath_diag_inuse; | 52 | int ipath_diag_inuse; |
@@ -274,6 +275,158 @@ bail: | |||
274 | return ret; | 275 | return ret; |
275 | } | 276 | } |
276 | 277 | ||
278 | static ssize_t ipath_diagpkt_write(struct file *fp, | ||
279 | const char __user *data, | ||
280 | size_t count, loff_t *off); | ||
281 | |||
282 | static struct file_operations diagpkt_file_ops = { | ||
283 | .owner = THIS_MODULE, | ||
284 | .write = ipath_diagpkt_write, | ||
285 | }; | ||
286 | |||
287 | static struct cdev *diagpkt_cdev; | ||
288 | static struct class_device *diagpkt_class_dev; | ||
289 | |||
290 | int __init ipath_diagpkt_add(void) | ||
291 | { | ||
292 | return ipath_cdev_init(IPATH_DIAGPKT_MINOR, | ||
293 | "ipath_diagpkt", &diagpkt_file_ops, | ||
294 | &diagpkt_cdev, &diagpkt_class_dev); | ||
295 | } | ||
296 | |||
297 | void __exit ipath_diagpkt_remove(void) | ||
298 | { | ||
299 | ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * ipath_diagpkt_write - write an IB packet | ||
304 | * @fp: the diag data device file pointer | ||
305 | * @data: ipath_diag_pkt structure saying where to get the packet | ||
306 | * @count: size of data to write | ||
307 | * @off: unused by this code | ||
308 | */ | ||
309 | static ssize_t ipath_diagpkt_write(struct file *fp, | ||
310 | const char __user *data, | ||
311 | size_t count, loff_t *off) | ||
312 | { | ||
313 | u32 __iomem *piobuf; | ||
314 | u32 plen, clen, pbufn; | ||
315 | struct ipath_diag_pkt dp; | ||
316 | u32 *tmpbuf = NULL; | ||
317 | struct ipath_devdata *dd; | ||
318 | ssize_t ret = 0; | ||
319 | u64 val; | ||
320 | |||
321 | if (count < sizeof(dp)) { | ||
322 | ret = -EINVAL; | ||
323 | goto bail; | ||
324 | } | ||
325 | |||
326 | if (copy_from_user(&dp, data, sizeof(dp))) { | ||
327 | ret = -EFAULT; | ||
328 | goto bail; | ||
329 | } | ||
330 | |||
331 | /* send count must be an exact number of dwords */ | ||
332 | if (dp.len & 3) { | ||
333 | ret = -EINVAL; | ||
334 | goto bail; | ||
335 | } | ||
336 | |||
337 | clen = dp.len >> 2; | ||
338 | |||
339 | dd = ipath_lookup(dp.unit); | ||
340 | if (!dd || !(dd->ipath_flags & IPATH_PRESENT) || | ||
341 | !dd->ipath_kregbase) { | ||
342 | ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n", | ||
343 | dp.unit); | ||
344 | ret = -ENODEV; | ||
345 | goto bail; | ||
346 | } | ||
347 | |||
348 | if (ipath_diag_inuse && !diag_set_link && | ||
349 | !(dd->ipath_flags & IPATH_LINKACTIVE)) { | ||
350 | diag_set_link = 1; | ||
351 | ipath_cdbg(VERBOSE, "Trying to set to set link active for " | ||
352 | "diag pkt\n"); | ||
353 | ipath_set_linkstate(dd, IPATH_IB_LINKARM); | ||
354 | ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); | ||
355 | } | ||
356 | |||
357 | if (!(dd->ipath_flags & IPATH_INITTED)) { | ||
358 | /* no hardware, freeze, etc. */ | ||
359 | ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit); | ||
360 | ret = -ENODEV; | ||
361 | goto bail; | ||
362 | } | ||
363 | val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; | ||
364 | if (val != IPATH_IBSTATE_INIT && val != IPATH_IBSTATE_ARM && | ||
365 | val != IPATH_IBSTATE_ACTIVE) { | ||
366 | ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n", | ||
367 | dd->ipath_unit, (unsigned long long) val); | ||
368 | ret = -EINVAL; | ||
369 | goto bail; | ||
370 | } | ||
371 | |||
372 | /* need total length before first word written */ | ||
373 | /* +1 word is for the qword padding */ | ||
374 | plen = sizeof(u32) + dp.len; | ||
375 | |||
376 | if ((plen + 4) > dd->ipath_ibmaxlen) { | ||
377 | ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n", | ||
378 | plen - 4, dd->ipath_ibmaxlen); | ||
379 | ret = -EINVAL; | ||
380 | goto bail; /* before writing pbc */ | ||
381 | } | ||
382 | tmpbuf = vmalloc(plen); | ||
383 | if (!tmpbuf) { | ||
384 | dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, " | ||
385 | "failing\n"); | ||
386 | ret = -ENOMEM; | ||
387 | goto bail; | ||
388 | } | ||
389 | |||
390 | if (copy_from_user(tmpbuf, | ||
391 | (const void __user *) (unsigned long) dp.data, | ||
392 | dp.len)) { | ||
393 | ret = -EFAULT; | ||
394 | goto bail; | ||
395 | } | ||
396 | |||
397 | piobuf = ipath_getpiobuf(dd, &pbufn); | ||
398 | if (!piobuf) { | ||
399 | ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n", | ||
400 | dd->ipath_unit); | ||
401 | ret = -EBUSY; | ||
402 | goto bail; | ||
403 | } | ||
404 | |||
405 | plen >>= 2; /* in dwords */ | ||
406 | |||
407 | if (ipath_debug & __IPATH_PKTDBG) | ||
408 | ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n", | ||
409 | dd->ipath_unit, plen - 1, pbufn); | ||
410 | |||
411 | /* we have to flush after the PBC for correctness on some cpus | ||
412 | * or WC buffer can be written out of order */ | ||
413 | writeq(plen, piobuf); | ||
414 | ipath_flush_wc(); | ||
415 | /* copy all by the trigger word, then flush, so it's written | ||
416 | * to chip before trigger word, then write trigger word, then | ||
417 | * flush again, so packet is sent. */ | ||
418 | __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); | ||
419 | ipath_flush_wc(); | ||
420 | __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); | ||
421 | ipath_flush_wc(); | ||
422 | |||
423 | ret = sizeof(dp); | ||
424 | |||
425 | bail: | ||
426 | vfree(tmpbuf); | ||
427 | return ret; | ||
428 | } | ||
429 | |||
277 | static int ipath_diag_release(struct inode *in, struct file *fp) | 430 | static int ipath_diag_release(struct inode *in, struct file *fp) |
278 | { | 431 | { |
279 | mutex_lock(&ipath_mutex); | 432 | mutex_lock(&ipath_mutex); |
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index f98518d912b5..2108466c7e33 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <linux/vmalloc.h> | 39 | #include <linux/vmalloc.h> |
40 | 40 | ||
41 | #include "ipath_kernel.h" | 41 | #include "ipath_kernel.h" |
42 | #include "ipath_layer.h" | 42 | #include "ipath_verbs.h" |
43 | #include "ipath_common.h" | 43 | #include "ipath_common.h" |
44 | 44 | ||
45 | static void ipath_update_pio_bufs(struct ipath_devdata *); | 45 | static void ipath_update_pio_bufs(struct ipath_devdata *); |
@@ -51,8 +51,6 @@ const char *ipath_get_unit_name(int unit) | |||
51 | return iname; | 51 | return iname; |
52 | } | 52 | } |
53 | 53 | ||
54 | EXPORT_SYMBOL_GPL(ipath_get_unit_name); | ||
55 | |||
56 | #define DRIVER_LOAD_MSG "QLogic " IPATH_DRV_NAME " loaded: " | 54 | #define DRIVER_LOAD_MSG "QLogic " IPATH_DRV_NAME " loaded: " |
57 | #define PFX IPATH_DRV_NAME ": " | 55 | #define PFX IPATH_DRV_NAME ": " |
58 | 56 | ||
@@ -60,13 +58,13 @@ EXPORT_SYMBOL_GPL(ipath_get_unit_name); | |||
60 | * The size has to be longer than this string, so we can append | 58 | * The size has to be longer than this string, so we can append |
61 | * board/chip information to it in the init code. | 59 | * board/chip information to it in the init code. |
62 | */ | 60 | */ |
63 | const char ipath_core_version[] = IPATH_IDSTR "\n"; | 61 | const char ib_ipath_version[] = IPATH_IDSTR "\n"; |
64 | 62 | ||
65 | static struct idr unit_table; | 63 | static struct idr unit_table; |
66 | DEFINE_SPINLOCK(ipath_devs_lock); | 64 | DEFINE_SPINLOCK(ipath_devs_lock); |
67 | LIST_HEAD(ipath_dev_list); | 65 | LIST_HEAD(ipath_dev_list); |
68 | 66 | ||
69 | wait_queue_head_t ipath_sma_state_wait; | 67 | wait_queue_head_t ipath_state_wait; |
70 | 68 | ||
71 | unsigned ipath_debug = __IPATH_INFO; | 69 | unsigned ipath_debug = __IPATH_INFO; |
72 | 70 | ||
@@ -403,10 +401,10 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, | |||
403 | /* setup the chip-specific functions, as early as possible. */ | 401 | /* setup the chip-specific functions, as early as possible. */ |
404 | switch (ent->device) { | 402 | switch (ent->device) { |
405 | case PCI_DEVICE_ID_INFINIPATH_HT: | 403 | case PCI_DEVICE_ID_INFINIPATH_HT: |
406 | ipath_init_ht400_funcs(dd); | 404 | ipath_init_iba6110_funcs(dd); |
407 | break; | 405 | break; |
408 | case PCI_DEVICE_ID_INFINIPATH_PE800: | 406 | case PCI_DEVICE_ID_INFINIPATH_PE800: |
409 | ipath_init_pe800_funcs(dd); | 407 | ipath_init_iba6120_funcs(dd); |
410 | break; | 408 | break; |
411 | default: | 409 | default: |
412 | ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, " | 410 | ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, " |
@@ -440,7 +438,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, | |||
440 | } | 438 | } |
441 | dd->ipath_pcirev = rev; | 439 | dd->ipath_pcirev = rev; |
442 | 440 | ||
441 | #if defined(__powerpc__) | ||
442 | /* There isn't a generic way to specify writethrough mappings */ | ||
443 | dd->ipath_kregbase = __ioremap(addr, len, | ||
444 | (_PAGE_NO_CACHE|_PAGE_WRITETHRU)); | ||
445 | #else | ||
443 | dd->ipath_kregbase = ioremap_nocache(addr, len); | 446 | dd->ipath_kregbase = ioremap_nocache(addr, len); |
447 | #endif | ||
444 | 448 | ||
445 | if (!dd->ipath_kregbase) { | 449 | if (!dd->ipath_kregbase) { |
446 | ipath_dbg("Unable to map io addr %llx to kvirt, failing\n", | 450 | ipath_dbg("Unable to map io addr %llx to kvirt, failing\n", |
@@ -503,7 +507,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, | |||
503 | ipathfs_add_device(dd); | 507 | ipathfs_add_device(dd); |
504 | ipath_user_add(dd); | 508 | ipath_user_add(dd); |
505 | ipath_diag_add(dd); | 509 | ipath_diag_add(dd); |
506 | ipath_layer_add(dd); | 510 | ipath_register_ib_device(dd); |
507 | 511 | ||
508 | goto bail; | 512 | goto bail; |
509 | 513 | ||
@@ -532,7 +536,7 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev) | |||
532 | return; | 536 | return; |
533 | 537 | ||
534 | dd = pci_get_drvdata(pdev); | 538 | dd = pci_get_drvdata(pdev); |
535 | ipath_layer_remove(dd); | 539 | ipath_unregister_ib_device(dd->verbs_dev); |
536 | ipath_diag_remove(dd); | 540 | ipath_diag_remove(dd); |
537 | ipath_user_remove(dd); | 541 | ipath_user_remove(dd); |
538 | ipathfs_remove_device(dd); | 542 | ipathfs_remove_device(dd); |
@@ -607,21 +611,23 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first, | |||
607 | * | 611 | * |
608 | * wait up to msecs milliseconds for IB link state change to occur for | 612 | * wait up to msecs milliseconds for IB link state change to occur for |
609 | * now, take the easy polling route. Currently used only by | 613 | * now, take the easy polling route. Currently used only by |
610 | * ipath_layer_set_linkstate. Returns 0 if state reached, otherwise | 614 | * ipath_set_linkstate. Returns 0 if state reached, otherwise |
611 | * -ETIMEDOUT state can have multiple states set, for any of several | 615 | * -ETIMEDOUT state can have multiple states set, for any of several |
612 | * transitions. | 616 | * transitions. |
613 | */ | 617 | */ |
614 | int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs) | 618 | static int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, |
619 | int msecs) | ||
615 | { | 620 | { |
616 | dd->ipath_sma_state_wanted = state; | 621 | dd->ipath_state_wanted = state; |
617 | wait_event_interruptible_timeout(ipath_sma_state_wait, | 622 | wait_event_interruptible_timeout(ipath_state_wait, |
618 | (dd->ipath_flags & state), | 623 | (dd->ipath_flags & state), |
619 | msecs_to_jiffies(msecs)); | 624 | msecs_to_jiffies(msecs)); |
620 | dd->ipath_sma_state_wanted = 0; | 625 | dd->ipath_state_wanted = 0; |
621 | 626 | ||
622 | if (!(dd->ipath_flags & state)) { | 627 | if (!(dd->ipath_flags & state)) { |
623 | u64 val; | 628 | u64 val; |
624 | ipath_cdbg(SMA, "Didn't reach linkstate %s within %u ms\n", | 629 | ipath_cdbg(VERBOSE, "Didn't reach linkstate %s within %u" |
630 | " ms\n", | ||
625 | /* test INIT ahead of DOWN, both can be set */ | 631 | /* test INIT ahead of DOWN, both can be set */ |
626 | (state & IPATH_LINKINIT) ? "INIT" : | 632 | (state & IPATH_LINKINIT) ? "INIT" : |
627 | ((state & IPATH_LINKDOWN) ? "DOWN" : | 633 | ((state & IPATH_LINKDOWN) ? "DOWN" : |
@@ -807,58 +813,6 @@ bail: | |||
807 | return skb; | 813 | return skb; |
808 | } | 814 | } |
809 | 815 | ||
810 | /** | ||
811 | * ipath_rcv_layer - receive a packet for the layered (ethernet) driver | ||
812 | * @dd: the infinipath device | ||
813 | * @etail: the sk_buff number | ||
814 | * @tlen: the total packet length | ||
815 | * @hdr: the ethernet header | ||
816 | * | ||
817 | * Separate routine for better overall optimization | ||
818 | */ | ||
819 | static void ipath_rcv_layer(struct ipath_devdata *dd, u32 etail, | ||
820 | u32 tlen, struct ether_header *hdr) | ||
821 | { | ||
822 | u32 elen; | ||
823 | u8 pad, *bthbytes; | ||
824 | struct sk_buff *skb, *nskb; | ||
825 | |||
826 | if (dd->ipath_port0_skbs && | ||
827 | hdr->sub_opcode == IPATH_ITH4X_OPCODE_ENCAP) { | ||
828 | /* | ||
829 | * Allocate a new sk_buff to replace the one we give | ||
830 | * to the network stack. | ||
831 | */ | ||
832 | nskb = ipath_alloc_skb(dd, GFP_ATOMIC); | ||
833 | if (!nskb) { | ||
834 | /* count OK packets that we drop */ | ||
835 | ipath_stats.sps_krdrops++; | ||
836 | return; | ||
837 | } | ||
838 | |||
839 | bthbytes = (u8 *) hdr->bth; | ||
840 | pad = (bthbytes[1] >> 4) & 3; | ||
841 | /* +CRC32 */ | ||
842 | elen = tlen - (sizeof(*hdr) + pad + sizeof(u32)); | ||
843 | |||
844 | skb = dd->ipath_port0_skbs[etail]; | ||
845 | dd->ipath_port0_skbs[etail] = nskb; | ||
846 | skb_put(skb, elen); | ||
847 | |||
848 | dd->ipath_f_put_tid(dd, etail + (u64 __iomem *) | ||
849 | ((char __iomem *) dd->ipath_kregbase | ||
850 | + dd->ipath_rcvegrbase), 0, | ||
851 | virt_to_phys(nskb->data)); | ||
852 | |||
853 | __ipath_layer_rcv(dd, hdr, skb); | ||
854 | |||
855 | /* another ether packet received */ | ||
856 | ipath_stats.sps_ether_rpkts++; | ||
857 | } | ||
858 | else if (hdr->sub_opcode == IPATH_ITH4X_OPCODE_LID_ARP) | ||
859 | __ipath_layer_rcv_lid(dd, hdr); | ||
860 | } | ||
861 | |||
862 | static void ipath_rcv_hdrerr(struct ipath_devdata *dd, | 816 | static void ipath_rcv_hdrerr(struct ipath_devdata *dd, |
863 | u32 eflags, | 817 | u32 eflags, |
864 | u32 l, | 818 | u32 l, |
@@ -972,26 +926,17 @@ reloop: | |||
972 | if (unlikely(eflags)) | 926 | if (unlikely(eflags)) |
973 | ipath_rcv_hdrerr(dd, eflags, l, etail, rc); | 927 | ipath_rcv_hdrerr(dd, eflags, l, etail, rc); |
974 | else if (etype == RCVHQ_RCV_TYPE_NON_KD) { | 928 | else if (etype == RCVHQ_RCV_TYPE_NON_KD) { |
975 | int ret = __ipath_verbs_rcv(dd, rc + 1, | 929 | ipath_ib_rcv(dd->verbs_dev, rc + 1, ebuf, tlen); |
976 | ebuf, tlen); | 930 | if (dd->ipath_lli_counter) |
977 | if (ret == -ENODEV) | 931 | dd->ipath_lli_counter--; |
978 | ipath_cdbg(VERBOSE, | 932 | ipath_cdbg(PKT, "typ %x, opcode %x (eager, " |
979 | "received IB packet, " | 933 | "qp=%x), len %x; ignored\n", |
980 | "not SMA (QP=%x)\n", qp); | 934 | etype, bthbytes[0], qp, tlen); |
981 | if (dd->ipath_lli_counter) | ||
982 | dd->ipath_lli_counter--; | ||
983 | |||
984 | } else if (etype == RCVHQ_RCV_TYPE_EAGER) { | ||
985 | if (qp == IPATH_KD_QP && | ||
986 | bthbytes[0] == ipath_layer_rcv_opcode && | ||
987 | ebuf) | ||
988 | ipath_rcv_layer(dd, etail, tlen, | ||
989 | (struct ether_header *)hdr); | ||
990 | else | ||
991 | ipath_cdbg(PKT, "typ %x, opcode %x (eager, " | ||
992 | "qp=%x), len %x; ignored\n", | ||
993 | etype, bthbytes[0], qp, tlen); | ||
994 | } | 935 | } |
936 | else if (etype == RCVHQ_RCV_TYPE_EAGER) | ||
937 | ipath_cdbg(PKT, "typ %x, opcode %x (eager, " | ||
938 | "qp=%x), len %x; ignored\n", | ||
939 | etype, bthbytes[0], qp, tlen); | ||
995 | else if (etype == RCVHQ_RCV_TYPE_EXPECTED) | 940 | else if (etype == RCVHQ_RCV_TYPE_EXPECTED) |
996 | ipath_dbg("Bug: Expected TID, opcode %x; ignored\n", | 941 | ipath_dbg("Bug: Expected TID, opcode %x; ignored\n", |
997 | be32_to_cpu(hdr->bth[0]) & 0xff); | 942 | be32_to_cpu(hdr->bth[0]) & 0xff); |
@@ -1024,7 +969,8 @@ reloop: | |||
1024 | */ | 969 | */ |
1025 | if (l == hdrqtail || (i && !(i&0xf))) { | 970 | if (l == hdrqtail || (i && !(i&0xf))) { |
1026 | u64 lval; | 971 | u64 lval; |
1027 | if (l == hdrqtail) /* PE-800 interrupt only on last */ | 972 | if (l == hdrqtail) |
973 | /* request IBA6120 interrupt only on last */ | ||
1028 | lval = dd->ipath_rhdrhead_intr_off | l; | 974 | lval = dd->ipath_rhdrhead_intr_off | l; |
1029 | else | 975 | else |
1030 | lval = l; | 976 | lval = l; |
@@ -1038,7 +984,7 @@ reloop: | |||
1038 | } | 984 | } |
1039 | 985 | ||
1040 | if (!dd->ipath_rhdrhead_intr_off && !reloop) { | 986 | if (!dd->ipath_rhdrhead_intr_off && !reloop) { |
1041 | /* HT-400 workaround; we can have a race clearing chip | 987 | /* IBA6110 workaround; we can have a race clearing chip |
1042 | * interrupt with another interrupt about to be delivered, | 988 | * interrupt with another interrupt about to be delivered, |
1043 | * and can clear it before it is delivered on the GPIO | 989 | * and can clear it before it is delivered on the GPIO |
1044 | * workaround. By doing the extra check here for the | 990 | * workaround. By doing the extra check here for the |
@@ -1211,7 +1157,7 @@ int ipath_setrcvhdrsize(struct ipath_devdata *dd, unsigned rhdrsize) | |||
1211 | * | 1157 | * |
1212 | * do appropriate marking as busy, etc. | 1158 | * do appropriate marking as busy, etc. |
1213 | * returns buffer number if one found (>=0), negative number is error. | 1159 | * returns buffer number if one found (>=0), negative number is error. |
1214 | * Used by ipath_sma_send_pkt and ipath_layer_send | 1160 | * Used by ipath_layer_send |
1215 | */ | 1161 | */ |
1216 | u32 __iomem *ipath_getpiobuf(struct ipath_devdata *dd, u32 * pbufnum) | 1162 | u32 __iomem *ipath_getpiobuf(struct ipath_devdata *dd, u32 * pbufnum) |
1217 | { | 1163 | { |
@@ -1317,13 +1263,6 @@ rescan: | |||
1317 | goto bail; | 1263 | goto bail; |
1318 | } | 1264 | } |
1319 | 1265 | ||
1320 | if (updated) | ||
1321 | /* | ||
1322 | * ran out of bufs, now some (at least this one we just | ||
1323 | * got) are now available, so tell the layered driver. | ||
1324 | */ | ||
1325 | __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); | ||
1326 | |||
1327 | /* | 1266 | /* |
1328 | * set next starting place. Since it's just an optimization, | 1267 | * set next starting place. Since it's just an optimization, |
1329 | * it doesn't matter who wins on this, so no locking | 1268 | * it doesn't matter who wins on this, so no locking |
@@ -1500,7 +1439,7 @@ int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd) | |||
1500 | return ret; | 1439 | return ret; |
1501 | } | 1440 | } |
1502 | 1441 | ||
1503 | void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) | 1442 | static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) |
1504 | { | 1443 | { |
1505 | static const char *what[4] = { | 1444 | static const char *what[4] = { |
1506 | [0] = "DOWN", | 1445 | [0] = "DOWN", |
@@ -1511,7 +1450,7 @@ void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) | |||
1511 | int linkcmd = (which >> INFINIPATH_IBCC_LINKCMD_SHIFT) & | 1450 | int linkcmd = (which >> INFINIPATH_IBCC_LINKCMD_SHIFT) & |
1512 | INFINIPATH_IBCC_LINKCMD_MASK; | 1451 | INFINIPATH_IBCC_LINKCMD_MASK; |
1513 | 1452 | ||
1514 | ipath_cdbg(SMA, "Trying to move unit %u to %s, current ltstate " | 1453 | ipath_cdbg(VERBOSE, "Trying to move unit %u to %s, current ltstate " |
1515 | "is %s\n", dd->ipath_unit, | 1454 | "is %s\n", dd->ipath_unit, |
1516 | what[linkcmd], | 1455 | what[linkcmd], |
1517 | ipath_ibcstatus_str[ | 1456 | ipath_ibcstatus_str[ |
@@ -1520,7 +1459,7 @@ void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) | |||
1520 | INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & | 1459 | INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & |
1521 | INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]); | 1460 | INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]); |
1522 | /* flush all queued sends when going to DOWN or INIT, to be sure that | 1461 | /* flush all queued sends when going to DOWN or INIT, to be sure that |
1523 | * they don't block SMA and other MAD packets */ | 1462 | * they don't block MAD packets */ |
1524 | if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT) { | 1463 | if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT) { |
1525 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 1464 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
1526 | INFINIPATH_S_ABORT); | 1465 | INFINIPATH_S_ABORT); |
@@ -1534,6 +1473,180 @@ void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) | |||
1534 | dd->ipath_ibcctrl | which); | 1473 | dd->ipath_ibcctrl | which); |
1535 | } | 1474 | } |
1536 | 1475 | ||
1476 | int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) | ||
1477 | { | ||
1478 | u32 lstate; | ||
1479 | int ret; | ||
1480 | |||
1481 | switch (newstate) { | ||
1482 | case IPATH_IB_LINKDOWN: | ||
1483 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL << | ||
1484 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | ||
1485 | /* don't wait */ | ||
1486 | ret = 0; | ||
1487 | goto bail; | ||
1488 | |||
1489 | case IPATH_IB_LINKDOWN_SLEEP: | ||
1490 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP << | ||
1491 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | ||
1492 | /* don't wait */ | ||
1493 | ret = 0; | ||
1494 | goto bail; | ||
1495 | |||
1496 | case IPATH_IB_LINKDOWN_DISABLE: | ||
1497 | ipath_set_ib_lstate(dd, | ||
1498 | INFINIPATH_IBCC_LINKINITCMD_DISABLE << | ||
1499 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | ||
1500 | /* don't wait */ | ||
1501 | ret = 0; | ||
1502 | goto bail; | ||
1503 | |||
1504 | case IPATH_IB_LINKINIT: | ||
1505 | if (dd->ipath_flags & IPATH_LINKINIT) { | ||
1506 | ret = 0; | ||
1507 | goto bail; | ||
1508 | } | ||
1509 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT << | ||
1510 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
1511 | lstate = IPATH_LINKINIT; | ||
1512 | break; | ||
1513 | |||
1514 | case IPATH_IB_LINKARM: | ||
1515 | if (dd->ipath_flags & IPATH_LINKARMED) { | ||
1516 | ret = 0; | ||
1517 | goto bail; | ||
1518 | } | ||
1519 | if (!(dd->ipath_flags & | ||
1520 | (IPATH_LINKINIT | IPATH_LINKACTIVE))) { | ||
1521 | ret = -EINVAL; | ||
1522 | goto bail; | ||
1523 | } | ||
1524 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED << | ||
1525 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
1526 | /* | ||
1527 | * Since the port can transition to ACTIVE by receiving | ||
1528 | * a non VL 15 packet, wait for either state. | ||
1529 | */ | ||
1530 | lstate = IPATH_LINKARMED | IPATH_LINKACTIVE; | ||
1531 | break; | ||
1532 | |||
1533 | case IPATH_IB_LINKACTIVE: | ||
1534 | if (dd->ipath_flags & IPATH_LINKACTIVE) { | ||
1535 | ret = 0; | ||
1536 | goto bail; | ||
1537 | } | ||
1538 | if (!(dd->ipath_flags & IPATH_LINKARMED)) { | ||
1539 | ret = -EINVAL; | ||
1540 | goto bail; | ||
1541 | } | ||
1542 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE << | ||
1543 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
1544 | lstate = IPATH_LINKACTIVE; | ||
1545 | break; | ||
1546 | |||
1547 | default: | ||
1548 | ipath_dbg("Invalid linkstate 0x%x requested\n", newstate); | ||
1549 | ret = -EINVAL; | ||
1550 | goto bail; | ||
1551 | } | ||
1552 | ret = ipath_wait_linkstate(dd, lstate, 2000); | ||
1553 | |||
1554 | bail: | ||
1555 | return ret; | ||
1556 | } | ||
1557 | |||
1558 | /** | ||
1559 | * ipath_set_mtu - set the MTU | ||
1560 | * @dd: the infinipath device | ||
1561 | * @arg: the new MTU | ||
1562 | * | ||
1563 | * we can handle "any" incoming size, the issue here is whether we | ||
1564 | * need to restrict our outgoing size. For now, we don't do any | ||
1565 | * sanity checking on this, and we don't deal with what happens to | ||
1566 | * programs that are already running when the size changes. | ||
1567 | * NOTE: changing the MTU will usually cause the IBC to go back to | ||
1568 | * link initialize (IPATH_IBSTATE_INIT) state... | ||
1569 | */ | ||
1570 | int ipath_set_mtu(struct ipath_devdata *dd, u16 arg) | ||
1571 | { | ||
1572 | u32 piosize; | ||
1573 | int changed = 0; | ||
1574 | int ret; | ||
1575 | |||
1576 | /* | ||
1577 | * mtu is IB data payload max. It's the largest power of 2 less | ||
1578 | * than piosize (or even larger, since it only really controls the | ||
1579 | * largest we can receive; we can send the max of the mtu and | ||
1580 | * piosize). We check that it's one of the valid IB sizes. | ||
1581 | */ | ||
1582 | if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 && | ||
1583 | arg != 4096) { | ||
1584 | ipath_dbg("Trying to set invalid mtu %u, failing\n", arg); | ||
1585 | ret = -EINVAL; | ||
1586 | goto bail; | ||
1587 | } | ||
1588 | if (dd->ipath_ibmtu == arg) { | ||
1589 | ret = 0; /* same as current */ | ||
1590 | goto bail; | ||
1591 | } | ||
1592 | |||
1593 | piosize = dd->ipath_ibmaxlen; | ||
1594 | dd->ipath_ibmtu = arg; | ||
1595 | |||
1596 | if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) { | ||
1597 | /* Only if it's not the initial value (or reset to it) */ | ||
1598 | if (piosize != dd->ipath_init_ibmaxlen) { | ||
1599 | dd->ipath_ibmaxlen = piosize; | ||
1600 | changed = 1; | ||
1601 | } | ||
1602 | } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) { | ||
1603 | piosize = arg + IPATH_PIO_MAXIBHDR; | ||
1604 | ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x " | ||
1605 | "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize, | ||
1606 | arg); | ||
1607 | dd->ipath_ibmaxlen = piosize; | ||
1608 | changed = 1; | ||
1609 | } | ||
1610 | |||
1611 | if (changed) { | ||
1612 | /* | ||
1613 | * set the IBC maxpktlength to the size of our pio | ||
1614 | * buffers in words | ||
1615 | */ | ||
1616 | u64 ibc = dd->ipath_ibcctrl; | ||
1617 | ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK << | ||
1618 | INFINIPATH_IBCC_MAXPKTLEN_SHIFT); | ||
1619 | |||
1620 | piosize = piosize - 2 * sizeof(u32); /* ignore pbc */ | ||
1621 | dd->ipath_ibmaxlen = piosize; | ||
1622 | piosize /= sizeof(u32); /* in words */ | ||
1623 | /* | ||
1624 | * for ICRC, which we only send in diag test pkt mode, and | ||
1625 | * we don't need to worry about that for mtu | ||
1626 | */ | ||
1627 | piosize += 1; | ||
1628 | |||
1629 | ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT; | ||
1630 | dd->ipath_ibcctrl = ibc; | ||
1631 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
1632 | dd->ipath_ibcctrl); | ||
1633 | dd->ipath_f_tidtemplate(dd); | ||
1634 | } | ||
1635 | |||
1636 | ret = 0; | ||
1637 | |||
1638 | bail: | ||
1639 | return ret; | ||
1640 | } | ||
1641 | |||
1642 | int ipath_set_lid(struct ipath_devdata *dd, u32 arg, u8 lmc) | ||
1643 | { | ||
1644 | dd->ipath_lid = arg; | ||
1645 | dd->ipath_lmc = lmc; | ||
1646 | |||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1537 | /** | 1650 | /** |
1538 | * ipath_read_kreg64_port - read a device's per-port 64-bit kernel register | 1651 | * ipath_read_kreg64_port - read a device's per-port 64-bit kernel register |
1539 | * @dd: the infinipath device | 1652 | * @dd: the infinipath device |
@@ -1637,13 +1750,6 @@ void ipath_shutdown_device(struct ipath_devdata *dd) | |||
1637 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE << | 1750 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE << |
1638 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | 1751 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); |
1639 | 1752 | ||
1640 | /* | ||
1641 | * we are shutting down, so tell the layered driver. We don't do | ||
1642 | * this on just a link state change, much like ethernet, a cable | ||
1643 | * unplug, etc. doesn't change driver state | ||
1644 | */ | ||
1645 | ipath_layer_intr(dd, IPATH_LAYER_INT_IF_DOWN); | ||
1646 | |||
1647 | /* disable IBC */ | 1753 | /* disable IBC */ |
1648 | dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; | 1754 | dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; |
1649 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, | 1755 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, |
@@ -1743,7 +1849,7 @@ static int __init infinipath_init(void) | |||
1743 | { | 1849 | { |
1744 | int ret; | 1850 | int ret; |
1745 | 1851 | ||
1746 | ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ipath_core_version); | 1852 | ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version); |
1747 | 1853 | ||
1748 | /* | 1854 | /* |
1749 | * These must be called before the driver is registered with | 1855 | * These must be called before the driver is registered with |
@@ -1776,8 +1882,18 @@ static int __init infinipath_init(void) | |||
1776 | goto bail_group; | 1882 | goto bail_group; |
1777 | } | 1883 | } |
1778 | 1884 | ||
1885 | ret = ipath_diagpkt_add(); | ||
1886 | if (ret < 0) { | ||
1887 | printk(KERN_ERR IPATH_DRV_NAME ": Unable to create " | ||
1888 | "diag data device: error %d\n", -ret); | ||
1889 | goto bail_ipathfs; | ||
1890 | } | ||
1891 | |||
1779 | goto bail; | 1892 | goto bail; |
1780 | 1893 | ||
1894 | bail_ipathfs: | ||
1895 | ipath_exit_ipathfs(); | ||
1896 | |||
1781 | bail_group: | 1897 | bail_group: |
1782 | ipath_driver_remove_group(&ipath_driver.driver); | 1898 | ipath_driver_remove_group(&ipath_driver.driver); |
1783 | 1899 | ||
@@ -1888,6 +2004,8 @@ static void __exit infinipath_cleanup(void) | |||
1888 | struct ipath_devdata *dd, *tmp; | 2004 | struct ipath_devdata *dd, *tmp; |
1889 | unsigned long flags; | 2005 | unsigned long flags; |
1890 | 2006 | ||
2007 | ipath_diagpkt_remove(); | ||
2008 | |||
1891 | ipath_exit_ipathfs(); | 2009 | ipath_exit_ipathfs(); |
1892 | 2010 | ||
1893 | ipath_driver_remove_group(&ipath_driver.driver); | 2011 | ipath_driver_remove_group(&ipath_driver.driver); |
@@ -1998,5 +2116,22 @@ bail: | |||
1998 | return ret; | 2116 | return ret; |
1999 | } | 2117 | } |
2000 | 2118 | ||
2119 | int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv) | ||
2120 | { | ||
2121 | u64 val; | ||
2122 | if ( new_pol_inv > INFINIPATH_XGXS_RX_POL_MASK ) { | ||
2123 | return -1; | ||
2124 | } | ||
2125 | if ( dd->ipath_rx_pol_inv != new_pol_inv ) { | ||
2126 | dd->ipath_rx_pol_inv = new_pol_inv; | ||
2127 | val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); | ||
2128 | val &= ~(INFINIPATH_XGXS_RX_POL_MASK << | ||
2129 | INFINIPATH_XGXS_RX_POL_SHIFT); | ||
2130 | val |= ((u64)dd->ipath_rx_pol_inv) << | ||
2131 | INFINIPATH_XGXS_RX_POL_SHIFT; | ||
2132 | ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); | ||
2133 | } | ||
2134 | return 0; | ||
2135 | } | ||
2001 | module_init(infinipath_init); | 2136 | module_init(infinipath_init); |
2002 | module_exit(infinipath_cleanup); | 2137 | module_exit(infinipath_cleanup); |
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index bbaa70e57db1..29930e22318e 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
40 | 40 | ||
41 | #include "ipath_kernel.h" | 41 | #include "ipath_kernel.h" |
42 | #include "ipath_layer.h" | ||
43 | #include "ipath_common.h" | 42 | #include "ipath_common.h" |
44 | 43 | ||
45 | static int ipath_open(struct inode *, struct file *); | 44 | static int ipath_open(struct inode *, struct file *); |
@@ -985,15 +984,17 @@ static int mmap_piobufs(struct vm_area_struct *vma, | |||
985 | * write combining behavior we want on the PIO buffers! | 984 | * write combining behavior we want on the PIO buffers! |
986 | */ | 985 | */ |
987 | 986 | ||
988 | if (vma->vm_flags & VM_READ) { | 987 | #if defined(__powerpc__) |
989 | dev_info(&dd->pcidev->dev, | 988 | /* There isn't a generic way to specify writethrough mappings */ |
990 | "Can't map piobufs as readable (flags=%lx)\n", | 989 | pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; |
991 | vma->vm_flags); | 990 | pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; |
992 | ret = -EPERM; | 991 | pgprot_val(vma->vm_page_prot) &= ~_PAGE_GUARDED; |
993 | goto bail; | 992 | #endif |
994 | } | ||
995 | 993 | ||
996 | /* don't allow them to later change to readable with mprotect */ | 994 | /* |
995 | * don't allow them to later change to readable with mprotect (for when | ||
996 | * not initially mapped readable, as is normally the case) | ||
997 | */ | ||
997 | vma->vm_flags &= ~VM_MAYREAD; | 998 | vma->vm_flags &= ~VM_MAYREAD; |
998 | vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; | 999 | vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; |
999 | 1000 | ||
@@ -1109,7 +1110,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma) | |||
1109 | ret = mmap_rcvegrbufs(vma, pd); | 1110 | ret = mmap_rcvegrbufs(vma, pd); |
1110 | else if (pgaddr == (u64) pd->port_rcvhdrq_phys) { | 1111 | else if (pgaddr == (u64) pd->port_rcvhdrq_phys) { |
1111 | /* | 1112 | /* |
1112 | * The rcvhdrq itself; readonly except on HT-400 (so have | 1113 | * The rcvhdrq itself; readonly except on HT (so have |
1113 | * to allow writable mapping), multiple pages, contiguous | 1114 | * to allow writable mapping), multiple pages, contiguous |
1114 | * from an i/o perspective. | 1115 | * from an i/o perspective. |
1115 | */ | 1116 | */ |
@@ -1149,6 +1150,7 @@ static unsigned int ipath_poll(struct file *fp, | |||
1149 | struct ipath_portdata *pd; | 1150 | struct ipath_portdata *pd; |
1150 | u32 head, tail; | 1151 | u32 head, tail; |
1151 | int bit; | 1152 | int bit; |
1153 | unsigned pollflag = 0; | ||
1152 | struct ipath_devdata *dd; | 1154 | struct ipath_devdata *dd; |
1153 | 1155 | ||
1154 | pd = port_fp(fp); | 1156 | pd = port_fp(fp); |
@@ -1185,9 +1187,12 @@ static unsigned int ipath_poll(struct file *fp, | |||
1185 | clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); | 1187 | clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); |
1186 | pd->port_rcvwait_to++; | 1188 | pd->port_rcvwait_to++; |
1187 | } | 1189 | } |
1190 | else | ||
1191 | pollflag = POLLIN | POLLRDNORM; | ||
1188 | } | 1192 | } |
1189 | else { | 1193 | else { |
1190 | /* it's already happened; don't do wait_event overhead */ | 1194 | /* it's already happened; don't do wait_event overhead */ |
1195 | pollflag = POLLIN | POLLRDNORM; | ||
1191 | pd->port_rcvnowait++; | 1196 | pd->port_rcvnowait++; |
1192 | } | 1197 | } |
1193 | 1198 | ||
@@ -1195,7 +1200,7 @@ static unsigned int ipath_poll(struct file *fp, | |||
1195 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, | 1200 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, |
1196 | dd->ipath_rcvctrl); | 1201 | dd->ipath_rcvctrl); |
1197 | 1202 | ||
1198 | return 0; | 1203 | return pollflag; |
1199 | } | 1204 | } |
1200 | 1205 | ||
1201 | static int try_alloc_port(struct ipath_devdata *dd, int port, | 1206 | static int try_alloc_port(struct ipath_devdata *dd, int port, |
@@ -1297,14 +1302,14 @@ static int find_best_unit(struct file *fp) | |||
1297 | * This code is present to allow a knowledgeable person to | 1302 | * This code is present to allow a knowledgeable person to |
1298 | * specify the layout of processes to processors before opening | 1303 | * specify the layout of processes to processors before opening |
1299 | * this driver, and then we'll assign the process to the "closest" | 1304 | * this driver, and then we'll assign the process to the "closest" |
1300 | * HT-400 to that processor (we assume reasonable connectivity, | 1305 | * InfiniPath chip to that processor (we assume reasonable connectivity, |
1301 | * for now). This code assumes that if affinity has been set | 1306 | * for now). This code assumes that if affinity has been set |
1302 | * before this point, that at most one cpu is set; for now this | 1307 | * before this point, that at most one cpu is set; for now this |
1303 | * is reasonable. I check for both cpus_empty() and cpus_full(), | 1308 | * is reasonable. I check for both cpus_empty() and cpus_full(), |
1304 | * in case some kernel variant sets none of the bits when no | 1309 | * in case some kernel variant sets none of the bits when no |
1305 | * affinity is set. 2.6.11 and 12 kernels have all present | 1310 | * affinity is set. 2.6.11 and 12 kernels have all present |
1306 | * cpus set. Some day we'll have to fix it up further to handle | 1311 | * cpus set. Some day we'll have to fix it up further to handle |
1307 | * a cpu subset. This algorithm fails for two HT-400's connected | 1312 | * a cpu subset. This algorithm fails for two HT chips connected |
1308 | * in tunnel fashion. Eventually this needs real topology | 1313 | * in tunnel fashion. Eventually this needs real topology |
1309 | * information. There may be some issues with dual core numbering | 1314 | * information. There may be some issues with dual core numbering |
1310 | * as well. This needs more work prior to release. | 1315 | * as well. This needs more work prior to release. |
@@ -1815,7 +1820,7 @@ int ipath_user_add(struct ipath_devdata *dd) | |||
1815 | if (ret < 0) { | 1820 | if (ret < 0) { |
1816 | ipath_dev_err(dd, "Could not create wildcard " | 1821 | ipath_dev_err(dd, "Could not create wildcard " |
1817 | "minor: error %d\n", -ret); | 1822 | "minor: error %d\n", -ret); |
1818 | goto bail_sma; | 1823 | goto bail_user; |
1819 | } | 1824 | } |
1820 | 1825 | ||
1821 | atomic_set(&user_setup, 1); | 1826 | atomic_set(&user_setup, 1); |
@@ -1831,7 +1836,7 @@ int ipath_user_add(struct ipath_devdata *dd) | |||
1831 | 1836 | ||
1832 | goto bail; | 1837 | goto bail; |
1833 | 1838 | ||
1834 | bail_sma: | 1839 | bail_user: |
1835 | user_cleanup(); | 1840 | user_cleanup(); |
1836 | bail: | 1841 | bail: |
1837 | return ret; | 1842 | return ret; |
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 0936d8e8d704..a5eb30a06a5c 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c | |||
@@ -191,8 +191,8 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf, | |||
191 | portinfo[4] = (dd->ipath_lid << 16); | 191 | portinfo[4] = (dd->ipath_lid << 16); |
192 | 192 | ||
193 | /* | 193 | /* |
194 | * Notimpl yet SMLID (should we store this in the driver, in case | 194 | * Notimpl yet SMLID. |
195 | * SMA dies?) CapabilityMask is 0, we don't support any of these | 195 | * CapabilityMask is 0, we don't support any of these |
196 | * DiagCode is 0; we don't store any diag info for now Notimpl yet | 196 | * DiagCode is 0; we don't store any diag info for now Notimpl yet |
197 | * M_KeyLeasePeriod (we don't support M_Key) | 197 | * M_KeyLeasePeriod (we don't support M_Key) |
198 | */ | 198 | */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_ht400.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index 3db015da6e77..bf2455a6d562 100644 --- a/drivers/infiniband/hw/ipath/ipath_ht400.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c | |||
@@ -33,7 +33,7 @@ | |||
33 | 33 | ||
34 | /* | 34 | /* |
35 | * This file contains all of the code that is specific to the InfiniPath | 35 | * This file contains all of the code that is specific to the InfiniPath |
36 | * HT-400 chip. | 36 | * HT chip. |
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
@@ -43,7 +43,7 @@ | |||
43 | #include "ipath_registers.h" | 43 | #include "ipath_registers.h" |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * This lists the InfiniPath HT400 registers, in the actual chip layout. | 46 | * This lists the InfiniPath registers, in the actual chip layout. |
47 | * This structure should never be directly accessed. | 47 | * This structure should never be directly accessed. |
48 | * | 48 | * |
49 | * The names are in InterCap form because they're taken straight from | 49 | * The names are in InterCap form because they're taken straight from |
@@ -461,8 +461,9 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
461 | * times. | 461 | * times. |
462 | */ | 462 | */ |
463 | if (dd->ipath_flags & IPATH_INITTED) { | 463 | if (dd->ipath_flags & IPATH_INITTED) { |
464 | ipath_dev_err(dd, "Fatal Error (freeze " | 464 | ipath_dev_err(dd, "Fatal Hardware Error (freeze " |
465 | "mode), no longer usable\n"); | 465 | "mode), no longer usable, SN %.16s\n", |
466 | dd->ipath_serial); | ||
466 | isfatal = 1; | 467 | isfatal = 1; |
467 | } | 468 | } |
468 | *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; | 469 | *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; |
@@ -537,7 +538,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
537 | if (hwerrs & INFINIPATH_HWE_HTCMISCERR7) | 538 | if (hwerrs & INFINIPATH_HWE_HTCMISCERR7) |
538 | strlcat(msg, "[HT core Misc7]", msgl); | 539 | strlcat(msg, "[HT core Misc7]", msgl); |
539 | if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { | 540 | if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { |
540 | strlcat(msg, "[Memory BIST test failed, HT-400 unusable]", | 541 | strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]", |
541 | msgl); | 542 | msgl); |
542 | /* ignore from now on, so disable until driver reloaded */ | 543 | /* ignore from now on, so disable until driver reloaded */ |
543 | dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED; | 544 | dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED; |
@@ -553,7 +554,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
553 | 554 | ||
554 | if (hwerrs & _IPATH_PLL_FAIL) { | 555 | if (hwerrs & _IPATH_PLL_FAIL) { |
555 | snprintf(bitsmsg, sizeof bitsmsg, | 556 | snprintf(bitsmsg, sizeof bitsmsg, |
556 | "[PLL failed (%llx), HT-400 unusable]", | 557 | "[PLL failed (%llx), InfiniPath hardware unusable]", |
557 | (unsigned long long) (hwerrs & _IPATH_PLL_FAIL)); | 558 | (unsigned long long) (hwerrs & _IPATH_PLL_FAIL)); |
558 | strlcat(msg, bitsmsg, msgl); | 559 | strlcat(msg, bitsmsg, msgl); |
559 | /* ignore from now on, so disable until driver reloaded */ | 560 | /* ignore from now on, so disable until driver reloaded */ |
@@ -610,18 +611,18 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, | |||
610 | break; | 611 | break; |
611 | case 5: | 612 | case 5: |
612 | /* | 613 | /* |
613 | * HT-460 original production board; two production levels, with | 614 | * original production board; two production levels, with |
614 | * different serial number ranges. See ipath_ht_early_init() for | 615 | * different serial number ranges. See ipath_ht_early_init() for |
615 | * case where we enable IPATH_GPIO_INTR for later serial # range. | 616 | * case where we enable IPATH_GPIO_INTR for later serial # range. |
616 | */ | 617 | */ |
617 | n = "InfiniPath_HT-460"; | 618 | n = "InfiniPath_QHT7040"; |
618 | break; | 619 | break; |
619 | case 6: | 620 | case 6: |
620 | n = "OEM_Board_3"; | 621 | n = "OEM_Board_3"; |
621 | break; | 622 | break; |
622 | case 7: | 623 | case 7: |
623 | /* HT-460 small form factor production board */ | 624 | /* small form factor production board */ |
624 | n = "InfiniPath_HT-465"; | 625 | n = "InfiniPath_QHT7140"; |
625 | break; | 626 | break; |
626 | case 8: | 627 | case 8: |
627 | n = "LS/X-1"; | 628 | n = "LS/X-1"; |
@@ -633,7 +634,7 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, | |||
633 | n = "OEM_Board_2"; | 634 | n = "OEM_Board_2"; |
634 | break; | 635 | break; |
635 | case 11: | 636 | case 11: |
636 | n = "InfiniPath_HT-470"; | 637 | n = "InfiniPath_HT-470"; /* obsoleted */ |
637 | break; | 638 | break; |
638 | case 12: | 639 | case 12: |
639 | n = "OEM_Board_4"; | 640 | n = "OEM_Board_4"; |
@@ -641,7 +642,7 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, | |||
641 | default: /* don't know, just print the number */ | 642 | default: /* don't know, just print the number */ |
642 | ipath_dev_err(dd, "Don't yet know about board " | 643 | ipath_dev_err(dd, "Don't yet know about board " |
643 | "with ID %u\n", boardrev); | 644 | "with ID %u\n", boardrev); |
644 | snprintf(name, namelen, "Unknown_InfiniPath_HT-4xx_%u", | 645 | snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u", |
645 | boardrev); | 646 | boardrev); |
646 | break; | 647 | break; |
647 | } | 648 | } |
@@ -650,11 +651,10 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, | |||
650 | 651 | ||
651 | if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) { | 652 | if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) { |
652 | /* | 653 | /* |
653 | * This version of the driver only supports the HT-400 | 654 | * This version of the driver only supports Rev 3.2 and 3.3 |
654 | * Rev 3.2 | ||
655 | */ | 655 | */ |
656 | ipath_dev_err(dd, | 656 | ipath_dev_err(dd, |
657 | "Unsupported HT-400 revision %u.%u!\n", | 657 | "Unsupported InfiniPath hardware revision %u.%u!\n", |
658 | dd->ipath_majrev, dd->ipath_minrev); | 658 | dd->ipath_majrev, dd->ipath_minrev); |
659 | ret = 1; | 659 | ret = 1; |
660 | goto bail; | 660 | goto bail; |
@@ -738,7 +738,7 @@ static void ipath_check_htlink(struct ipath_devdata *dd) | |||
738 | 738 | ||
739 | static int ipath_setup_ht_reset(struct ipath_devdata *dd) | 739 | static int ipath_setup_ht_reset(struct ipath_devdata *dd) |
740 | { | 740 | { |
741 | ipath_dbg("No reset possible for HT-400\n"); | 741 | ipath_dbg("No reset possible for this InfiniPath hardware\n"); |
742 | return 0; | 742 | return 0; |
743 | } | 743 | } |
744 | 744 | ||
@@ -925,7 +925,7 @@ static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev, | |||
925 | 925 | ||
926 | /* | 926 | /* |
927 | * kernels with CONFIG_PCI_MSI set the vector in the irq field of | 927 | * kernels with CONFIG_PCI_MSI set the vector in the irq field of |
928 | * struct pci_device, so we use that to program the HT-400 internal | 928 | * struct pci_device, so we use that to program the internal |
929 | * interrupt register (not config space) with that value. The BIOS | 929 | * interrupt register (not config space) with that value. The BIOS |
930 | * must still have done the basic MSI setup. | 930 | * must still have done the basic MSI setup. |
931 | */ | 931 | */ |
@@ -1013,7 +1013,7 @@ bail: | |||
1013 | * @dd: the infinipath device | 1013 | * @dd: the infinipath device |
1014 | * | 1014 | * |
1015 | * Called during driver unload. | 1015 | * Called during driver unload. |
1016 | * This is currently a nop for the HT-400, not for all chips | 1016 | * This is currently a nop for the HT chip, not for all chips |
1017 | */ | 1017 | */ |
1018 | static void ipath_setup_ht_cleanup(struct ipath_devdata *dd) | 1018 | static void ipath_setup_ht_cleanup(struct ipath_devdata *dd) |
1019 | { | 1019 | { |
@@ -1290,6 +1290,15 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd) | |||
1290 | val &= ~INFINIPATH_XGXS_RESET; | 1290 | val &= ~INFINIPATH_XGXS_RESET; |
1291 | change = 1; | 1291 | change = 1; |
1292 | } | 1292 | } |
1293 | if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & | ||
1294 | INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { | ||
1295 | /* need to compensate for Tx inversion in partner */ | ||
1296 | val &= ~(INFINIPATH_XGXS_RX_POL_MASK << | ||
1297 | INFINIPATH_XGXS_RX_POL_SHIFT); | ||
1298 | val |= dd->ipath_rx_pol_inv << | ||
1299 | INFINIPATH_XGXS_RX_POL_SHIFT; | ||
1300 | change = 1; | ||
1301 | } | ||
1293 | if (change) | 1302 | if (change) |
1294 | ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); | 1303 | ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); |
1295 | 1304 | ||
@@ -1470,7 +1479,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) | |||
1470 | dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; | 1479 | dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; |
1471 | 1480 | ||
1472 | /* | 1481 | /* |
1473 | * For HT-400, we allocate a somewhat overly large eager buffer, | 1482 | * For HT, we allocate a somewhat overly large eager buffer, |
1474 | * such that we can guarantee that we can receive the largest | 1483 | * such that we can guarantee that we can receive the largest |
1475 | * packet that we can send out. To truly support a 4KB MTU, | 1484 | * packet that we can send out. To truly support a 4KB MTU, |
1476 | * we need to bump this to a large value. To date, other than | 1485 | * we need to bump this to a large value. To date, other than |
@@ -1531,7 +1540,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) | |||
1531 | if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' && | 1540 | if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' && |
1532 | dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') { | 1541 | dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') { |
1533 | /* | 1542 | /* |
1534 | * Later production HT-460 has same changes as HT-465, so | 1543 | * Later production QHT7040 has same changes as QHT7140, so |
1535 | * can use GPIO interrupts. They have serial #'s starting | 1544 | * can use GPIO interrupts. They have serial #'s starting |
1536 | * with 128, rather than 112. | 1545 | * with 128, rather than 112. |
1537 | */ | 1546 | */ |
@@ -1560,13 +1569,13 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) | |||
1560 | } | 1569 | } |
1561 | 1570 | ||
1562 | /** | 1571 | /** |
1563 | * ipath_init_ht400_funcs - set up the chip-specific function pointers | 1572 | * ipath_init_iba6110_funcs - set up the chip-specific function pointers |
1564 | * @dd: the infinipath device | 1573 | * @dd: the infinipath device |
1565 | * | 1574 | * |
1566 | * This is global, and is called directly at init to set up the | 1575 | * This is global, and is called directly at init to set up the |
1567 | * chip-specific function pointers for later use. | 1576 | * chip-specific function pointers for later use. |
1568 | */ | 1577 | */ |
1569 | void ipath_init_ht400_funcs(struct ipath_devdata *dd) | 1578 | void ipath_init_iba6110_funcs(struct ipath_devdata *dd) |
1570 | { | 1579 | { |
1571 | dd->ipath_f_intrsetup = ipath_ht_intconfig; | 1580 | dd->ipath_f_intrsetup = ipath_ht_intconfig; |
1572 | dd->ipath_f_bus = ipath_setup_ht_config; | 1581 | dd->ipath_f_bus = ipath_setup_ht_config; |
diff --git a/drivers/infiniband/hw/ipath/ipath_pe800.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index b83f66d8262c..d86516d23df6 100644 --- a/drivers/infiniband/hw/ipath/ipath_pe800.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c | |||
@@ -32,7 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | /* | 33 | /* |
34 | * This file contains all of the code that is specific to the | 34 | * This file contains all of the code that is specific to the |
35 | * InfiniPath PE-800 chip. | 35 | * InfiniPath PCIe chip. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
@@ -45,9 +45,9 @@ | |||
45 | 45 | ||
46 | /* | 46 | /* |
47 | * This file contains all the chip-specific register information and | 47 | * This file contains all the chip-specific register information and |
48 | * access functions for the QLogic InfiniPath PE800, the PCI-Express chip. | 48 | * access functions for the QLogic InfiniPath PCI-Express chip. |
49 | * | 49 | * |
50 | * This lists the InfiniPath PE800 registers, in the actual chip layout. | 50 | * This lists the InfiniPath registers, in the actual chip layout. |
51 | * This structure should never be directly accessed. | 51 | * This structure should never be directly accessed. |
52 | */ | 52 | */ |
53 | struct _infinipath_do_not_use_kernel_regs { | 53 | struct _infinipath_do_not_use_kernel_regs { |
@@ -213,7 +213,6 @@ static const struct ipath_kregs ipath_pe_kregs = { | |||
213 | .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), | 213 | .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), |
214 | .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0), | 214 | .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0), |
215 | 215 | ||
216 | /* This group is pe-800-specific; and used only in this file */ | ||
217 | /* The rcvpktled register controls one of the debug port signals, so | 216 | /* The rcvpktled register controls one of the debug port signals, so |
218 | * a packet activity LED can be connected to it. */ | 217 | * a packet activity LED can be connected to it. */ |
219 | .kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt), | 218 | .kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt), |
@@ -364,8 +363,9 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
364 | * and we get here multiple times | 363 | * and we get here multiple times |
365 | */ | 364 | */ |
366 | if (dd->ipath_flags & IPATH_INITTED) { | 365 | if (dd->ipath_flags & IPATH_INITTED) { |
367 | ipath_dev_err(dd, "Fatal Error (freeze " | 366 | ipath_dev_err(dd, "Fatal Hardware Error (freeze " |
368 | "mode), no longer usable\n"); | 367 | "mode), no longer usable, SN %.16s\n", |
368 | dd->ipath_serial); | ||
369 | isfatal = 1; | 369 | isfatal = 1; |
370 | } | 370 | } |
371 | /* | 371 | /* |
@@ -388,7 +388,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
388 | *msg = '\0'; | 388 | *msg = '\0'; |
389 | 389 | ||
390 | if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { | 390 | if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { |
391 | strlcat(msg, "[Memory BIST test failed, PE-800 unusable]", | 391 | strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]", |
392 | msgl); | 392 | msgl); |
393 | /* ignore from now on, so disable until driver reloaded */ | 393 | /* ignore from now on, so disable until driver reloaded */ |
394 | *dd->ipath_statusp |= IPATH_STATUS_HWERROR; | 394 | *dd->ipath_statusp |= IPATH_STATUS_HWERROR; |
@@ -433,7 +433,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
433 | 433 | ||
434 | if (hwerrs & _IPATH_PLL_FAIL) { | 434 | if (hwerrs & _IPATH_PLL_FAIL) { |
435 | snprintf(bitsmsg, sizeof bitsmsg, | 435 | snprintf(bitsmsg, sizeof bitsmsg, |
436 | "[PLL failed (%llx), PE-800 unusable]", | 436 | "[PLL failed (%llx), InfiniPath hardware unusable]", |
437 | (unsigned long long) hwerrs & _IPATH_PLL_FAIL); | 437 | (unsigned long long) hwerrs & _IPATH_PLL_FAIL); |
438 | strlcat(msg, bitsmsg, msgl); | 438 | strlcat(msg, bitsmsg, msgl); |
439 | /* ignore from now on, so disable until driver reloaded */ | 439 | /* ignore from now on, so disable until driver reloaded */ |
@@ -511,22 +511,25 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name, | |||
511 | n = "InfiniPath_Emulation"; | 511 | n = "InfiniPath_Emulation"; |
512 | break; | 512 | break; |
513 | case 1: | 513 | case 1: |
514 | n = "InfiniPath_PE-800-Bringup"; | 514 | n = "InfiniPath_QLE7140-Bringup"; |
515 | break; | 515 | break; |
516 | case 2: | 516 | case 2: |
517 | n = "InfiniPath_PE-880"; | 517 | n = "InfiniPath_QLE7140"; |
518 | break; | 518 | break; |
519 | case 3: | 519 | case 3: |
520 | n = "InfiniPath_PE-850"; | 520 | n = "InfiniPath_QMI7140"; |
521 | break; | 521 | break; |
522 | case 4: | 522 | case 4: |
523 | n = "InfiniPath_PE-860"; | 523 | n = "InfiniPath_QEM7140"; |
524 | break; | ||
525 | case 5: | ||
526 | n = "InfiniPath_QMH7140"; | ||
524 | break; | 527 | break; |
525 | default: | 528 | default: |
526 | ipath_dev_err(dd, | 529 | ipath_dev_err(dd, |
527 | "Don't yet know about board with ID %u\n", | 530 | "Don't yet know about board with ID %u\n", |
528 | boardrev); | 531 | boardrev); |
529 | snprintf(name, namelen, "Unknown_InfiniPath_PE-8xx_%u", | 532 | snprintf(name, namelen, "Unknown_InfiniPath_PCIe_%u", |
530 | boardrev); | 533 | boardrev); |
531 | break; | 534 | break; |
532 | } | 535 | } |
@@ -534,7 +537,7 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name, | |||
534 | snprintf(name, namelen, "%s", n); | 537 | snprintf(name, namelen, "%s", n); |
535 | 538 | ||
536 | if (dd->ipath_majrev != 4 || !dd->ipath_minrev || dd->ipath_minrev>2) { | 539 | if (dd->ipath_majrev != 4 || !dd->ipath_minrev || dd->ipath_minrev>2) { |
537 | ipath_dev_err(dd, "Unsupported PE-800 revision %u.%u!\n", | 540 | ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n", |
538 | dd->ipath_majrev, dd->ipath_minrev); | 541 | dd->ipath_majrev, dd->ipath_minrev); |
539 | ret = 1; | 542 | ret = 1; |
540 | } else | 543 | } else |
@@ -651,6 +654,15 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) | |||
651 | val &= ~INFINIPATH_XGXS_RESET; | 654 | val &= ~INFINIPATH_XGXS_RESET; |
652 | change = 1; | 655 | change = 1; |
653 | } | 656 | } |
657 | if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & | ||
658 | INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { | ||
659 | /* need to compensate for Tx inversion in partner */ | ||
660 | val &= ~(INFINIPATH_XGXS_RX_POL_MASK << | ||
661 | INFINIPATH_XGXS_RX_POL_SHIFT); | ||
662 | val |= dd->ipath_rx_pol_inv << | ||
663 | INFINIPATH_XGXS_RX_POL_SHIFT; | ||
664 | change = 1; | ||
665 | } | ||
654 | if (change) | 666 | if (change) |
655 | ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); | 667 | ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); |
656 | 668 | ||
@@ -705,7 +717,7 @@ static void ipath_pe_quiet_serdes(struct ipath_devdata *dd) | |||
705 | ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); | 717 | ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); |
706 | } | 718 | } |
707 | 719 | ||
708 | /* this is not yet needed on the PE800, so just return 0. */ | 720 | /* this is not yet needed on this chip, so just return 0. */ |
709 | static int ipath_pe_intconfig(struct ipath_devdata *dd) | 721 | static int ipath_pe_intconfig(struct ipath_devdata *dd) |
710 | { | 722 | { |
711 | return 0; | 723 | return 0; |
@@ -759,8 +771,8 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst, | |||
759 | * | 771 | * |
760 | * This is called during driver unload. | 772 | * This is called during driver unload. |
761 | * We do the pci_disable_msi here, not in generic code, because it | 773 | * We do the pci_disable_msi here, not in generic code, because it |
762 | * isn't used for the HT-400. If we do end up needing pci_enable_msi | 774 | * isn't used for the HT chips. If we do end up needing pci_enable_msi |
763 | * at some point in the future for HT-400, we'll move the call back | 775 | * at some point in the future for HT, we'll move the call back |
764 | * into the main init_one code. | 776 | * into the main init_one code. |
765 | */ | 777 | */ |
766 | static void ipath_setup_pe_cleanup(struct ipath_devdata *dd) | 778 | static void ipath_setup_pe_cleanup(struct ipath_devdata *dd) |
@@ -780,10 +792,10 @@ static void ipath_setup_pe_cleanup(struct ipath_devdata *dd) | |||
780 | * late in 2.6.16). | 792 | * late in 2.6.16). |
781 | * All that can be done is to edit the kernel source to remove the quirk | 793 | * All that can be done is to edit the kernel source to remove the quirk |
782 | * check until that is fixed. | 794 | * check until that is fixed. |
783 | * We do not need to call enable_msi() for our HyperTransport chip (HT-400), | 795 | * We do not need to call enable_msi() for our HyperTransport chip, |
784 | * even those it uses MSI, and we want to avoid the quirk warning, so | 796 | * even though it uses MSI, and we want to avoid the quirk warning, so |
785 | * So we call enable_msi only for the PE-800. If we do end up needing | 797 | * So we call enable_msi only for PCIe. If we do end up needing |
786 | * pci_enable_msi at some point in the future for HT-400, we'll move the | 798 | * pci_enable_msi at some point in the future for HT, we'll move the |
787 | * call back into the main init_one code. | 799 | * call back into the main init_one code. |
788 | * We save the msi lo and hi values, so we can restore them after | 800 | * We save the msi lo and hi values, so we can restore them after |
789 | * chip reset (the kernel PCI infrastructure doesn't yet handle that | 801 | * chip reset (the kernel PCI infrastructure doesn't yet handle that |
@@ -971,8 +983,7 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd) | |||
971 | int ret; | 983 | int ret; |
972 | 984 | ||
973 | /* Use ERROR so it shows up in logs, etc. */ | 985 | /* Use ERROR so it shows up in logs, etc. */ |
974 | ipath_dev_err(dd, "Resetting PE-800 unit %u\n", | 986 | ipath_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->ipath_unit); |
975 | dd->ipath_unit); | ||
976 | /* keep chip from being accessed in a few places */ | 987 | /* keep chip from being accessed in a few places */ |
977 | dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT); | 988 | dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT); |
978 | val = dd->ipath_control | INFINIPATH_C_RESET; | 989 | val = dd->ipath_control | INFINIPATH_C_RESET; |
@@ -1078,7 +1089,7 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, | |||
1078 | * @port: the port | 1089 | * @port: the port |
1079 | * | 1090 | * |
1080 | * clear all TID entries for a port, expected and eager. | 1091 | * clear all TID entries for a port, expected and eager. |
1081 | * Used from ipath_close(). On PE800, TIDs are only 32 bits, | 1092 | * Used from ipath_close(). On this chip, TIDs are only 32 bits, |
1082 | * not 64, but they are still on 64 bit boundaries, so tidbase | 1093 | * not 64, but they are still on 64 bit boundaries, so tidbase |
1083 | * is declared as u64 * for the pointer math, even though we write 32 bits | 1094 | * is declared as u64 * for the pointer math, even though we write 32 bits |
1084 | */ | 1095 | */ |
@@ -1148,9 +1159,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd) | |||
1148 | dd->ipath_flags |= IPATH_4BYTE_TID; | 1159 | dd->ipath_flags |= IPATH_4BYTE_TID; |
1149 | 1160 | ||
1150 | /* | 1161 | /* |
1151 | * For openib, we need to be able to handle an IB header of 96 bytes | 1162 | * For openfabrics, we need to be able to handle an IB header of |
1152 | * or 24 dwords. HT-400 has arbitrary sized receive buffers, so we | 1163 | * 24 dwords. HT chip has arbitrary sized receive buffers, so we |
1153 | * made them the same size as the PIO buffers. The PE-800 does not | 1164 | * made them the same size as the PIO buffers. This chip does not |
1154 | * handle arbitrary size buffers, so we need the header large enough | 1165 | * handle arbitrary size buffers, so we need the header large enough |
1155 | * to handle largest IB header, but still have room for a 2KB MTU | 1166 | * to handle largest IB header, but still have room for a 2KB MTU |
1156 | * standard IB packet. | 1167 | * standard IB packet. |
@@ -1158,11 +1169,10 @@ static int ipath_pe_early_init(struct ipath_devdata *dd) | |||
1158 | dd->ipath_rcvhdrentsize = 24; | 1169 | dd->ipath_rcvhdrentsize = 24; |
1159 | dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; | 1170 | dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; |
1160 | 1171 | ||
1161 | /* For HT-400, we allocate a somewhat overly large eager buffer, | 1172 | /* |
1162 | * such that we can guarantee that we can receive the largest packet | 1173 | * To truly support a 4KB MTU (for usermode), we need to |
1163 | * that we can send out. To truly support a 4KB MTU, we need to | 1174 | * bump this to a larger value. For now, we use them for |
1164 | * bump this to a larger value. We'll do this when I get around to | 1175 | * the kernel only. |
1165 | * testing 4KB sends on the PE-800, which I have not yet done. | ||
1166 | */ | 1176 | */ |
1167 | dd->ipath_rcvegrbufsize = 2048; | 1177 | dd->ipath_rcvegrbufsize = 2048; |
1168 | /* | 1178 | /* |
@@ -1175,9 +1185,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd) | |||
1175 | dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen; | 1185 | dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen; |
1176 | 1186 | ||
1177 | /* | 1187 | /* |
1178 | * For PE-800, we can request a receive interrupt for 1 or | 1188 | * We can request a receive interrupt for 1 or |
1179 | * more packets from current offset. For now, we set this | 1189 | * more packets from current offset. For now, we set this |
1180 | * up for a single packet, to match the HT-400 behavior. | 1190 | * up for a single packet. |
1181 | */ | 1191 | */ |
1182 | dd->ipath_rhdrhead_intr_off = 1ULL<<32; | 1192 | dd->ipath_rhdrhead_intr_off = 1ULL<<32; |
1183 | 1193 | ||
@@ -1216,13 +1226,13 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) | |||
1216 | } | 1226 | } |
1217 | 1227 | ||
1218 | /** | 1228 | /** |
1219 | * ipath_init_pe800_funcs - set up the chip-specific function pointers | 1229 | * ipath_init_iba6120_funcs - set up the chip-specific function pointers |
1220 | * @dd: the infinipath device | 1230 | * @dd: the infinipath device |
1221 | * | 1231 | * |
1222 | * This is global, and is called directly at init to set up the | 1232 | * This is global, and is called directly at init to set up the |
1223 | * chip-specific function pointers for later use. | 1233 | * chip-specific function pointers for later use. |
1224 | */ | 1234 | */ |
1225 | void ipath_init_pe800_funcs(struct ipath_devdata *dd) | 1235 | void ipath_init_iba6120_funcs(struct ipath_devdata *dd) |
1226 | { | 1236 | { |
1227 | dd->ipath_f_intrsetup = ipath_pe_intconfig; | 1237 | dd->ipath_f_intrsetup = ipath_pe_intconfig; |
1228 | dd->ipath_f_bus = ipath_setup_pe_config; | 1238 | dd->ipath_f_bus = ipath_setup_pe_config; |
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 414cdd1d80a6..44669dc2e22d 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c | |||
@@ -53,8 +53,8 @@ module_param_named(cfgports, ipath_cfgports, ushort, S_IRUGO); | |||
53 | MODULE_PARM_DESC(cfgports, "Set max number of ports to use"); | 53 | MODULE_PARM_DESC(cfgports, "Set max number of ports to use"); |
54 | 54 | ||
55 | /* | 55 | /* |
56 | * Number of buffers reserved for driver (layered drivers and SMA | 56 | * Number of buffers reserved for driver (verbs and layered drivers.) |
57 | * send). Reserved at end of buffer list. Initialized based on | 57 | * Reserved at end of buffer list. Initialized based on |
58 | * number of PIO buffers if not set via module interface. | 58 | * number of PIO buffers if not set via module interface. |
59 | * The problem with this is that it's global, but we'll use different | 59 | * The problem with this is that it's global, but we'll use different |
60 | * numbers for different chip types. So the default value is not | 60 | * numbers for different chip types. So the default value is not |
@@ -80,7 +80,7 @@ MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver"); | |||
80 | * | 80 | * |
81 | * Allocate the eager TID buffers and program them into infinipath. | 81 | * Allocate the eager TID buffers and program them into infinipath. |
82 | * We use the network layer alloc_skb() allocator to allocate the | 82 | * We use the network layer alloc_skb() allocator to allocate the |
83 | * memory, and either use the buffers as is for things like SMA | 83 | * memory, and either use the buffers as is for things like verbs |
84 | * packets, or pass the buffers up to the ipath layered driver and | 84 | * packets, or pass the buffers up to the ipath layered driver and |
85 | * thence the network layer, replacing them as we do so (see | 85 | * thence the network layer, replacing them as we do so (see |
86 | * ipath_rcv_layer()). | 86 | * ipath_rcv_layer()). |
@@ -240,7 +240,11 @@ static int init_chip_first(struct ipath_devdata *dd, | |||
240 | "only supports %u\n", ipath_cfgports, | 240 | "only supports %u\n", ipath_cfgports, |
241 | dd->ipath_portcnt); | 241 | dd->ipath_portcnt); |
242 | } | 242 | } |
243 | dd->ipath_pd = kzalloc(sizeof(*dd->ipath_pd) * dd->ipath_cfgports, | 243 | /* |
244 | * Allocate full portcnt array, rather than just cfgports, because | ||
245 | * cleanup iterates across all possible ports. | ||
246 | */ | ||
247 | dd->ipath_pd = kzalloc(sizeof(*dd->ipath_pd) * dd->ipath_portcnt, | ||
244 | GFP_KERNEL); | 248 | GFP_KERNEL); |
245 | 249 | ||
246 | if (!dd->ipath_pd) { | 250 | if (!dd->ipath_pd) { |
@@ -446,9 +450,9 @@ static void enable_chip(struct ipath_devdata *dd, | |||
446 | u32 val; | 450 | u32 val; |
447 | int i; | 451 | int i; |
448 | 452 | ||
449 | if (!reinit) { | 453 | if (!reinit) |
450 | init_waitqueue_head(&ipath_sma_state_wait); | 454 | init_waitqueue_head(&ipath_state_wait); |
451 | } | 455 | |
452 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, | 456 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, |
453 | dd->ipath_rcvctrl); | 457 | dd->ipath_rcvctrl); |
454 | 458 | ||
@@ -687,7 +691,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) | |||
687 | dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2) | 691 | dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2) |
688 | / (sizeof(u64) * BITS_PER_BYTE / 2); | 692 | / (sizeof(u64) * BITS_PER_BYTE / 2); |
689 | if (ipath_kpiobufs == 0) { | 693 | if (ipath_kpiobufs == 0) { |
690 | /* not set by user, or set explictly to default */ | 694 | /* not set by user (this is default) */ |
691 | if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128) | 695 | if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128) |
692 | kpiobufs = 32; | 696 | kpiobufs = 32; |
693 | else | 697 | else |
@@ -946,6 +950,7 @@ static int ipath_set_kpiobufs(const char *str, struct kernel_param *kp) | |||
946 | dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - val; | 950 | dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - val; |
947 | } | 951 | } |
948 | 952 | ||
953 | ipath_kpiobufs = val; | ||
949 | ret = 0; | 954 | ret = 0; |
950 | bail: | 955 | bail: |
951 | spin_unlock_irqrestore(&ipath_devs_lock, flags); | 956 | spin_unlock_irqrestore(&ipath_devs_lock, flags); |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 280e732660a1..49bf7bb15b04 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | 35 | ||
36 | #include "ipath_kernel.h" | 36 | #include "ipath_kernel.h" |
37 | #include "ipath_layer.h" | 37 | #include "ipath_verbs.h" |
38 | #include "ipath_common.h" | 38 | #include "ipath_common.h" |
39 | 39 | ||
40 | /* These are all rcv-related errors which we want to count for stats */ | 40 | /* These are all rcv-related errors which we want to count for stats */ |
@@ -201,7 +201,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
201 | ib_linkstate(lstate)); | 201 | ib_linkstate(lstate)); |
202 | } | 202 | } |
203 | else | 203 | else |
204 | ipath_cdbg(SMA, "Unit %u link state %s, last " | 204 | ipath_cdbg(VERBOSE, "Unit %u link state %s, last " |
205 | "was %s\n", dd->ipath_unit, | 205 | "was %s\n", dd->ipath_unit, |
206 | ib_linkstate(lstate), | 206 | ib_linkstate(lstate), |
207 | ib_linkstate((unsigned) | 207 | ib_linkstate((unsigned) |
@@ -213,7 +213,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
213 | if (lstate == IPATH_IBSTATE_INIT || | 213 | if (lstate == IPATH_IBSTATE_INIT || |
214 | lstate == IPATH_IBSTATE_ARM || | 214 | lstate == IPATH_IBSTATE_ARM || |
215 | lstate == IPATH_IBSTATE_ACTIVE) | 215 | lstate == IPATH_IBSTATE_ACTIVE) |
216 | ipath_cdbg(SMA, "Unit %u link state down" | 216 | ipath_cdbg(VERBOSE, "Unit %u link state down" |
217 | " (state 0x%x), from %s\n", | 217 | " (state 0x%x), from %s\n", |
218 | dd->ipath_unit, | 218 | dd->ipath_unit, |
219 | (u32)val & IPATH_IBSTATE_MASK, | 219 | (u32)val & IPATH_IBSTATE_MASK, |
@@ -269,7 +269,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
269 | INFINIPATH_IBCS_LINKSTATE_MASK) | 269 | INFINIPATH_IBCS_LINKSTATE_MASK) |
270 | == INFINIPATH_IBCS_L_STATE_ACTIVE) | 270 | == INFINIPATH_IBCS_L_STATE_ACTIVE) |
271 | /* if from up to down be more vocal */ | 271 | /* if from up to down be more vocal */ |
272 | ipath_cdbg(SMA, | 272 | ipath_cdbg(VERBOSE, |
273 | "Unit %u link now down (%s)\n", | 273 | "Unit %u link now down (%s)\n", |
274 | dd->ipath_unit, | 274 | dd->ipath_unit, |
275 | ipath_ibcstatus_str[ltstate]); | 275 | ipath_ibcstatus_str[ltstate]); |
@@ -289,8 +289,6 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
289 | *dd->ipath_statusp |= | 289 | *dd->ipath_statusp |= |
290 | IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; | 290 | IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; |
291 | dd->ipath_f_setextled(dd, lstate, ltstate); | 291 | dd->ipath_f_setextled(dd, lstate, ltstate); |
292 | |||
293 | __ipath_layer_intr(dd, IPATH_LAYER_INT_IF_UP); | ||
294 | } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) { | 292 | } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) { |
295 | /* | 293 | /* |
296 | * set INIT and DOWN. Down is checked by most of the other | 294 | * set INIT and DOWN. Down is checked by most of the other |
@@ -598,11 +596,11 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) | |||
598 | 596 | ||
599 | if (!noprint && *msg) | 597 | if (!noprint && *msg) |
600 | ipath_dev_err(dd, "%s error\n", msg); | 598 | ipath_dev_err(dd, "%s error\n", msg); |
601 | if (dd->ipath_sma_state_wanted & dd->ipath_flags) { | 599 | if (dd->ipath_state_wanted & dd->ipath_flags) { |
602 | ipath_cdbg(VERBOSE, "sma wanted state %x, iflags now %x, " | 600 | ipath_cdbg(VERBOSE, "driver wanted state %x, iflags now %x, " |
603 | "waking\n", dd->ipath_sma_state_wanted, | 601 | "waking\n", dd->ipath_state_wanted, |
604 | dd->ipath_flags); | 602 | dd->ipath_flags); |
605 | wake_up_interruptible(&ipath_sma_state_wait); | 603 | wake_up_interruptible(&ipath_state_wait); |
606 | } | 604 | } |
607 | 605 | ||
608 | return chkerrpkts; | 606 | return chkerrpkts; |
@@ -708,11 +706,7 @@ static void handle_layer_pioavail(struct ipath_devdata *dd) | |||
708 | { | 706 | { |
709 | int ret; | 707 | int ret; |
710 | 708 | ||
711 | ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); | 709 | ret = ipath_ib_piobufavail(dd->verbs_dev); |
712 | if (ret > 0) | ||
713 | goto set; | ||
714 | |||
715 | ret = __ipath_verbs_piobufavail(dd); | ||
716 | if (ret > 0) | 710 | if (ret > 0) |
717 | goto set; | 711 | goto set; |
718 | 712 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index e9f374fb641e..a8a56276ff1d 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -132,12 +132,6 @@ struct _ipath_layer { | |||
132 | void *l_arg; | 132 | void *l_arg; |
133 | }; | 133 | }; |
134 | 134 | ||
135 | /* Verbs layer interface */ | ||
136 | struct _verbs_layer { | ||
137 | void *l_arg; | ||
138 | struct timer_list l_timer; | ||
139 | }; | ||
140 | |||
141 | struct ipath_devdata { | 135 | struct ipath_devdata { |
142 | struct list_head ipath_list; | 136 | struct list_head ipath_list; |
143 | 137 | ||
@@ -198,7 +192,8 @@ struct ipath_devdata { | |||
198 | void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64); | 192 | void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64); |
199 | /* fill out chip-specific fields */ | 193 | /* fill out chip-specific fields */ |
200 | int (*ipath_f_get_base_info)(struct ipath_portdata *, void *); | 194 | int (*ipath_f_get_base_info)(struct ipath_portdata *, void *); |
201 | struct _verbs_layer verbs_layer; | 195 | struct ipath_ibdev *verbs_dev; |
196 | struct timer_list verbs_timer; | ||
202 | /* total dwords sent (summed from counter) */ | 197 | /* total dwords sent (summed from counter) */ |
203 | u64 ipath_sword; | 198 | u64 ipath_sword; |
204 | /* total dwords rcvd (summed from counter) */ | 199 | /* total dwords rcvd (summed from counter) */ |
@@ -241,7 +236,7 @@ struct ipath_devdata { | |||
241 | u64 ipath_tidtemplate; | 236 | u64 ipath_tidtemplate; |
242 | /* value to write to free TIDs */ | 237 | /* value to write to free TIDs */ |
243 | u64 ipath_tidinvalid; | 238 | u64 ipath_tidinvalid; |
244 | /* PE-800 rcv interrupt setup */ | 239 | /* IBA6120 rcv interrupt setup */ |
245 | u64 ipath_rhdrhead_intr_off; | 240 | u64 ipath_rhdrhead_intr_off; |
246 | 241 | ||
247 | /* size of memory at ipath_kregbase */ | 242 | /* size of memory at ipath_kregbase */ |
@@ -250,8 +245,8 @@ struct ipath_devdata { | |||
250 | u32 ipath_pioavregs; | 245 | u32 ipath_pioavregs; |
251 | /* IPATH_POLL, etc. */ | 246 | /* IPATH_POLL, etc. */ |
252 | u32 ipath_flags; | 247 | u32 ipath_flags; |
253 | /* ipath_flags sma is waiting for */ | 248 | /* ipath_flags driver is waiting for */ |
254 | u32 ipath_sma_state_wanted; | 249 | u32 ipath_state_wanted; |
255 | /* last buffer for user use, first buf for kernel use is this | 250 | /* last buffer for user use, first buf for kernel use is this |
256 | * index. */ | 251 | * index. */ |
257 | u32 ipath_lastport_piobuf; | 252 | u32 ipath_lastport_piobuf; |
@@ -311,10 +306,6 @@ struct ipath_devdata { | |||
311 | u32 ipath_pcibar0; | 306 | u32 ipath_pcibar0; |
312 | /* so we can rewrite it after a chip reset */ | 307 | /* so we can rewrite it after a chip reset */ |
313 | u32 ipath_pcibar1; | 308 | u32 ipath_pcibar1; |
314 | /* sequential tries for SMA send and no bufs */ | ||
315 | u32 ipath_nosma_bufs; | ||
316 | /* duration (seconds) ipath_nosma_bufs set */ | ||
317 | u32 ipath_nosma_secs; | ||
318 | 309 | ||
319 | /* HT/PCI Vendor ID (here for NodeInfo) */ | 310 | /* HT/PCI Vendor ID (here for NodeInfo) */ |
320 | u16 ipath_vendorid; | 311 | u16 ipath_vendorid; |
@@ -512,6 +503,8 @@ struct ipath_devdata { | |||
512 | u8 ipath_pci_cacheline; | 503 | u8 ipath_pci_cacheline; |
513 | /* LID mask control */ | 504 | /* LID mask control */ |
514 | u8 ipath_lmc; | 505 | u8 ipath_lmc; |
506 | /* Rx Polarity inversion (compensate for ~tx on partner) */ | ||
507 | u8 ipath_rx_pol_inv; | ||
515 | 508 | ||
516 | /* local link integrity counter */ | 509 | /* local link integrity counter */ |
517 | u32 ipath_lli_counter; | 510 | u32 ipath_lli_counter; |
@@ -523,18 +516,6 @@ extern struct list_head ipath_dev_list; | |||
523 | extern spinlock_t ipath_devs_lock; | 516 | extern spinlock_t ipath_devs_lock; |
524 | extern struct ipath_devdata *ipath_lookup(int unit); | 517 | extern struct ipath_devdata *ipath_lookup(int unit); |
525 | 518 | ||
526 | extern u16 ipath_layer_rcv_opcode; | ||
527 | extern int __ipath_layer_intr(struct ipath_devdata *, u32); | ||
528 | extern int ipath_layer_intr(struct ipath_devdata *, u32); | ||
529 | extern int __ipath_layer_rcv(struct ipath_devdata *, void *, | ||
530 | struct sk_buff *); | ||
531 | extern int __ipath_layer_rcv_lid(struct ipath_devdata *, void *); | ||
532 | extern int __ipath_verbs_piobufavail(struct ipath_devdata *); | ||
533 | extern int __ipath_verbs_rcv(struct ipath_devdata *, void *, void *, u32); | ||
534 | |||
535 | void ipath_layer_add(struct ipath_devdata *); | ||
536 | void ipath_layer_remove(struct ipath_devdata *); | ||
537 | |||
538 | int ipath_init_chip(struct ipath_devdata *, int); | 519 | int ipath_init_chip(struct ipath_devdata *, int); |
539 | int ipath_enable_wc(struct ipath_devdata *dd); | 520 | int ipath_enable_wc(struct ipath_devdata *dd); |
540 | void ipath_disable_wc(struct ipath_devdata *dd); | 521 | void ipath_disable_wc(struct ipath_devdata *dd); |
@@ -549,9 +530,8 @@ void ipath_cdev_cleanup(struct cdev **cdevp, | |||
549 | 530 | ||
550 | int ipath_diag_add(struct ipath_devdata *); | 531 | int ipath_diag_add(struct ipath_devdata *); |
551 | void ipath_diag_remove(struct ipath_devdata *); | 532 | void ipath_diag_remove(struct ipath_devdata *); |
552 | void ipath_diag_bringup_link(struct ipath_devdata *); | ||
553 | 533 | ||
554 | extern wait_queue_head_t ipath_sma_state_wait; | 534 | extern wait_queue_head_t ipath_state_wait; |
555 | 535 | ||
556 | int ipath_user_add(struct ipath_devdata *dd); | 536 | int ipath_user_add(struct ipath_devdata *dd); |
557 | void ipath_user_remove(struct ipath_devdata *dd); | 537 | void ipath_user_remove(struct ipath_devdata *dd); |
@@ -582,12 +562,14 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *); | |||
582 | 562 | ||
583 | int ipath_parse_ushort(const char *str, unsigned short *valp); | 563 | int ipath_parse_ushort(const char *str, unsigned short *valp); |
584 | 564 | ||
585 | int ipath_wait_linkstate(struct ipath_devdata *, u32, int); | ||
586 | void ipath_set_ib_lstate(struct ipath_devdata *, int); | ||
587 | void ipath_kreceive(struct ipath_devdata *); | 565 | void ipath_kreceive(struct ipath_devdata *); |
588 | int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); | 566 | int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); |
589 | int ipath_reset_device(int); | 567 | int ipath_reset_device(int); |
590 | void ipath_get_faststats(unsigned long); | 568 | void ipath_get_faststats(unsigned long); |
569 | int ipath_set_linkstate(struct ipath_devdata *, u8); | ||
570 | int ipath_set_mtu(struct ipath_devdata *, u16); | ||
571 | int ipath_set_lid(struct ipath_devdata *, u32, u8); | ||
572 | int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); | ||
591 | 573 | ||
592 | /* for use in system calls, where we want to know device type, etc. */ | 574 | /* for use in system calls, where we want to know device type, etc. */ |
593 | #define port_fp(fp) ((struct ipath_portdata *) (fp)->private_data) | 575 | #define port_fp(fp) ((struct ipath_portdata *) (fp)->private_data) |
@@ -642,10 +624,8 @@ void ipath_free_data(struct ipath_portdata *dd); | |||
642 | int ipath_waitfor_mdio_cmdready(struct ipath_devdata *); | 624 | int ipath_waitfor_mdio_cmdready(struct ipath_devdata *); |
643 | int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *); | 625 | int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *); |
644 | u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *); | 626 | u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *); |
645 | /* init PE-800-specific func */ | 627 | void ipath_init_iba6120_funcs(struct ipath_devdata *); |
646 | void ipath_init_pe800_funcs(struct ipath_devdata *); | 628 | void ipath_init_iba6110_funcs(struct ipath_devdata *); |
647 | /* init HT-400-specific func */ | ||
648 | void ipath_init_ht400_funcs(struct ipath_devdata *); | ||
649 | void ipath_get_eeprom_info(struct ipath_devdata *); | 629 | void ipath_get_eeprom_info(struct ipath_devdata *); |
650 | u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); | 630 | u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); |
651 | 631 | ||
@@ -801,7 +781,7 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd, | |||
801 | 781 | ||
802 | struct device_driver; | 782 | struct device_driver; |
803 | 783 | ||
804 | extern const char ipath_core_version[]; | 784 | extern const char ib_ipath_version[]; |
805 | 785 | ||
806 | int ipath_driver_create_group(struct device_driver *); | 786 | int ipath_driver_create_group(struct device_driver *); |
807 | void ipath_driver_remove_group(struct device_driver *); | 787 | void ipath_driver_remove_group(struct device_driver *); |
@@ -810,6 +790,9 @@ int ipath_device_create_group(struct device *, struct ipath_devdata *); | |||
810 | void ipath_device_remove_group(struct device *, struct ipath_devdata *); | 790 | void ipath_device_remove_group(struct device *, struct ipath_devdata *); |
811 | int ipath_expose_reset(struct device *); | 791 | int ipath_expose_reset(struct device *); |
812 | 792 | ||
793 | int ipath_diagpkt_add(void); | ||
794 | void ipath_diagpkt_remove(void); | ||
795 | |||
813 | int ipath_init_ipathfs(void); | 796 | int ipath_init_ipathfs(void); |
814 | void ipath_exit_ipathfs(void); | 797 | void ipath_exit_ipathfs(void); |
815 | int ipathfs_add_device(struct ipath_devdata *); | 798 | int ipathfs_add_device(struct ipath_devdata *); |
@@ -831,10 +814,10 @@ const char *ipath_get_unit_name(int unit); | |||
831 | 814 | ||
832 | extern struct mutex ipath_mutex; | 815 | extern struct mutex ipath_mutex; |
833 | 816 | ||
834 | #define IPATH_DRV_NAME "ipath_core" | 817 | #define IPATH_DRV_NAME "ib_ipath" |
835 | #define IPATH_MAJOR 233 | 818 | #define IPATH_MAJOR 233 |
836 | #define IPATH_USER_MINOR_BASE 0 | 819 | #define IPATH_USER_MINOR_BASE 0 |
837 | #define IPATH_SMA_MINOR 128 | 820 | #define IPATH_DIAGPKT_MINOR 127 |
838 | #define IPATH_DIAG_MINOR_BASE 129 | 821 | #define IPATH_DIAG_MINOR_BASE 129 |
839 | #define IPATH_NMINORS 255 | 822 | #define IPATH_NMINORS 255 |
840 | 823 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c index a5ca279370aa..ba1b93226caa 100644 --- a/drivers/infiniband/hw/ipath/ipath_keys.c +++ b/drivers/infiniband/hw/ipath/ipath_keys.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
35 | 35 | ||
36 | #include "ipath_verbs.h" | 36 | #include "ipath_verbs.h" |
37 | #include "ipath_kernel.h" | ||
37 | 38 | ||
38 | /** | 39 | /** |
39 | * ipath_alloc_lkey - allocate an lkey | 40 | * ipath_alloc_lkey - allocate an lkey |
@@ -60,7 +61,7 @@ int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr) | |||
60 | r = (r + 1) & (rkt->max - 1); | 61 | r = (r + 1) & (rkt->max - 1); |
61 | if (r == n) { | 62 | if (r == n) { |
62 | spin_unlock_irqrestore(&rkt->lock, flags); | 63 | spin_unlock_irqrestore(&rkt->lock, flags); |
63 | _VERBS_INFO("LKEY table full\n"); | 64 | ipath_dbg(KERN_INFO "LKEY table full\n"); |
64 | ret = 0; | 65 | ret = 0; |
65 | goto bail; | 66 | goto bail; |
66 | } | 67 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c index b28c6f81c731..e46aa4ed2a7e 100644 --- a/drivers/infiniband/hw/ipath/ipath_layer.c +++ b/drivers/infiniband/hw/ipath/ipath_layer.c | |||
@@ -42,26 +42,20 @@ | |||
42 | 42 | ||
43 | #include "ipath_kernel.h" | 43 | #include "ipath_kernel.h" |
44 | #include "ipath_layer.h" | 44 | #include "ipath_layer.h" |
45 | #include "ipath_verbs.h" | ||
45 | #include "ipath_common.h" | 46 | #include "ipath_common.h" |
46 | 47 | ||
47 | /* Acquire before ipath_devs_lock. */ | 48 | /* Acquire before ipath_devs_lock. */ |
48 | static DEFINE_MUTEX(ipath_layer_mutex); | 49 | static DEFINE_MUTEX(ipath_layer_mutex); |
49 | 50 | ||
50 | static int ipath_verbs_registered; | ||
51 | |||
52 | u16 ipath_layer_rcv_opcode; | 51 | u16 ipath_layer_rcv_opcode; |
53 | 52 | ||
54 | static int (*layer_intr)(void *, u32); | 53 | static int (*layer_intr)(void *, u32); |
55 | static int (*layer_rcv)(void *, void *, struct sk_buff *); | 54 | static int (*layer_rcv)(void *, void *, struct sk_buff *); |
56 | static int (*layer_rcv_lid)(void *, void *); | 55 | static int (*layer_rcv_lid)(void *, void *); |
57 | static int (*verbs_piobufavail)(void *); | ||
58 | static void (*verbs_rcv)(void *, void *, void *, u32); | ||
59 | 56 | ||
60 | static void *(*layer_add_one)(int, struct ipath_devdata *); | 57 | static void *(*layer_add_one)(int, struct ipath_devdata *); |
61 | static void (*layer_remove_one)(void *); | 58 | static void (*layer_remove_one)(void *); |
62 | static void *(*verbs_add_one)(int, struct ipath_devdata *); | ||
63 | static void (*verbs_remove_one)(void *); | ||
64 | static void (*verbs_timer_cb)(void *); | ||
65 | 59 | ||
66 | int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg) | 60 | int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg) |
67 | { | 61 | { |
@@ -107,302 +101,16 @@ int __ipath_layer_rcv_lid(struct ipath_devdata *dd, void *hdr) | |||
107 | return ret; | 101 | return ret; |
108 | } | 102 | } |
109 | 103 | ||
110 | int __ipath_verbs_piobufavail(struct ipath_devdata *dd) | 104 | void ipath_layer_lid_changed(struct ipath_devdata *dd) |
111 | { | ||
112 | int ret = -ENODEV; | ||
113 | |||
114 | if (dd->verbs_layer.l_arg && verbs_piobufavail) | ||
115 | ret = verbs_piobufavail(dd->verbs_layer.l_arg); | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | int __ipath_verbs_rcv(struct ipath_devdata *dd, void *rc, void *ebuf, | ||
121 | u32 tlen) | ||
122 | { | ||
123 | int ret = -ENODEV; | ||
124 | |||
125 | if (dd->verbs_layer.l_arg && verbs_rcv) { | ||
126 | verbs_rcv(dd->verbs_layer.l_arg, rc, ebuf, tlen); | ||
127 | ret = 0; | ||
128 | } | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 newstate) | ||
134 | { | 105 | { |
135 | u32 lstate; | ||
136 | int ret; | ||
137 | |||
138 | switch (newstate) { | ||
139 | case IPATH_IB_LINKDOWN: | ||
140 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL << | ||
141 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | ||
142 | /* don't wait */ | ||
143 | ret = 0; | ||
144 | goto bail; | ||
145 | |||
146 | case IPATH_IB_LINKDOWN_SLEEP: | ||
147 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP << | ||
148 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | ||
149 | /* don't wait */ | ||
150 | ret = 0; | ||
151 | goto bail; | ||
152 | |||
153 | case IPATH_IB_LINKDOWN_DISABLE: | ||
154 | ipath_set_ib_lstate(dd, | ||
155 | INFINIPATH_IBCC_LINKINITCMD_DISABLE << | ||
156 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | ||
157 | /* don't wait */ | ||
158 | ret = 0; | ||
159 | goto bail; | ||
160 | |||
161 | case IPATH_IB_LINKINIT: | ||
162 | if (dd->ipath_flags & IPATH_LINKINIT) { | ||
163 | ret = 0; | ||
164 | goto bail; | ||
165 | } | ||
166 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT << | ||
167 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
168 | lstate = IPATH_LINKINIT; | ||
169 | break; | ||
170 | |||
171 | case IPATH_IB_LINKARM: | ||
172 | if (dd->ipath_flags & IPATH_LINKARMED) { | ||
173 | ret = 0; | ||
174 | goto bail; | ||
175 | } | ||
176 | if (!(dd->ipath_flags & | ||
177 | (IPATH_LINKINIT | IPATH_LINKACTIVE))) { | ||
178 | ret = -EINVAL; | ||
179 | goto bail; | ||
180 | } | ||
181 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED << | ||
182 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
183 | /* | ||
184 | * Since the port can transition to ACTIVE by receiving | ||
185 | * a non VL 15 packet, wait for either state. | ||
186 | */ | ||
187 | lstate = IPATH_LINKARMED | IPATH_LINKACTIVE; | ||
188 | break; | ||
189 | |||
190 | case IPATH_IB_LINKACTIVE: | ||
191 | if (dd->ipath_flags & IPATH_LINKACTIVE) { | ||
192 | ret = 0; | ||
193 | goto bail; | ||
194 | } | ||
195 | if (!(dd->ipath_flags & IPATH_LINKARMED)) { | ||
196 | ret = -EINVAL; | ||
197 | goto bail; | ||
198 | } | ||
199 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE << | ||
200 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
201 | lstate = IPATH_LINKACTIVE; | ||
202 | break; | ||
203 | |||
204 | default: | ||
205 | ipath_dbg("Invalid linkstate 0x%x requested\n", newstate); | ||
206 | ret = -EINVAL; | ||
207 | goto bail; | ||
208 | } | ||
209 | ret = ipath_wait_linkstate(dd, lstate, 2000); | ||
210 | |||
211 | bail: | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | EXPORT_SYMBOL_GPL(ipath_layer_set_linkstate); | ||
216 | |||
217 | /** | ||
218 | * ipath_layer_set_mtu - set the MTU | ||
219 | * @dd: the infinipath device | ||
220 | * @arg: the new MTU | ||
221 | * | ||
222 | * we can handle "any" incoming size, the issue here is whether we | ||
223 | * need to restrict our outgoing size. For now, we don't do any | ||
224 | * sanity checking on this, and we don't deal with what happens to | ||
225 | * programs that are already running when the size changes. | ||
226 | * NOTE: changing the MTU will usually cause the IBC to go back to | ||
227 | * link initialize (IPATH_IBSTATE_INIT) state... | ||
228 | */ | ||
229 | int ipath_layer_set_mtu(struct ipath_devdata *dd, u16 arg) | ||
230 | { | ||
231 | u32 piosize; | ||
232 | int changed = 0; | ||
233 | int ret; | ||
234 | |||
235 | /* | ||
236 | * mtu is IB data payload max. It's the largest power of 2 less | ||
237 | * than piosize (or even larger, since it only really controls the | ||
238 | * largest we can receive; we can send the max of the mtu and | ||
239 | * piosize). We check that it's one of the valid IB sizes. | ||
240 | */ | ||
241 | if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 && | ||
242 | arg != 4096) { | ||
243 | ipath_dbg("Trying to set invalid mtu %u, failing\n", arg); | ||
244 | ret = -EINVAL; | ||
245 | goto bail; | ||
246 | } | ||
247 | if (dd->ipath_ibmtu == arg) { | ||
248 | ret = 0; /* same as current */ | ||
249 | goto bail; | ||
250 | } | ||
251 | |||
252 | piosize = dd->ipath_ibmaxlen; | ||
253 | dd->ipath_ibmtu = arg; | ||
254 | |||
255 | if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) { | ||
256 | /* Only if it's not the initial value (or reset to it) */ | ||
257 | if (piosize != dd->ipath_init_ibmaxlen) { | ||
258 | dd->ipath_ibmaxlen = piosize; | ||
259 | changed = 1; | ||
260 | } | ||
261 | } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) { | ||
262 | piosize = arg + IPATH_PIO_MAXIBHDR; | ||
263 | ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x " | ||
264 | "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize, | ||
265 | arg); | ||
266 | dd->ipath_ibmaxlen = piosize; | ||
267 | changed = 1; | ||
268 | } | ||
269 | |||
270 | if (changed) { | ||
271 | /* | ||
272 | * set the IBC maxpktlength to the size of our pio | ||
273 | * buffers in words | ||
274 | */ | ||
275 | u64 ibc = dd->ipath_ibcctrl; | ||
276 | ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK << | ||
277 | INFINIPATH_IBCC_MAXPKTLEN_SHIFT); | ||
278 | |||
279 | piosize = piosize - 2 * sizeof(u32); /* ignore pbc */ | ||
280 | dd->ipath_ibmaxlen = piosize; | ||
281 | piosize /= sizeof(u32); /* in words */ | ||
282 | /* | ||
283 | * for ICRC, which we only send in diag test pkt mode, and | ||
284 | * we don't need to worry about that for mtu | ||
285 | */ | ||
286 | piosize += 1; | ||
287 | |||
288 | ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT; | ||
289 | dd->ipath_ibcctrl = ibc; | ||
290 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
291 | dd->ipath_ibcctrl); | ||
292 | dd->ipath_f_tidtemplate(dd); | ||
293 | } | ||
294 | |||
295 | ret = 0; | ||
296 | |||
297 | bail: | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | EXPORT_SYMBOL_GPL(ipath_layer_set_mtu); | ||
302 | |||
303 | int ipath_set_lid(struct ipath_devdata *dd, u32 arg, u8 lmc) | ||
304 | { | ||
305 | dd->ipath_lid = arg; | ||
306 | dd->ipath_lmc = lmc; | ||
307 | |||
308 | mutex_lock(&ipath_layer_mutex); | 106 | mutex_lock(&ipath_layer_mutex); |
309 | 107 | ||
310 | if (dd->ipath_layer.l_arg && layer_intr) | 108 | if (dd->ipath_layer.l_arg && layer_intr) |
311 | layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID); | 109 | layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID); |
312 | 110 | ||
313 | mutex_unlock(&ipath_layer_mutex); | 111 | mutex_unlock(&ipath_layer_mutex); |
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | EXPORT_SYMBOL_GPL(ipath_set_lid); | ||
319 | |||
320 | int ipath_layer_set_guid(struct ipath_devdata *dd, __be64 guid) | ||
321 | { | ||
322 | /* XXX - need to inform anyone who cares this just happened. */ | ||
323 | dd->ipath_guid = guid; | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | EXPORT_SYMBOL_GPL(ipath_layer_set_guid); | ||
328 | |||
329 | __be64 ipath_layer_get_guid(struct ipath_devdata *dd) | ||
330 | { | ||
331 | return dd->ipath_guid; | ||
332 | } | ||
333 | |||
334 | EXPORT_SYMBOL_GPL(ipath_layer_get_guid); | ||
335 | |||
336 | u32 ipath_layer_get_nguid(struct ipath_devdata *dd) | ||
337 | { | ||
338 | return dd->ipath_nguid; | ||
339 | } | ||
340 | |||
341 | EXPORT_SYMBOL_GPL(ipath_layer_get_nguid); | ||
342 | |||
343 | u32 ipath_layer_get_majrev(struct ipath_devdata *dd) | ||
344 | { | ||
345 | return dd->ipath_majrev; | ||
346 | } | 112 | } |
347 | 113 | ||
348 | EXPORT_SYMBOL_GPL(ipath_layer_get_majrev); | ||
349 | |||
350 | u32 ipath_layer_get_minrev(struct ipath_devdata *dd) | ||
351 | { | ||
352 | return dd->ipath_minrev; | ||
353 | } | ||
354 | |||
355 | EXPORT_SYMBOL_GPL(ipath_layer_get_minrev); | ||
356 | |||
357 | u32 ipath_layer_get_pcirev(struct ipath_devdata *dd) | ||
358 | { | ||
359 | return dd->ipath_pcirev; | ||
360 | } | ||
361 | |||
362 | EXPORT_SYMBOL_GPL(ipath_layer_get_pcirev); | ||
363 | |||
364 | u32 ipath_layer_get_flags(struct ipath_devdata *dd) | ||
365 | { | ||
366 | return dd->ipath_flags; | ||
367 | } | ||
368 | |||
369 | EXPORT_SYMBOL_GPL(ipath_layer_get_flags); | ||
370 | |||
371 | struct device *ipath_layer_get_device(struct ipath_devdata *dd) | ||
372 | { | ||
373 | return &dd->pcidev->dev; | ||
374 | } | ||
375 | |||
376 | EXPORT_SYMBOL_GPL(ipath_layer_get_device); | ||
377 | |||
378 | u16 ipath_layer_get_deviceid(struct ipath_devdata *dd) | ||
379 | { | ||
380 | return dd->ipath_deviceid; | ||
381 | } | ||
382 | |||
383 | EXPORT_SYMBOL_GPL(ipath_layer_get_deviceid); | ||
384 | |||
385 | u32 ipath_layer_get_vendorid(struct ipath_devdata *dd) | ||
386 | { | ||
387 | return dd->ipath_vendorid; | ||
388 | } | ||
389 | |||
390 | EXPORT_SYMBOL_GPL(ipath_layer_get_vendorid); | ||
391 | |||
392 | u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd) | ||
393 | { | ||
394 | return dd->ipath_lastibcstat; | ||
395 | } | ||
396 | |||
397 | EXPORT_SYMBOL_GPL(ipath_layer_get_lastibcstat); | ||
398 | |||
399 | u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd) | ||
400 | { | ||
401 | return dd->ipath_ibmtu; | ||
402 | } | ||
403 | |||
404 | EXPORT_SYMBOL_GPL(ipath_layer_get_ibmtu); | ||
405 | |||
406 | void ipath_layer_add(struct ipath_devdata *dd) | 114 | void ipath_layer_add(struct ipath_devdata *dd) |
407 | { | 115 | { |
408 | mutex_lock(&ipath_layer_mutex); | 116 | mutex_lock(&ipath_layer_mutex); |
@@ -411,10 +119,6 @@ void ipath_layer_add(struct ipath_devdata *dd) | |||
411 | dd->ipath_layer.l_arg = | 119 | dd->ipath_layer.l_arg = |
412 | layer_add_one(dd->ipath_unit, dd); | 120 | layer_add_one(dd->ipath_unit, dd); |
413 | 121 | ||
414 | if (verbs_add_one) | ||
415 | dd->verbs_layer.l_arg = | ||
416 | verbs_add_one(dd->ipath_unit, dd); | ||
417 | |||
418 | mutex_unlock(&ipath_layer_mutex); | 122 | mutex_unlock(&ipath_layer_mutex); |
419 | } | 123 | } |
420 | 124 | ||
@@ -427,11 +131,6 @@ void ipath_layer_remove(struct ipath_devdata *dd) | |||
427 | dd->ipath_layer.l_arg = NULL; | 131 | dd->ipath_layer.l_arg = NULL; |
428 | } | 132 | } |
429 | 133 | ||
430 | if (dd->verbs_layer.l_arg && verbs_remove_one) { | ||
431 | verbs_remove_one(dd->verbs_layer.l_arg); | ||
432 | dd->verbs_layer.l_arg = NULL; | ||
433 | } | ||
434 | |||
435 | mutex_unlock(&ipath_layer_mutex); | 134 | mutex_unlock(&ipath_layer_mutex); |
436 | } | 135 | } |
437 | 136 | ||
@@ -463,9 +162,6 @@ int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *), | |||
463 | if (dd->ipath_layer.l_arg) | 162 | if (dd->ipath_layer.l_arg) |
464 | continue; | 163 | continue; |
465 | 164 | ||
466 | if (!(*dd->ipath_statusp & IPATH_STATUS_SMA)) | ||
467 | *dd->ipath_statusp |= IPATH_STATUS_OIB_SMA; | ||
468 | |||
469 | spin_unlock_irqrestore(&ipath_devs_lock, flags); | 165 | spin_unlock_irqrestore(&ipath_devs_lock, flags); |
470 | dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd); | 166 | dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd); |
471 | spin_lock_irqsave(&ipath_devs_lock, flags); | 167 | spin_lock_irqsave(&ipath_devs_lock, flags); |
@@ -509,107 +205,6 @@ void ipath_layer_unregister(void) | |||
509 | 205 | ||
510 | EXPORT_SYMBOL_GPL(ipath_layer_unregister); | 206 | EXPORT_SYMBOL_GPL(ipath_layer_unregister); |
511 | 207 | ||
512 | static void __ipath_verbs_timer(unsigned long arg) | ||
513 | { | ||
514 | struct ipath_devdata *dd = (struct ipath_devdata *) arg; | ||
515 | |||
516 | /* | ||
517 | * If port 0 receive packet interrupts are not available, or | ||
518 | * can be missed, poll the receive queue | ||
519 | */ | ||
520 | if (dd->ipath_flags & IPATH_POLL_RX_INTR) | ||
521 | ipath_kreceive(dd); | ||
522 | |||
523 | /* Handle verbs layer timeouts. */ | ||
524 | if (dd->verbs_layer.l_arg && verbs_timer_cb) | ||
525 | verbs_timer_cb(dd->verbs_layer.l_arg); | ||
526 | |||
527 | mod_timer(&dd->verbs_layer.l_timer, jiffies + 1); | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * ipath_verbs_register - verbs layer registration | ||
532 | * @l_piobufavail: callback for when PIO buffers become available | ||
533 | * @l_rcv: callback for receiving a packet | ||
534 | * @l_timer_cb: timer callback | ||
535 | * @ipath_devdata: device data structure is put here | ||
536 | */ | ||
537 | int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *), | ||
538 | void (*l_remove)(void *arg), | ||
539 | int (*l_piobufavail) (void *arg), | ||
540 | void (*l_rcv) (void *arg, void *rhdr, | ||
541 | void *data, u32 tlen), | ||
542 | void (*l_timer_cb) (void *arg)) | ||
543 | { | ||
544 | struct ipath_devdata *dd, *tmp; | ||
545 | unsigned long flags; | ||
546 | |||
547 | mutex_lock(&ipath_layer_mutex); | ||
548 | |||
549 | verbs_add_one = l_add; | ||
550 | verbs_remove_one = l_remove; | ||
551 | verbs_piobufavail = l_piobufavail; | ||
552 | verbs_rcv = l_rcv; | ||
553 | verbs_timer_cb = l_timer_cb; | ||
554 | |||
555 | spin_lock_irqsave(&ipath_devs_lock, flags); | ||
556 | |||
557 | list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { | ||
558 | if (!(dd->ipath_flags & IPATH_INITTED)) | ||
559 | continue; | ||
560 | |||
561 | if (dd->verbs_layer.l_arg) | ||
562 | continue; | ||
563 | |||
564 | spin_unlock_irqrestore(&ipath_devs_lock, flags); | ||
565 | dd->verbs_layer.l_arg = l_add(dd->ipath_unit, dd); | ||
566 | spin_lock_irqsave(&ipath_devs_lock, flags); | ||
567 | } | ||
568 | |||
569 | spin_unlock_irqrestore(&ipath_devs_lock, flags); | ||
570 | mutex_unlock(&ipath_layer_mutex); | ||
571 | |||
572 | ipath_verbs_registered = 1; | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | EXPORT_SYMBOL_GPL(ipath_verbs_register); | ||
578 | |||
579 | void ipath_verbs_unregister(void) | ||
580 | { | ||
581 | struct ipath_devdata *dd, *tmp; | ||
582 | unsigned long flags; | ||
583 | |||
584 | mutex_lock(&ipath_layer_mutex); | ||
585 | spin_lock_irqsave(&ipath_devs_lock, flags); | ||
586 | |||
587 | list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { | ||
588 | *dd->ipath_statusp &= ~IPATH_STATUS_OIB_SMA; | ||
589 | |||
590 | if (dd->verbs_layer.l_arg && verbs_remove_one) { | ||
591 | spin_unlock_irqrestore(&ipath_devs_lock, flags); | ||
592 | verbs_remove_one(dd->verbs_layer.l_arg); | ||
593 | spin_lock_irqsave(&ipath_devs_lock, flags); | ||
594 | dd->verbs_layer.l_arg = NULL; | ||
595 | } | ||
596 | } | ||
597 | |||
598 | spin_unlock_irqrestore(&ipath_devs_lock, flags); | ||
599 | |||
600 | verbs_add_one = NULL; | ||
601 | verbs_remove_one = NULL; | ||
602 | verbs_piobufavail = NULL; | ||
603 | verbs_rcv = NULL; | ||
604 | verbs_timer_cb = NULL; | ||
605 | |||
606 | ipath_verbs_registered = 0; | ||
607 | |||
608 | mutex_unlock(&ipath_layer_mutex); | ||
609 | } | ||
610 | |||
611 | EXPORT_SYMBOL_GPL(ipath_verbs_unregister); | ||
612 | |||
613 | int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax) | 208 | int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax) |
614 | { | 209 | { |
615 | int ret; | 210 | int ret; |
@@ -698,390 +293,6 @@ u16 ipath_layer_get_bcast(struct ipath_devdata *dd) | |||
698 | 293 | ||
699 | EXPORT_SYMBOL_GPL(ipath_layer_get_bcast); | 294 | EXPORT_SYMBOL_GPL(ipath_layer_get_bcast); |
700 | 295 | ||
701 | u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd) | ||
702 | { | ||
703 | return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey); | ||
704 | } | ||
705 | |||
706 | EXPORT_SYMBOL_GPL(ipath_layer_get_cr_errpkey); | ||
707 | |||
708 | static void update_sge(struct ipath_sge_state *ss, u32 length) | ||
709 | { | ||
710 | struct ipath_sge *sge = &ss->sge; | ||
711 | |||
712 | sge->vaddr += length; | ||
713 | sge->length -= length; | ||
714 | sge->sge_length -= length; | ||
715 | if (sge->sge_length == 0) { | ||
716 | if (--ss->num_sge) | ||
717 | *sge = *ss->sg_list++; | ||
718 | } else if (sge->length == 0 && sge->mr != NULL) { | ||
719 | if (++sge->n >= IPATH_SEGSZ) { | ||
720 | if (++sge->m >= sge->mr->mapsz) | ||
721 | return; | ||
722 | sge->n = 0; | ||
723 | } | ||
724 | sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr; | ||
725 | sge->length = sge->mr->map[sge->m]->segs[sge->n].length; | ||
726 | } | ||
727 | } | ||
728 | |||
729 | #ifdef __LITTLE_ENDIAN | ||
730 | static inline u32 get_upper_bits(u32 data, u32 shift) | ||
731 | { | ||
732 | return data >> shift; | ||
733 | } | ||
734 | |||
735 | static inline u32 set_upper_bits(u32 data, u32 shift) | ||
736 | { | ||
737 | return data << shift; | ||
738 | } | ||
739 | |||
740 | static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) | ||
741 | { | ||
742 | data <<= ((sizeof(u32) - n) * BITS_PER_BYTE); | ||
743 | data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE); | ||
744 | return data; | ||
745 | } | ||
746 | #else | ||
747 | static inline u32 get_upper_bits(u32 data, u32 shift) | ||
748 | { | ||
749 | return data << shift; | ||
750 | } | ||
751 | |||
752 | static inline u32 set_upper_bits(u32 data, u32 shift) | ||
753 | { | ||
754 | return data >> shift; | ||
755 | } | ||
756 | |||
757 | static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) | ||
758 | { | ||
759 | data >>= ((sizeof(u32) - n) * BITS_PER_BYTE); | ||
760 | data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE); | ||
761 | return data; | ||
762 | } | ||
763 | #endif | ||
764 | |||
765 | static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, | ||
766 | u32 length) | ||
767 | { | ||
768 | u32 extra = 0; | ||
769 | u32 data = 0; | ||
770 | u32 last; | ||
771 | |||
772 | while (1) { | ||
773 | u32 len = ss->sge.length; | ||
774 | u32 off; | ||
775 | |||
776 | BUG_ON(len == 0); | ||
777 | if (len > length) | ||
778 | len = length; | ||
779 | if (len > ss->sge.sge_length) | ||
780 | len = ss->sge.sge_length; | ||
781 | /* If the source address is not aligned, try to align it. */ | ||
782 | off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1); | ||
783 | if (off) { | ||
784 | u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr & | ||
785 | ~(sizeof(u32) - 1)); | ||
786 | u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE); | ||
787 | u32 y; | ||
788 | |||
789 | y = sizeof(u32) - off; | ||
790 | if (len > y) | ||
791 | len = y; | ||
792 | if (len + extra >= sizeof(u32)) { | ||
793 | data |= set_upper_bits(v, extra * | ||
794 | BITS_PER_BYTE); | ||
795 | len = sizeof(u32) - extra; | ||
796 | if (len == length) { | ||
797 | last = data; | ||
798 | break; | ||
799 | } | ||
800 | __raw_writel(data, piobuf); | ||
801 | piobuf++; | ||
802 | extra = 0; | ||
803 | data = 0; | ||
804 | } else { | ||
805 | /* Clear unused upper bytes */ | ||
806 | data |= clear_upper_bytes(v, len, extra); | ||
807 | if (len == length) { | ||
808 | last = data; | ||
809 | break; | ||
810 | } | ||
811 | extra += len; | ||
812 | } | ||
813 | } else if (extra) { | ||
814 | /* Source address is aligned. */ | ||
815 | u32 *addr = (u32 *) ss->sge.vaddr; | ||
816 | int shift = extra * BITS_PER_BYTE; | ||
817 | int ushift = 32 - shift; | ||
818 | u32 l = len; | ||
819 | |||
820 | while (l >= sizeof(u32)) { | ||
821 | u32 v = *addr; | ||
822 | |||
823 | data |= set_upper_bits(v, shift); | ||
824 | __raw_writel(data, piobuf); | ||
825 | data = get_upper_bits(v, ushift); | ||
826 | piobuf++; | ||
827 | addr++; | ||
828 | l -= sizeof(u32); | ||
829 | } | ||
830 | /* | ||
831 | * We still have 'extra' number of bytes leftover. | ||
832 | */ | ||
833 | if (l) { | ||
834 | u32 v = *addr; | ||
835 | |||
836 | if (l + extra >= sizeof(u32)) { | ||
837 | data |= set_upper_bits(v, shift); | ||
838 | len -= l + extra - sizeof(u32); | ||
839 | if (len == length) { | ||
840 | last = data; | ||
841 | break; | ||
842 | } | ||
843 | __raw_writel(data, piobuf); | ||
844 | piobuf++; | ||
845 | extra = 0; | ||
846 | data = 0; | ||
847 | } else { | ||
848 | /* Clear unused upper bytes */ | ||
849 | data |= clear_upper_bytes(v, l, | ||
850 | extra); | ||
851 | if (len == length) { | ||
852 | last = data; | ||
853 | break; | ||
854 | } | ||
855 | extra += l; | ||
856 | } | ||
857 | } else if (len == length) { | ||
858 | last = data; | ||
859 | break; | ||
860 | } | ||
861 | } else if (len == length) { | ||
862 | u32 w; | ||
863 | |||
864 | /* | ||
865 | * Need to round up for the last dword in the | ||
866 | * packet. | ||
867 | */ | ||
868 | w = (len + 3) >> 2; | ||
869 | __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1); | ||
870 | piobuf += w - 1; | ||
871 | last = ((u32 *) ss->sge.vaddr)[w - 1]; | ||
872 | break; | ||
873 | } else { | ||
874 | u32 w = len >> 2; | ||
875 | |||
876 | __iowrite32_copy(piobuf, ss->sge.vaddr, w); | ||
877 | piobuf += w; | ||
878 | |||
879 | extra = len & (sizeof(u32) - 1); | ||
880 | if (extra) { | ||
881 | u32 v = ((u32 *) ss->sge.vaddr)[w]; | ||
882 | |||
883 | /* Clear unused upper bytes */ | ||
884 | data = clear_upper_bytes(v, extra, 0); | ||
885 | } | ||
886 | } | ||
887 | update_sge(ss, len); | ||
888 | length -= len; | ||
889 | } | ||
890 | /* Update address before sending packet. */ | ||
891 | update_sge(ss, length); | ||
892 | /* must flush early everything before trigger word */ | ||
893 | ipath_flush_wc(); | ||
894 | __raw_writel(last, piobuf); | ||
895 | /* be sure trigger word is written */ | ||
896 | ipath_flush_wc(); | ||
897 | } | ||
898 | |||
899 | /** | ||
900 | * ipath_verbs_send - send a packet from the verbs layer | ||
901 | * @dd: the infinipath device | ||
902 | * @hdrwords: the number of words in the header | ||
903 | * @hdr: the packet header | ||
904 | * @len: the length of the packet in bytes | ||
905 | * @ss: the SGE to send | ||
906 | * | ||
907 | * This is like ipath_sma_send_pkt() in that we need to be able to send | ||
908 | * packets after the chip is initialized (MADs) but also like | ||
909 | * ipath_layer_send_hdr() since its used by the verbs layer. | ||
910 | */ | ||
911 | int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, | ||
912 | u32 *hdr, u32 len, struct ipath_sge_state *ss) | ||
913 | { | ||
914 | u32 __iomem *piobuf; | ||
915 | u32 plen; | ||
916 | int ret; | ||
917 | |||
918 | /* +1 is for the qword padding of pbc */ | ||
919 | plen = hdrwords + ((len + 3) >> 2) + 1; | ||
920 | if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) { | ||
921 | ipath_dbg("packet len 0x%x too long, failing\n", plen); | ||
922 | ret = -EINVAL; | ||
923 | goto bail; | ||
924 | } | ||
925 | |||
926 | /* Get a PIO buffer to use. */ | ||
927 | piobuf = ipath_getpiobuf(dd, NULL); | ||
928 | if (unlikely(piobuf == NULL)) { | ||
929 | ret = -EBUSY; | ||
930 | goto bail; | ||
931 | } | ||
932 | |||
933 | /* | ||
934 | * Write len to control qword, no flags. | ||
935 | * We have to flush after the PBC for correctness on some cpus | ||
936 | * or WC buffer can be written out of order. | ||
937 | */ | ||
938 | writeq(plen, piobuf); | ||
939 | ipath_flush_wc(); | ||
940 | piobuf += 2; | ||
941 | if (len == 0) { | ||
942 | /* | ||
943 | * If there is just the header portion, must flush before | ||
944 | * writing last word of header for correctness, and after | ||
945 | * the last header word (trigger word). | ||
946 | */ | ||
947 | __iowrite32_copy(piobuf, hdr, hdrwords - 1); | ||
948 | ipath_flush_wc(); | ||
949 | __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1); | ||
950 | ipath_flush_wc(); | ||
951 | ret = 0; | ||
952 | goto bail; | ||
953 | } | ||
954 | |||
955 | __iowrite32_copy(piobuf, hdr, hdrwords); | ||
956 | piobuf += hdrwords; | ||
957 | |||
958 | /* The common case is aligned and contained in one segment. */ | ||
959 | if (likely(ss->num_sge == 1 && len <= ss->sge.length && | ||
960 | !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) { | ||
961 | u32 w; | ||
962 | u32 *addr = (u32 *) ss->sge.vaddr; | ||
963 | |||
964 | /* Update address before sending packet. */ | ||
965 | update_sge(ss, len); | ||
966 | /* Need to round up for the last dword in the packet. */ | ||
967 | w = (len + 3) >> 2; | ||
968 | __iowrite32_copy(piobuf, addr, w - 1); | ||
969 | /* must flush early everything before trigger word */ | ||
970 | ipath_flush_wc(); | ||
971 | __raw_writel(addr[w - 1], piobuf + w - 1); | ||
972 | /* be sure trigger word is written */ | ||
973 | ipath_flush_wc(); | ||
974 | ret = 0; | ||
975 | goto bail; | ||
976 | } | ||
977 | copy_io(piobuf, ss, len); | ||
978 | ret = 0; | ||
979 | |||
980 | bail: | ||
981 | return ret; | ||
982 | } | ||
983 | |||
984 | EXPORT_SYMBOL_GPL(ipath_verbs_send); | ||
985 | |||
986 | int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords, | ||
987 | u64 *rwords, u64 *spkts, u64 *rpkts, | ||
988 | u64 *xmit_wait) | ||
989 | { | ||
990 | int ret; | ||
991 | |||
992 | if (!(dd->ipath_flags & IPATH_INITTED)) { | ||
993 | /* no hardware, freeze, etc. */ | ||
994 | ipath_dbg("unit %u not usable\n", dd->ipath_unit); | ||
995 | ret = -EINVAL; | ||
996 | goto bail; | ||
997 | } | ||
998 | *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); | ||
999 | *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); | ||
1000 | *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); | ||
1001 | *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); | ||
1002 | *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt); | ||
1003 | |||
1004 | ret = 0; | ||
1005 | |||
1006 | bail: | ||
1007 | return ret; | ||
1008 | } | ||
1009 | |||
1010 | EXPORT_SYMBOL_GPL(ipath_layer_snapshot_counters); | ||
1011 | |||
1012 | /** | ||
1013 | * ipath_layer_get_counters - get various chip counters | ||
1014 | * @dd: the infinipath device | ||
1015 | * @cntrs: counters are placed here | ||
1016 | * | ||
1017 | * Return the counters needed by recv_pma_get_portcounters(). | ||
1018 | */ | ||
1019 | int ipath_layer_get_counters(struct ipath_devdata *dd, | ||
1020 | struct ipath_layer_counters *cntrs) | ||
1021 | { | ||
1022 | int ret; | ||
1023 | |||
1024 | if (!(dd->ipath_flags & IPATH_INITTED)) { | ||
1025 | /* no hardware, freeze, etc. */ | ||
1026 | ipath_dbg("unit %u not usable\n", dd->ipath_unit); | ||
1027 | ret = -EINVAL; | ||
1028 | goto bail; | ||
1029 | } | ||
1030 | cntrs->symbol_error_counter = | ||
1031 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt); | ||
1032 | cntrs->link_error_recovery_counter = | ||
1033 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt); | ||
1034 | /* | ||
1035 | * The link downed counter counts when the other side downs the | ||
1036 | * connection. We add in the number of times we downed the link | ||
1037 | * due to local link integrity errors to compensate. | ||
1038 | */ | ||
1039 | cntrs->link_downed_counter = | ||
1040 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt); | ||
1041 | cntrs->port_rcv_errors = | ||
1042 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) + | ||
1043 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) + | ||
1044 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) + | ||
1045 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) + | ||
1046 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) + | ||
1047 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) + | ||
1048 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) + | ||
1049 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) + | ||
1050 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt); | ||
1051 | cntrs->port_rcv_remphys_errors = | ||
1052 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt); | ||
1053 | cntrs->port_xmit_discards = | ||
1054 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt); | ||
1055 | cntrs->port_xmit_data = | ||
1056 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); | ||
1057 | cntrs->port_rcv_data = | ||
1058 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); | ||
1059 | cntrs->port_xmit_packets = | ||
1060 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); | ||
1061 | cntrs->port_rcv_packets = | ||
1062 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); | ||
1063 | cntrs->local_link_integrity_errors = dd->ipath_lli_errors; | ||
1064 | cntrs->excessive_buffer_overrun_errors = 0; /* XXX */ | ||
1065 | |||
1066 | ret = 0; | ||
1067 | |||
1068 | bail: | ||
1069 | return ret; | ||
1070 | } | ||
1071 | |||
1072 | EXPORT_SYMBOL_GPL(ipath_layer_get_counters); | ||
1073 | |||
1074 | int ipath_layer_want_buffer(struct ipath_devdata *dd) | ||
1075 | { | ||
1076 | set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); | ||
1077 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | ||
1078 | dd->ipath_sendctrl); | ||
1079 | |||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | EXPORT_SYMBOL_GPL(ipath_layer_want_buffer); | ||
1084 | |||
1085 | int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr) | 296 | int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr) |
1086 | { | 297 | { |
1087 | int ret = 0; | 298 | int ret = 0; |
@@ -1153,389 +364,3 @@ int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd) | |||
1153 | } | 364 | } |
1154 | 365 | ||
1155 | EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int); | 366 | EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int); |
1156 | |||
1157 | int ipath_layer_enable_timer(struct ipath_devdata *dd) | ||
1158 | { | ||
1159 | /* | ||
1160 | * HT-400 has a design flaw where the chip and kernel idea | ||
1161 | * of the tail register don't always agree, and therefore we won't | ||
1162 | * get an interrupt on the next packet received. | ||
1163 | * If the board supports per packet receive interrupts, use it. | ||
1164 | * Otherwise, the timer function periodically checks for packets | ||
1165 | * to cover this case. | ||
1166 | * Either way, the timer is needed for verbs layer related | ||
1167 | * processing. | ||
1168 | */ | ||
1169 | if (dd->ipath_flags & IPATH_GPIO_INTR) { | ||
1170 | ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect, | ||
1171 | 0x2074076542310ULL); | ||
1172 | /* Enable GPIO bit 2 interrupt */ | ||
1173 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, | ||
1174 | (u64) (1 << 2)); | ||
1175 | } | ||
1176 | |||
1177 | init_timer(&dd->verbs_layer.l_timer); | ||
1178 | dd->verbs_layer.l_timer.function = __ipath_verbs_timer; | ||
1179 | dd->verbs_layer.l_timer.data = (unsigned long)dd; | ||
1180 | dd->verbs_layer.l_timer.expires = jiffies + 1; | ||
1181 | add_timer(&dd->verbs_layer.l_timer); | ||
1182 | |||
1183 | return 0; | ||
1184 | } | ||
1185 | |||
1186 | EXPORT_SYMBOL_GPL(ipath_layer_enable_timer); | ||
1187 | |||
1188 | int ipath_layer_disable_timer(struct ipath_devdata *dd) | ||
1189 | { | ||
1190 | /* Disable GPIO bit 2 interrupt */ | ||
1191 | if (dd->ipath_flags & IPATH_GPIO_INTR) | ||
1192 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, 0); | ||
1193 | |||
1194 | del_timer_sync(&dd->verbs_layer.l_timer); | ||
1195 | |||
1196 | return 0; | ||
1197 | } | ||
1198 | |||
1199 | EXPORT_SYMBOL_GPL(ipath_layer_disable_timer); | ||
1200 | |||
1201 | /** | ||
1202 | * ipath_layer_set_verbs_flags - set the verbs layer flags | ||
1203 | * @dd: the infinipath device | ||
1204 | * @flags: the flags to set | ||
1205 | */ | ||
1206 | int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags) | ||
1207 | { | ||
1208 | struct ipath_devdata *ss; | ||
1209 | unsigned long lflags; | ||
1210 | |||
1211 | spin_lock_irqsave(&ipath_devs_lock, lflags); | ||
1212 | |||
1213 | list_for_each_entry(ss, &ipath_dev_list, ipath_list) { | ||
1214 | if (!(ss->ipath_flags & IPATH_INITTED)) | ||
1215 | continue; | ||
1216 | if ((flags & IPATH_VERBS_KERNEL_SMA) && | ||
1217 | !(*ss->ipath_statusp & IPATH_STATUS_SMA)) | ||
1218 | *ss->ipath_statusp |= IPATH_STATUS_OIB_SMA; | ||
1219 | else | ||
1220 | *ss->ipath_statusp &= ~IPATH_STATUS_OIB_SMA; | ||
1221 | } | ||
1222 | |||
1223 | spin_unlock_irqrestore(&ipath_devs_lock, lflags); | ||
1224 | |||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | EXPORT_SYMBOL_GPL(ipath_layer_set_verbs_flags); | ||
1229 | |||
1230 | /** | ||
1231 | * ipath_layer_get_npkeys - return the size of the PKEY table for port 0 | ||
1232 | * @dd: the infinipath device | ||
1233 | */ | ||
1234 | unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd) | ||
1235 | { | ||
1236 | return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys); | ||
1237 | } | ||
1238 | |||
1239 | EXPORT_SYMBOL_GPL(ipath_layer_get_npkeys); | ||
1240 | |||
1241 | /** | ||
1242 | * ipath_layer_get_pkey - return the indexed PKEY from the port 0 PKEY table | ||
1243 | * @dd: the infinipath device | ||
1244 | * @index: the PKEY index | ||
1245 | */ | ||
1246 | unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index) | ||
1247 | { | ||
1248 | unsigned ret; | ||
1249 | |||
1250 | if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys)) | ||
1251 | ret = 0; | ||
1252 | else | ||
1253 | ret = dd->ipath_pd[0]->port_pkeys[index]; | ||
1254 | |||
1255 | return ret; | ||
1256 | } | ||
1257 | |||
1258 | EXPORT_SYMBOL_GPL(ipath_layer_get_pkey); | ||
1259 | |||
1260 | /** | ||
1261 | * ipath_layer_get_pkeys - return the PKEY table for port 0 | ||
1262 | * @dd: the infinipath device | ||
1263 | * @pkeys: the pkey table is placed here | ||
1264 | */ | ||
1265 | int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 * pkeys) | ||
1266 | { | ||
1267 | struct ipath_portdata *pd = dd->ipath_pd[0]; | ||
1268 | |||
1269 | memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys)); | ||
1270 | |||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | EXPORT_SYMBOL_GPL(ipath_layer_get_pkeys); | ||
1275 | |||
1276 | /** | ||
1277 | * rm_pkey - decrecment the reference count for the given PKEY | ||
1278 | * @dd: the infinipath device | ||
1279 | * @key: the PKEY index | ||
1280 | * | ||
1281 | * Return true if this was the last reference and the hardware table entry | ||
1282 | * needs to be changed. | ||
1283 | */ | ||
1284 | static int rm_pkey(struct ipath_devdata *dd, u16 key) | ||
1285 | { | ||
1286 | int i; | ||
1287 | int ret; | ||
1288 | |||
1289 | for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { | ||
1290 | if (dd->ipath_pkeys[i] != key) | ||
1291 | continue; | ||
1292 | if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) { | ||
1293 | dd->ipath_pkeys[i] = 0; | ||
1294 | ret = 1; | ||
1295 | goto bail; | ||
1296 | } | ||
1297 | break; | ||
1298 | } | ||
1299 | |||
1300 | ret = 0; | ||
1301 | |||
1302 | bail: | ||
1303 | return ret; | ||
1304 | } | ||
1305 | |||
1306 | /** | ||
1307 | * add_pkey - add the given PKEY to the hardware table | ||
1308 | * @dd: the infinipath device | ||
1309 | * @key: the PKEY | ||
1310 | * | ||
1311 | * Return an error code if unable to add the entry, zero if no change, | ||
1312 | * or 1 if the hardware PKEY register needs to be updated. | ||
1313 | */ | ||
1314 | static int add_pkey(struct ipath_devdata *dd, u16 key) | ||
1315 | { | ||
1316 | int i; | ||
1317 | u16 lkey = key & 0x7FFF; | ||
1318 | int any = 0; | ||
1319 | int ret; | ||
1320 | |||
1321 | if (lkey == 0x7FFF) { | ||
1322 | ret = 0; | ||
1323 | goto bail; | ||
1324 | } | ||
1325 | |||
1326 | /* Look for an empty slot or a matching PKEY. */ | ||
1327 | for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { | ||
1328 | if (!dd->ipath_pkeys[i]) { | ||
1329 | any++; | ||
1330 | continue; | ||
1331 | } | ||
1332 | /* If it matches exactly, try to increment the ref count */ | ||
1333 | if (dd->ipath_pkeys[i] == key) { | ||
1334 | if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) { | ||
1335 | ret = 0; | ||
1336 | goto bail; | ||
1337 | } | ||
1338 | /* Lost the race. Look for an empty slot below. */ | ||
1339 | atomic_dec(&dd->ipath_pkeyrefs[i]); | ||
1340 | any++; | ||
1341 | } | ||
1342 | /* | ||
1343 | * It makes no sense to have both the limited and unlimited | ||
1344 | * PKEY set at the same time since the unlimited one will | ||
1345 | * disable the limited one. | ||
1346 | */ | ||
1347 | if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) { | ||
1348 | ret = -EEXIST; | ||
1349 | goto bail; | ||
1350 | } | ||
1351 | } | ||
1352 | if (!any) { | ||
1353 | ret = -EBUSY; | ||
1354 | goto bail; | ||
1355 | } | ||
1356 | for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { | ||
1357 | if (!dd->ipath_pkeys[i] && | ||
1358 | atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) { | ||
1359 | /* for ipathstats, etc. */ | ||
1360 | ipath_stats.sps_pkeys[i] = lkey; | ||
1361 | dd->ipath_pkeys[i] = key; | ||
1362 | ret = 1; | ||
1363 | goto bail; | ||
1364 | } | ||
1365 | } | ||
1366 | ret = -EBUSY; | ||
1367 | |||
1368 | bail: | ||
1369 | return ret; | ||
1370 | } | ||
1371 | |||
1372 | /** | ||
1373 | * ipath_layer_set_pkeys - set the PKEY table for port 0 | ||
1374 | * @dd: the infinipath device | ||
1375 | * @pkeys: the PKEY table | ||
1376 | */ | ||
1377 | int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 * pkeys) | ||
1378 | { | ||
1379 | struct ipath_portdata *pd; | ||
1380 | int i; | ||
1381 | int changed = 0; | ||
1382 | |||
1383 | pd = dd->ipath_pd[0]; | ||
1384 | |||
1385 | for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { | ||
1386 | u16 key = pkeys[i]; | ||
1387 | u16 okey = pd->port_pkeys[i]; | ||
1388 | |||
1389 | if (key == okey) | ||
1390 | continue; | ||
1391 | /* | ||
1392 | * The value of this PKEY table entry is changing. | ||
1393 | * Remove the old entry in the hardware's array of PKEYs. | ||
1394 | */ | ||
1395 | if (okey & 0x7FFF) | ||
1396 | changed |= rm_pkey(dd, okey); | ||
1397 | if (key & 0x7FFF) { | ||
1398 | int ret = add_pkey(dd, key); | ||
1399 | |||
1400 | if (ret < 0) | ||
1401 | key = 0; | ||
1402 | else | ||
1403 | changed |= ret; | ||
1404 | } | ||
1405 | pd->port_pkeys[i] = key; | ||
1406 | } | ||
1407 | if (changed) { | ||
1408 | u64 pkey; | ||
1409 | |||
1410 | pkey = (u64) dd->ipath_pkeys[0] | | ||
1411 | ((u64) dd->ipath_pkeys[1] << 16) | | ||
1412 | ((u64) dd->ipath_pkeys[2] << 32) | | ||
1413 | ((u64) dd->ipath_pkeys[3] << 48); | ||
1414 | ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n", | ||
1415 | (unsigned long long) pkey); | ||
1416 | ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey, | ||
1417 | pkey); | ||
1418 | } | ||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1422 | EXPORT_SYMBOL_GPL(ipath_layer_set_pkeys); | ||
1423 | |||
1424 | /** | ||
1425 | * ipath_layer_get_linkdowndefaultstate - get the default linkdown state | ||
1426 | * @dd: the infinipath device | ||
1427 | * | ||
1428 | * Returns zero if the default is POLL, 1 if the default is SLEEP. | ||
1429 | */ | ||
1430 | int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd) | ||
1431 | { | ||
1432 | return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE); | ||
1433 | } | ||
1434 | |||
1435 | EXPORT_SYMBOL_GPL(ipath_layer_get_linkdowndefaultstate); | ||
1436 | |||
1437 | /** | ||
1438 | * ipath_layer_set_linkdowndefaultstate - set the default linkdown state | ||
1439 | * @dd: the infinipath device | ||
1440 | * @sleep: the new state | ||
1441 | * | ||
1442 | * Note that this will only take effect when the link state changes. | ||
1443 | */ | ||
1444 | int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd, | ||
1445 | int sleep) | ||
1446 | { | ||
1447 | if (sleep) | ||
1448 | dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE; | ||
1449 | else | ||
1450 | dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE; | ||
1451 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
1452 | dd->ipath_ibcctrl); | ||
1453 | return 0; | ||
1454 | } | ||
1455 | |||
1456 | EXPORT_SYMBOL_GPL(ipath_layer_set_linkdowndefaultstate); | ||
1457 | |||
1458 | int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd) | ||
1459 | { | ||
1460 | return (dd->ipath_ibcctrl >> | ||
1461 | INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) & | ||
1462 | INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK; | ||
1463 | } | ||
1464 | |||
1465 | EXPORT_SYMBOL_GPL(ipath_layer_get_phyerrthreshold); | ||
1466 | |||
1467 | /** | ||
1468 | * ipath_layer_set_phyerrthreshold - set the physical error threshold | ||
1469 | * @dd: the infinipath device | ||
1470 | * @n: the new threshold | ||
1471 | * | ||
1472 | * Note that this will only take effect when the link state changes. | ||
1473 | */ | ||
1474 | int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n) | ||
1475 | { | ||
1476 | unsigned v; | ||
1477 | |||
1478 | v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) & | ||
1479 | INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK; | ||
1480 | if (v != n) { | ||
1481 | dd->ipath_ibcctrl &= | ||
1482 | ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK << | ||
1483 | INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT); | ||
1484 | dd->ipath_ibcctrl |= | ||
1485 | (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT; | ||
1486 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
1487 | dd->ipath_ibcctrl); | ||
1488 | } | ||
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | EXPORT_SYMBOL_GPL(ipath_layer_set_phyerrthreshold); | ||
1493 | |||
1494 | int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd) | ||
1495 | { | ||
1496 | return (dd->ipath_ibcctrl >> | ||
1497 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) & | ||
1498 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK; | ||
1499 | } | ||
1500 | |||
1501 | EXPORT_SYMBOL_GPL(ipath_layer_get_overrunthreshold); | ||
1502 | |||
1503 | /** | ||
1504 | * ipath_layer_set_overrunthreshold - set the overrun threshold | ||
1505 | * @dd: the infinipath device | ||
1506 | * @n: the new threshold | ||
1507 | * | ||
1508 | * Note that this will only take effect when the link state changes. | ||
1509 | */ | ||
1510 | int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n) | ||
1511 | { | ||
1512 | unsigned v; | ||
1513 | |||
1514 | v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) & | ||
1515 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK; | ||
1516 | if (v != n) { | ||
1517 | dd->ipath_ibcctrl &= | ||
1518 | ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK << | ||
1519 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT); | ||
1520 | dd->ipath_ibcctrl |= | ||
1521 | (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT; | ||
1522 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
1523 | dd->ipath_ibcctrl); | ||
1524 | } | ||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | EXPORT_SYMBOL_GPL(ipath_layer_set_overrunthreshold); | ||
1529 | |||
1530 | int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name, | ||
1531 | size_t namelen) | ||
1532 | { | ||
1533 | return dd->ipath_f_get_boardname(dd, name, namelen); | ||
1534 | } | ||
1535 | EXPORT_SYMBOL_GPL(ipath_layer_get_boardname); | ||
1536 | |||
1537 | u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd) | ||
1538 | { | ||
1539 | return dd->ipath_rcvhdrentsize; | ||
1540 | } | ||
1541 | EXPORT_SYMBOL_GPL(ipath_layer_get_rcvhdrentsize); | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.h b/drivers/infiniband/hw/ipath/ipath_layer.h index 71485096fcac..3854a4eae684 100644 --- a/drivers/infiniband/hw/ipath/ipath_layer.h +++ b/drivers/infiniband/hw/ipath/ipath_layer.h | |||
@@ -40,73 +40,9 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | struct sk_buff; | 42 | struct sk_buff; |
43 | struct ipath_sge_state; | ||
44 | struct ipath_devdata; | 43 | struct ipath_devdata; |
45 | struct ether_header; | 44 | struct ether_header; |
46 | 45 | ||
47 | struct ipath_layer_counters { | ||
48 | u64 symbol_error_counter; | ||
49 | u64 link_error_recovery_counter; | ||
50 | u64 link_downed_counter; | ||
51 | u64 port_rcv_errors; | ||
52 | u64 port_rcv_remphys_errors; | ||
53 | u64 port_xmit_discards; | ||
54 | u64 port_xmit_data; | ||
55 | u64 port_rcv_data; | ||
56 | u64 port_xmit_packets; | ||
57 | u64 port_rcv_packets; | ||
58 | u32 local_link_integrity_errors; | ||
59 | u32 excessive_buffer_overrun_errors; | ||
60 | }; | ||
61 | |||
62 | /* | ||
63 | * A segment is a linear region of low physical memory. | ||
64 | * XXX Maybe we should use phys addr here and kmap()/kunmap(). | ||
65 | * Used by the verbs layer. | ||
66 | */ | ||
67 | struct ipath_seg { | ||
68 | void *vaddr; | ||
69 | size_t length; | ||
70 | }; | ||
71 | |||
72 | /* The number of ipath_segs that fit in a page. */ | ||
73 | #define IPATH_SEGSZ (PAGE_SIZE / sizeof (struct ipath_seg)) | ||
74 | |||
75 | struct ipath_segarray { | ||
76 | struct ipath_seg segs[IPATH_SEGSZ]; | ||
77 | }; | ||
78 | |||
79 | struct ipath_mregion { | ||
80 | u64 user_base; /* User's address for this region */ | ||
81 | u64 iova; /* IB start address of this region */ | ||
82 | size_t length; | ||
83 | u32 lkey; | ||
84 | u32 offset; /* offset (bytes) to start of region */ | ||
85 | int access_flags; | ||
86 | u32 max_segs; /* number of ipath_segs in all the arrays */ | ||
87 | u32 mapsz; /* size of the map array */ | ||
88 | struct ipath_segarray *map[0]; /* the segments */ | ||
89 | }; | ||
90 | |||
91 | /* | ||
92 | * These keep track of the copy progress within a memory region. | ||
93 | * Used by the verbs layer. | ||
94 | */ | ||
95 | struct ipath_sge { | ||
96 | struct ipath_mregion *mr; | ||
97 | void *vaddr; /* current pointer into the segment */ | ||
98 | u32 sge_length; /* length of the SGE */ | ||
99 | u32 length; /* remaining length of the segment */ | ||
100 | u16 m; /* current index: mr->map[m] */ | ||
101 | u16 n; /* current index: mr->map[m]->segs[n] */ | ||
102 | }; | ||
103 | |||
104 | struct ipath_sge_state { | ||
105 | struct ipath_sge *sg_list; /* next SGE to be used if any */ | ||
106 | struct ipath_sge sge; /* progress state for the current SGE */ | ||
107 | u8 num_sge; | ||
108 | }; | ||
109 | |||
110 | int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *), | 46 | int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *), |
111 | void (*l_remove)(void *), | 47 | void (*l_remove)(void *), |
112 | int (*l_intr)(void *, u32), | 48 | int (*l_intr)(void *, u32), |
@@ -114,62 +50,14 @@ int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *), | |||
114 | struct sk_buff *), | 50 | struct sk_buff *), |
115 | u16 rcv_opcode, | 51 | u16 rcv_opcode, |
116 | int (*l_rcv_lid)(void *, void *)); | 52 | int (*l_rcv_lid)(void *, void *)); |
117 | int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *), | ||
118 | void (*l_remove)(void *arg), | ||
119 | int (*l_piobufavail)(void *arg), | ||
120 | void (*l_rcv)(void *arg, void *rhdr, | ||
121 | void *data, u32 tlen), | ||
122 | void (*l_timer_cb)(void *arg)); | ||
123 | void ipath_layer_unregister(void); | 53 | void ipath_layer_unregister(void); |
124 | void ipath_verbs_unregister(void); | ||
125 | int ipath_layer_open(struct ipath_devdata *, u32 * pktmax); | 54 | int ipath_layer_open(struct ipath_devdata *, u32 * pktmax); |
126 | u16 ipath_layer_get_lid(struct ipath_devdata *dd); | 55 | u16 ipath_layer_get_lid(struct ipath_devdata *dd); |
127 | int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *); | 56 | int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *); |
128 | u16 ipath_layer_get_bcast(struct ipath_devdata *dd); | 57 | u16 ipath_layer_get_bcast(struct ipath_devdata *dd); |
129 | u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd); | ||
130 | int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 state); | ||
131 | int ipath_layer_set_mtu(struct ipath_devdata *, u16); | ||
132 | int ipath_set_lid(struct ipath_devdata *, u32, u8); | ||
133 | int ipath_layer_send_hdr(struct ipath_devdata *dd, | 58 | int ipath_layer_send_hdr(struct ipath_devdata *dd, |
134 | struct ether_header *hdr); | 59 | struct ether_header *hdr); |
135 | int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, | ||
136 | u32 * hdr, u32 len, struct ipath_sge_state *ss); | ||
137 | int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd); | 60 | int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd); |
138 | int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name, | ||
139 | size_t namelen); | ||
140 | int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords, | ||
141 | u64 *rwords, u64 *spkts, u64 *rpkts, | ||
142 | u64 *xmit_wait); | ||
143 | int ipath_layer_get_counters(struct ipath_devdata *dd, | ||
144 | struct ipath_layer_counters *cntrs); | ||
145 | int ipath_layer_want_buffer(struct ipath_devdata *dd); | ||
146 | int ipath_layer_set_guid(struct ipath_devdata *, __be64 guid); | ||
147 | __be64 ipath_layer_get_guid(struct ipath_devdata *); | ||
148 | u32 ipath_layer_get_nguid(struct ipath_devdata *); | ||
149 | u32 ipath_layer_get_majrev(struct ipath_devdata *); | ||
150 | u32 ipath_layer_get_minrev(struct ipath_devdata *); | ||
151 | u32 ipath_layer_get_pcirev(struct ipath_devdata *); | ||
152 | u32 ipath_layer_get_flags(struct ipath_devdata *dd); | ||
153 | struct device *ipath_layer_get_device(struct ipath_devdata *dd); | ||
154 | u16 ipath_layer_get_deviceid(struct ipath_devdata *dd); | ||
155 | u32 ipath_layer_get_vendorid(struct ipath_devdata *); | ||
156 | u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd); | ||
157 | u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd); | ||
158 | int ipath_layer_enable_timer(struct ipath_devdata *dd); | ||
159 | int ipath_layer_disable_timer(struct ipath_devdata *dd); | ||
160 | int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags); | ||
161 | unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd); | ||
162 | unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index); | ||
163 | int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 *pkeys); | ||
164 | int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 *pkeys); | ||
165 | int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd); | ||
166 | int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd, | ||
167 | int sleep); | ||
168 | int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd); | ||
169 | int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n); | ||
170 | int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd); | ||
171 | int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n); | ||
172 | u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd); | ||
173 | 61 | ||
174 | /* ipath_ether interrupt values */ | 62 | /* ipath_ether interrupt values */ |
175 | #define IPATH_LAYER_INT_IF_UP 0x2 | 63 | #define IPATH_LAYER_INT_IF_UP 0x2 |
@@ -178,9 +66,6 @@ u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd); | |||
178 | #define IPATH_LAYER_INT_SEND_CONTINUE 0x10 | 66 | #define IPATH_LAYER_INT_SEND_CONTINUE 0x10 |
179 | #define IPATH_LAYER_INT_BCAST 0x40 | 67 | #define IPATH_LAYER_INT_BCAST 0x40 |
180 | 68 | ||
181 | /* _verbs_layer.l_flags */ | ||
182 | #define IPATH_VERBS_KERNEL_SMA 0x1 | ||
183 | |||
184 | extern unsigned ipath_debug; /* debugging bit mask */ | 69 | extern unsigned ipath_debug; /* debugging bit mask */ |
185 | 70 | ||
186 | #endif /* _IPATH_LAYER_H */ | 71 | #endif /* _IPATH_LAYER_H */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index d3402341b7d0..72d1db89db8f 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c | |||
@@ -101,15 +101,15 @@ static int recv_subn_get_nodeinfo(struct ib_smp *smp, | |||
101 | nip->num_ports = ibdev->phys_port_cnt; | 101 | nip->num_ports = ibdev->phys_port_cnt; |
102 | /* This is already in network order */ | 102 | /* This is already in network order */ |
103 | nip->sys_guid = to_idev(ibdev)->sys_image_guid; | 103 | nip->sys_guid = to_idev(ibdev)->sys_image_guid; |
104 | nip->node_guid = ipath_layer_get_guid(dd); | 104 | nip->node_guid = dd->ipath_guid; |
105 | nip->port_guid = nip->sys_guid; | 105 | nip->port_guid = nip->sys_guid; |
106 | nip->partition_cap = cpu_to_be16(ipath_layer_get_npkeys(dd)); | 106 | nip->partition_cap = cpu_to_be16(ipath_get_npkeys(dd)); |
107 | nip->device_id = cpu_to_be16(ipath_layer_get_deviceid(dd)); | 107 | nip->device_id = cpu_to_be16(dd->ipath_deviceid); |
108 | majrev = ipath_layer_get_majrev(dd); | 108 | majrev = dd->ipath_majrev; |
109 | minrev = ipath_layer_get_minrev(dd); | 109 | minrev = dd->ipath_minrev; |
110 | nip->revision = cpu_to_be32((majrev << 16) | minrev); | 110 | nip->revision = cpu_to_be32((majrev << 16) | minrev); |
111 | nip->local_port_num = port; | 111 | nip->local_port_num = port; |
112 | vendor = ipath_layer_get_vendorid(dd); | 112 | vendor = dd->ipath_vendorid; |
113 | nip->vendor_id[0] = 0; | 113 | nip->vendor_id[0] = 0; |
114 | nip->vendor_id[1] = vendor >> 8; | 114 | nip->vendor_id[1] = vendor >> 8; |
115 | nip->vendor_id[2] = vendor; | 115 | nip->vendor_id[2] = vendor; |
@@ -133,13 +133,89 @@ static int recv_subn_get_guidinfo(struct ib_smp *smp, | |||
133 | */ | 133 | */ |
134 | if (startgx == 0) | 134 | if (startgx == 0) |
135 | /* The first is a copy of the read-only HW GUID. */ | 135 | /* The first is a copy of the read-only HW GUID. */ |
136 | *p = ipath_layer_get_guid(to_idev(ibdev)->dd); | 136 | *p = to_idev(ibdev)->dd->ipath_guid; |
137 | else | 137 | else |
138 | smp->status |= IB_SMP_INVALID_FIELD; | 138 | smp->status |= IB_SMP_INVALID_FIELD; |
139 | 139 | ||
140 | return reply(smp); | 140 | return reply(smp); |
141 | } | 141 | } |
142 | 142 | ||
143 | |||
144 | static int get_overrunthreshold(struct ipath_devdata *dd) | ||
145 | { | ||
146 | return (dd->ipath_ibcctrl >> | ||
147 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) & | ||
148 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * set_overrunthreshold - set the overrun threshold | ||
153 | * @dd: the infinipath device | ||
154 | * @n: the new threshold | ||
155 | * | ||
156 | * Note that this will only take effect when the link state changes. | ||
157 | */ | ||
158 | static int set_overrunthreshold(struct ipath_devdata *dd, unsigned n) | ||
159 | { | ||
160 | unsigned v; | ||
161 | |||
162 | v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) & | ||
163 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK; | ||
164 | if (v != n) { | ||
165 | dd->ipath_ibcctrl &= | ||
166 | ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK << | ||
167 | INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT); | ||
168 | dd->ipath_ibcctrl |= | ||
169 | (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT; | ||
170 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
171 | dd->ipath_ibcctrl); | ||
172 | } | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int get_phyerrthreshold(struct ipath_devdata *dd) | ||
177 | { | ||
178 | return (dd->ipath_ibcctrl >> | ||
179 | INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) & | ||
180 | INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * set_phyerrthreshold - set the physical error threshold | ||
185 | * @dd: the infinipath device | ||
186 | * @n: the new threshold | ||
187 | * | ||
188 | * Note that this will only take effect when the link state changes. | ||
189 | */ | ||
190 | static int set_phyerrthreshold(struct ipath_devdata *dd, unsigned n) | ||
191 | { | ||
192 | unsigned v; | ||
193 | |||
194 | v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) & | ||
195 | INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK; | ||
196 | if (v != n) { | ||
197 | dd->ipath_ibcctrl &= | ||
198 | ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK << | ||
199 | INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT); | ||
200 | dd->ipath_ibcctrl |= | ||
201 | (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT; | ||
202 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
203 | dd->ipath_ibcctrl); | ||
204 | } | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * get_linkdowndefaultstate - get the default linkdown state | ||
210 | * @dd: the infinipath device | ||
211 | * | ||
212 | * Returns zero if the default is POLL, 1 if the default is SLEEP. | ||
213 | */ | ||
214 | static int get_linkdowndefaultstate(struct ipath_devdata *dd) | ||
215 | { | ||
216 | return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE); | ||
217 | } | ||
218 | |||
143 | static int recv_subn_get_portinfo(struct ib_smp *smp, | 219 | static int recv_subn_get_portinfo(struct ib_smp *smp, |
144 | struct ib_device *ibdev, u8 port) | 220 | struct ib_device *ibdev, u8 port) |
145 | { | 221 | { |
@@ -166,7 +242,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, | |||
166 | (dev->mkeyprot_resv_lmc >> 6) == 0) | 242 | (dev->mkeyprot_resv_lmc >> 6) == 0) |
167 | pip->mkey = dev->mkey; | 243 | pip->mkey = dev->mkey; |
168 | pip->gid_prefix = dev->gid_prefix; | 244 | pip->gid_prefix = dev->gid_prefix; |
169 | lid = ipath_layer_get_lid(dev->dd); | 245 | lid = dev->dd->ipath_lid; |
170 | pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE; | 246 | pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE; |
171 | pip->sm_lid = cpu_to_be16(dev->sm_lid); | 247 | pip->sm_lid = cpu_to_be16(dev->sm_lid); |
172 | pip->cap_mask = cpu_to_be32(dev->port_cap_flags); | 248 | pip->cap_mask = cpu_to_be32(dev->port_cap_flags); |
@@ -177,14 +253,14 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, | |||
177 | pip->link_width_supported = 3; /* 1x or 4x */ | 253 | pip->link_width_supported = 3; /* 1x or 4x */ |
178 | pip->link_width_active = 2; /* 4x */ | 254 | pip->link_width_active = 2; /* 4x */ |
179 | pip->linkspeed_portstate = 0x10; /* 2.5Gbps */ | 255 | pip->linkspeed_portstate = 0x10; /* 2.5Gbps */ |
180 | ibcstat = ipath_layer_get_lastibcstat(dev->dd); | 256 | ibcstat = dev->dd->ipath_lastibcstat; |
181 | pip->linkspeed_portstate |= ((ibcstat >> 4) & 0x3) + 1; | 257 | pip->linkspeed_portstate |= ((ibcstat >> 4) & 0x3) + 1; |
182 | pip->portphysstate_linkdown = | 258 | pip->portphysstate_linkdown = |
183 | (ipath_cvt_physportstate[ibcstat & 0xf] << 4) | | 259 | (ipath_cvt_physportstate[ibcstat & 0xf] << 4) | |
184 | (ipath_layer_get_linkdowndefaultstate(dev->dd) ? 1 : 2); | 260 | (get_linkdowndefaultstate(dev->dd) ? 1 : 2); |
185 | pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc; | 261 | pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc; |
186 | pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */ | 262 | pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */ |
187 | switch (ipath_layer_get_ibmtu(dev->dd)) { | 263 | switch (dev->dd->ipath_ibmtu) { |
188 | case 4096: | 264 | case 4096: |
189 | mtu = IB_MTU_4096; | 265 | mtu = IB_MTU_4096; |
190 | break; | 266 | break; |
@@ -217,7 +293,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, | |||
217 | pip->mkey_violations = cpu_to_be16(dev->mkey_violations); | 293 | pip->mkey_violations = cpu_to_be16(dev->mkey_violations); |
218 | /* P_KeyViolations are counted by hardware. */ | 294 | /* P_KeyViolations are counted by hardware. */ |
219 | pip->pkey_violations = | 295 | pip->pkey_violations = |
220 | cpu_to_be16((ipath_layer_get_cr_errpkey(dev->dd) - | 296 | cpu_to_be16((ipath_get_cr_errpkey(dev->dd) - |
221 | dev->z_pkey_violations) & 0xFFFF); | 297 | dev->z_pkey_violations) & 0xFFFF); |
222 | pip->qkey_violations = cpu_to_be16(dev->qkey_violations); | 298 | pip->qkey_violations = cpu_to_be16(dev->qkey_violations); |
223 | /* Only the hardware GUID is supported for now */ | 299 | /* Only the hardware GUID is supported for now */ |
@@ -226,8 +302,8 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, | |||
226 | /* 32.768 usec. response time (guessing) */ | 302 | /* 32.768 usec. response time (guessing) */ |
227 | pip->resv_resptimevalue = 3; | 303 | pip->resv_resptimevalue = 3; |
228 | pip->localphyerrors_overrunerrors = | 304 | pip->localphyerrors_overrunerrors = |
229 | (ipath_layer_get_phyerrthreshold(dev->dd) << 4) | | 305 | (get_phyerrthreshold(dev->dd) << 4) | |
230 | ipath_layer_get_overrunthreshold(dev->dd); | 306 | get_overrunthreshold(dev->dd); |
231 | /* pip->max_credit_hint; */ | 307 | /* pip->max_credit_hint; */ |
232 | /* pip->link_roundtrip_latency[3]; */ | 308 | /* pip->link_roundtrip_latency[3]; */ |
233 | 309 | ||
@@ -237,6 +313,20 @@ bail: | |||
237 | return ret; | 313 | return ret; |
238 | } | 314 | } |
239 | 315 | ||
316 | /** | ||
317 | * get_pkeys - return the PKEY table for port 0 | ||
318 | * @dd: the infinipath device | ||
319 | * @pkeys: the pkey table is placed here | ||
320 | */ | ||
321 | static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys) | ||
322 | { | ||
323 | struct ipath_portdata *pd = dd->ipath_pd[0]; | ||
324 | |||
325 | memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys)); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
240 | static int recv_subn_get_pkeytable(struct ib_smp *smp, | 330 | static int recv_subn_get_pkeytable(struct ib_smp *smp, |
241 | struct ib_device *ibdev) | 331 | struct ib_device *ibdev) |
242 | { | 332 | { |
@@ -249,9 +339,9 @@ static int recv_subn_get_pkeytable(struct ib_smp *smp, | |||
249 | memset(smp->data, 0, sizeof(smp->data)); | 339 | memset(smp->data, 0, sizeof(smp->data)); |
250 | if (startpx == 0) { | 340 | if (startpx == 0) { |
251 | struct ipath_ibdev *dev = to_idev(ibdev); | 341 | struct ipath_ibdev *dev = to_idev(ibdev); |
252 | unsigned i, n = ipath_layer_get_npkeys(dev->dd); | 342 | unsigned i, n = ipath_get_npkeys(dev->dd); |
253 | 343 | ||
254 | ipath_layer_get_pkeys(dev->dd, p); | 344 | get_pkeys(dev->dd, p); |
255 | 345 | ||
256 | for (i = 0; i < n; i++) | 346 | for (i = 0; i < n; i++) |
257 | q[i] = cpu_to_be16(p[i]); | 347 | q[i] = cpu_to_be16(p[i]); |
@@ -269,6 +359,24 @@ static int recv_subn_set_guidinfo(struct ib_smp *smp, | |||
269 | } | 359 | } |
270 | 360 | ||
271 | /** | 361 | /** |
362 | * set_linkdowndefaultstate - set the default linkdown state | ||
363 | * @dd: the infinipath device | ||
364 | * @sleep: the new state | ||
365 | * | ||
366 | * Note that this will only take effect when the link state changes. | ||
367 | */ | ||
368 | static int set_linkdowndefaultstate(struct ipath_devdata *dd, int sleep) | ||
369 | { | ||
370 | if (sleep) | ||
371 | dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE; | ||
372 | else | ||
373 | dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE; | ||
374 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | ||
375 | dd->ipath_ibcctrl); | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /** | ||
272 | * recv_subn_set_portinfo - set port information | 380 | * recv_subn_set_portinfo - set port information |
273 | * @smp: the incoming SM packet | 381 | * @smp: the incoming SM packet |
274 | * @ibdev: the infiniband device | 382 | * @ibdev: the infiniband device |
@@ -290,7 +398,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
290 | u8 state; | 398 | u8 state; |
291 | u16 lstate; | 399 | u16 lstate; |
292 | u32 mtu; | 400 | u32 mtu; |
293 | int ret; | 401 | int ret, ore; |
294 | 402 | ||
295 | if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt) | 403 | if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt) |
296 | goto err; | 404 | goto err; |
@@ -304,7 +412,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
304 | dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period); | 412 | dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period); |
305 | 413 | ||
306 | lid = be16_to_cpu(pip->lid); | 414 | lid = be16_to_cpu(pip->lid); |
307 | if (lid != ipath_layer_get_lid(dev->dd)) { | 415 | if (lid != dev->dd->ipath_lid) { |
308 | /* Must be a valid unicast LID address. */ | 416 | /* Must be a valid unicast LID address. */ |
309 | if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE) | 417 | if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE) |
310 | goto err; | 418 | goto err; |
@@ -342,11 +450,11 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
342 | case 0: /* NOP */ | 450 | case 0: /* NOP */ |
343 | break; | 451 | break; |
344 | case 1: /* SLEEP */ | 452 | case 1: /* SLEEP */ |
345 | if (ipath_layer_set_linkdowndefaultstate(dev->dd, 1)) | 453 | if (set_linkdowndefaultstate(dev->dd, 1)) |
346 | goto err; | 454 | goto err; |
347 | break; | 455 | break; |
348 | case 2: /* POLL */ | 456 | case 2: /* POLL */ |
349 | if (ipath_layer_set_linkdowndefaultstate(dev->dd, 0)) | 457 | if (set_linkdowndefaultstate(dev->dd, 0)) |
350 | goto err; | 458 | goto err; |
351 | break; | 459 | break; |
352 | default: | 460 | default: |
@@ -376,7 +484,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
376 | /* XXX We have already partially updated our state! */ | 484 | /* XXX We have already partially updated our state! */ |
377 | goto err; | 485 | goto err; |
378 | } | 486 | } |
379 | ipath_layer_set_mtu(dev->dd, mtu); | 487 | ipath_set_mtu(dev->dd, mtu); |
380 | 488 | ||
381 | dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF; | 489 | dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF; |
382 | 490 | ||
@@ -392,20 +500,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
392 | * later. | 500 | * later. |
393 | */ | 501 | */ |
394 | if (pip->pkey_violations == 0) | 502 | if (pip->pkey_violations == 0) |
395 | dev->z_pkey_violations = | 503 | dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd); |
396 | ipath_layer_get_cr_errpkey(dev->dd); | ||
397 | 504 | ||
398 | if (pip->qkey_violations == 0) | 505 | if (pip->qkey_violations == 0) |
399 | dev->qkey_violations = 0; | 506 | dev->qkey_violations = 0; |
400 | 507 | ||
401 | if (ipath_layer_set_phyerrthreshold( | 508 | ore = pip->localphyerrors_overrunerrors; |
402 | dev->dd, | 509 | if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF)) |
403 | (pip->localphyerrors_overrunerrors >> 4) & 0xF)) | ||
404 | goto err; | 510 | goto err; |
405 | 511 | ||
406 | if (ipath_layer_set_overrunthreshold( | 512 | if (set_overrunthreshold(dev->dd, (ore & 0xF))) |
407 | dev->dd, | ||
408 | (pip->localphyerrors_overrunerrors & 0xF))) | ||
409 | goto err; | 513 | goto err; |
410 | 514 | ||
411 | dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F; | 515 | dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F; |
@@ -423,7 +527,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
423 | * is down or is being set to down. | 527 | * is down or is being set to down. |
424 | */ | 528 | */ |
425 | state = pip->linkspeed_portstate & 0xF; | 529 | state = pip->linkspeed_portstate & 0xF; |
426 | flags = ipath_layer_get_flags(dev->dd); | 530 | flags = dev->dd->ipath_flags; |
427 | lstate = (pip->portphysstate_linkdown >> 4) & 0xF; | 531 | lstate = (pip->portphysstate_linkdown >> 4) & 0xF; |
428 | if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) | 532 | if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) |
429 | goto err; | 533 | goto err; |
@@ -439,7 +543,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
439 | /* FALLTHROUGH */ | 543 | /* FALLTHROUGH */ |
440 | case IB_PORT_DOWN: | 544 | case IB_PORT_DOWN: |
441 | if (lstate == 0) | 545 | if (lstate == 0) |
442 | if (ipath_layer_get_linkdowndefaultstate(dev->dd)) | 546 | if (get_linkdowndefaultstate(dev->dd)) |
443 | lstate = IPATH_IB_LINKDOWN_SLEEP; | 547 | lstate = IPATH_IB_LINKDOWN_SLEEP; |
444 | else | 548 | else |
445 | lstate = IPATH_IB_LINKDOWN; | 549 | lstate = IPATH_IB_LINKDOWN; |
@@ -451,7 +555,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
451 | lstate = IPATH_IB_LINKDOWN_DISABLE; | 555 | lstate = IPATH_IB_LINKDOWN_DISABLE; |
452 | else | 556 | else |
453 | goto err; | 557 | goto err; |
454 | ipath_layer_set_linkstate(dev->dd, lstate); | 558 | ipath_set_linkstate(dev->dd, lstate); |
455 | if (flags & IPATH_LINKACTIVE) { | 559 | if (flags & IPATH_LINKACTIVE) { |
456 | event.event = IB_EVENT_PORT_ERR; | 560 | event.event = IB_EVENT_PORT_ERR; |
457 | ib_dispatch_event(&event); | 561 | ib_dispatch_event(&event); |
@@ -460,7 +564,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
460 | case IB_PORT_ARMED: | 564 | case IB_PORT_ARMED: |
461 | if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) | 565 | if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) |
462 | break; | 566 | break; |
463 | ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKARM); | 567 | ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM); |
464 | if (flags & IPATH_LINKACTIVE) { | 568 | if (flags & IPATH_LINKACTIVE) { |
465 | event.event = IB_EVENT_PORT_ERR; | 569 | event.event = IB_EVENT_PORT_ERR; |
466 | ib_dispatch_event(&event); | 570 | ib_dispatch_event(&event); |
@@ -469,7 +573,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
469 | case IB_PORT_ACTIVE: | 573 | case IB_PORT_ACTIVE: |
470 | if (!(flags & IPATH_LINKARMED)) | 574 | if (!(flags & IPATH_LINKARMED)) |
471 | break; | 575 | break; |
472 | ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE); | 576 | ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE); |
473 | event.event = IB_EVENT_PORT_ACTIVE; | 577 | event.event = IB_EVENT_PORT_ACTIVE; |
474 | ib_dispatch_event(&event); | 578 | ib_dispatch_event(&event); |
475 | break; | 579 | break; |
@@ -493,6 +597,152 @@ done: | |||
493 | return ret; | 597 | return ret; |
494 | } | 598 | } |
495 | 599 | ||
600 | /** | ||
601 | * rm_pkey - decrecment the reference count for the given PKEY | ||
602 | * @dd: the infinipath device | ||
603 | * @key: the PKEY index | ||
604 | * | ||
605 | * Return true if this was the last reference and the hardware table entry | ||
606 | * needs to be changed. | ||
607 | */ | ||
608 | static int rm_pkey(struct ipath_devdata *dd, u16 key) | ||
609 | { | ||
610 | int i; | ||
611 | int ret; | ||
612 | |||
613 | for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { | ||
614 | if (dd->ipath_pkeys[i] != key) | ||
615 | continue; | ||
616 | if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) { | ||
617 | dd->ipath_pkeys[i] = 0; | ||
618 | ret = 1; | ||
619 | goto bail; | ||
620 | } | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | ret = 0; | ||
625 | |||
626 | bail: | ||
627 | return ret; | ||
628 | } | ||
629 | |||
630 | /** | ||
631 | * add_pkey - add the given PKEY to the hardware table | ||
632 | * @dd: the infinipath device | ||
633 | * @key: the PKEY | ||
634 | * | ||
635 | * Return an error code if unable to add the entry, zero if no change, | ||
636 | * or 1 if the hardware PKEY register needs to be updated. | ||
637 | */ | ||
638 | static int add_pkey(struct ipath_devdata *dd, u16 key) | ||
639 | { | ||
640 | int i; | ||
641 | u16 lkey = key & 0x7FFF; | ||
642 | int any = 0; | ||
643 | int ret; | ||
644 | |||
645 | if (lkey == 0x7FFF) { | ||
646 | ret = 0; | ||
647 | goto bail; | ||
648 | } | ||
649 | |||
650 | /* Look for an empty slot or a matching PKEY. */ | ||
651 | for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { | ||
652 | if (!dd->ipath_pkeys[i]) { | ||
653 | any++; | ||
654 | continue; | ||
655 | } | ||
656 | /* If it matches exactly, try to increment the ref count */ | ||
657 | if (dd->ipath_pkeys[i] == key) { | ||
658 | if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) { | ||
659 | ret = 0; | ||
660 | goto bail; | ||
661 | } | ||
662 | /* Lost the race. Look for an empty slot below. */ | ||
663 | atomic_dec(&dd->ipath_pkeyrefs[i]); | ||
664 | any++; | ||
665 | } | ||
666 | /* | ||
667 | * It makes no sense to have both the limited and unlimited | ||
668 | * PKEY set at the same time since the unlimited one will | ||
669 | * disable the limited one. | ||
670 | */ | ||
671 | if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) { | ||
672 | ret = -EEXIST; | ||
673 | goto bail; | ||
674 | } | ||
675 | } | ||
676 | if (!any) { | ||
677 | ret = -EBUSY; | ||
678 | goto bail; | ||
679 | } | ||
680 | for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { | ||
681 | if (!dd->ipath_pkeys[i] && | ||
682 | atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) { | ||
683 | /* for ipathstats, etc. */ | ||
684 | ipath_stats.sps_pkeys[i] = lkey; | ||
685 | dd->ipath_pkeys[i] = key; | ||
686 | ret = 1; | ||
687 | goto bail; | ||
688 | } | ||
689 | } | ||
690 | ret = -EBUSY; | ||
691 | |||
692 | bail: | ||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | /** | ||
697 | * set_pkeys - set the PKEY table for port 0 | ||
698 | * @dd: the infinipath device | ||
699 | * @pkeys: the PKEY table | ||
700 | */ | ||
701 | static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys) | ||
702 | { | ||
703 | struct ipath_portdata *pd; | ||
704 | int i; | ||
705 | int changed = 0; | ||
706 | |||
707 | pd = dd->ipath_pd[0]; | ||
708 | |||
709 | for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { | ||
710 | u16 key = pkeys[i]; | ||
711 | u16 okey = pd->port_pkeys[i]; | ||
712 | |||
713 | if (key == okey) | ||
714 | continue; | ||
715 | /* | ||
716 | * The value of this PKEY table entry is changing. | ||
717 | * Remove the old entry in the hardware's array of PKEYs. | ||
718 | */ | ||
719 | if (okey & 0x7FFF) | ||
720 | changed |= rm_pkey(dd, okey); | ||
721 | if (key & 0x7FFF) { | ||
722 | int ret = add_pkey(dd, key); | ||
723 | |||
724 | if (ret < 0) | ||
725 | key = 0; | ||
726 | else | ||
727 | changed |= ret; | ||
728 | } | ||
729 | pd->port_pkeys[i] = key; | ||
730 | } | ||
731 | if (changed) { | ||
732 | u64 pkey; | ||
733 | |||
734 | pkey = (u64) dd->ipath_pkeys[0] | | ||
735 | ((u64) dd->ipath_pkeys[1] << 16) | | ||
736 | ((u64) dd->ipath_pkeys[2] << 32) | | ||
737 | ((u64) dd->ipath_pkeys[3] << 48); | ||
738 | ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n", | ||
739 | (unsigned long long) pkey); | ||
740 | ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey, | ||
741 | pkey); | ||
742 | } | ||
743 | return 0; | ||
744 | } | ||
745 | |||
496 | static int recv_subn_set_pkeytable(struct ib_smp *smp, | 746 | static int recv_subn_set_pkeytable(struct ib_smp *smp, |
497 | struct ib_device *ibdev) | 747 | struct ib_device *ibdev) |
498 | { | 748 | { |
@@ -500,13 +750,12 @@ static int recv_subn_set_pkeytable(struct ib_smp *smp, | |||
500 | __be16 *p = (__be16 *) smp->data; | 750 | __be16 *p = (__be16 *) smp->data; |
501 | u16 *q = (u16 *) smp->data; | 751 | u16 *q = (u16 *) smp->data; |
502 | struct ipath_ibdev *dev = to_idev(ibdev); | 752 | struct ipath_ibdev *dev = to_idev(ibdev); |
503 | unsigned i, n = ipath_layer_get_npkeys(dev->dd); | 753 | unsigned i, n = ipath_get_npkeys(dev->dd); |
504 | 754 | ||
505 | for (i = 0; i < n; i++) | 755 | for (i = 0; i < n; i++) |
506 | q[i] = be16_to_cpu(p[i]); | 756 | q[i] = be16_to_cpu(p[i]); |
507 | 757 | ||
508 | if (startpx != 0 || | 758 | if (startpx != 0 || set_pkeys(dev->dd, q) != 0) |
509 | ipath_layer_set_pkeys(dev->dd, q) != 0) | ||
510 | smp->status |= IB_SMP_INVALID_FIELD; | 759 | smp->status |= IB_SMP_INVALID_FIELD; |
511 | 760 | ||
512 | return recv_subn_get_pkeytable(smp, ibdev); | 761 | return recv_subn_get_pkeytable(smp, ibdev); |
@@ -844,10 +1093,10 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp, | |||
844 | struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) | 1093 | struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) |
845 | pmp->data; | 1094 | pmp->data; |
846 | struct ipath_ibdev *dev = to_idev(ibdev); | 1095 | struct ipath_ibdev *dev = to_idev(ibdev); |
847 | struct ipath_layer_counters cntrs; | 1096 | struct ipath_verbs_counters cntrs; |
848 | u8 port_select = p->port_select; | 1097 | u8 port_select = p->port_select; |
849 | 1098 | ||
850 | ipath_layer_get_counters(dev->dd, &cntrs); | 1099 | ipath_get_counters(dev->dd, &cntrs); |
851 | 1100 | ||
852 | /* Adjust counters for any resets done. */ | 1101 | /* Adjust counters for any resets done. */ |
853 | cntrs.symbol_error_counter -= dev->z_symbol_error_counter; | 1102 | cntrs.symbol_error_counter -= dev->z_symbol_error_counter; |
@@ -944,8 +1193,8 @@ static int recv_pma_get_portcounters_ext(struct ib_perf *pmp, | |||
944 | u64 swords, rwords, spkts, rpkts, xwait; | 1193 | u64 swords, rwords, spkts, rpkts, xwait; |
945 | u8 port_select = p->port_select; | 1194 | u8 port_select = p->port_select; |
946 | 1195 | ||
947 | ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts, | 1196 | ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts, |
948 | &rpkts, &xwait); | 1197 | &rpkts, &xwait); |
949 | 1198 | ||
950 | /* Adjust counters for any resets done. */ | 1199 | /* Adjust counters for any resets done. */ |
951 | swords -= dev->z_port_xmit_data; | 1200 | swords -= dev->z_port_xmit_data; |
@@ -978,13 +1227,13 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp, | |||
978 | struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) | 1227 | struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) |
979 | pmp->data; | 1228 | pmp->data; |
980 | struct ipath_ibdev *dev = to_idev(ibdev); | 1229 | struct ipath_ibdev *dev = to_idev(ibdev); |
981 | struct ipath_layer_counters cntrs; | 1230 | struct ipath_verbs_counters cntrs; |
982 | 1231 | ||
983 | /* | 1232 | /* |
984 | * Since the HW doesn't support clearing counters, we save the | 1233 | * Since the HW doesn't support clearing counters, we save the |
985 | * current count and subtract it from future responses. | 1234 | * current count and subtract it from future responses. |
986 | */ | 1235 | */ |
987 | ipath_layer_get_counters(dev->dd, &cntrs); | 1236 | ipath_get_counters(dev->dd, &cntrs); |
988 | 1237 | ||
989 | if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR) | 1238 | if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR) |
990 | dev->z_symbol_error_counter = cntrs.symbol_error_counter; | 1239 | dev->z_symbol_error_counter = cntrs.symbol_error_counter; |
@@ -1041,8 +1290,8 @@ static int recv_pma_set_portcounters_ext(struct ib_perf *pmp, | |||
1041 | struct ipath_ibdev *dev = to_idev(ibdev); | 1290 | struct ipath_ibdev *dev = to_idev(ibdev); |
1042 | u64 swords, rwords, spkts, rpkts, xwait; | 1291 | u64 swords, rwords, spkts, rpkts, xwait; |
1043 | 1292 | ||
1044 | ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts, | 1293 | ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts, |
1045 | &rpkts, &xwait); | 1294 | &rpkts, &xwait); |
1046 | 1295 | ||
1047 | if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA) | 1296 | if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA) |
1048 | dev->z_port_xmit_data = swords; | 1297 | dev->z_port_xmit_data = swords; |
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c new file mode 100644 index 000000000000..11b7378ff214 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_mmap.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 QLogic, Inc. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | */ | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/vmalloc.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | |||
40 | #include "ipath_verbs.h" | ||
41 | |||
42 | /** | ||
43 | * ipath_release_mmap_info - free mmap info structure | ||
44 | * @ref: a pointer to the kref within struct ipath_mmap_info | ||
45 | */ | ||
46 | void ipath_release_mmap_info(struct kref *ref) | ||
47 | { | ||
48 | struct ipath_mmap_info *ip = | ||
49 | container_of(ref, struct ipath_mmap_info, ref); | ||
50 | |||
51 | vfree(ip->obj); | ||
52 | kfree(ip); | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * open and close keep track of how many times the CQ is mapped, | ||
57 | * to avoid releasing it. | ||
58 | */ | ||
59 | static void ipath_vma_open(struct vm_area_struct *vma) | ||
60 | { | ||
61 | struct ipath_mmap_info *ip = vma->vm_private_data; | ||
62 | |||
63 | kref_get(&ip->ref); | ||
64 | ip->mmap_cnt++; | ||
65 | } | ||
66 | |||
67 | static void ipath_vma_close(struct vm_area_struct *vma) | ||
68 | { | ||
69 | struct ipath_mmap_info *ip = vma->vm_private_data; | ||
70 | |||
71 | ip->mmap_cnt--; | ||
72 | kref_put(&ip->ref, ipath_release_mmap_info); | ||
73 | } | ||
74 | |||
75 | static struct vm_operations_struct ipath_vm_ops = { | ||
76 | .open = ipath_vma_open, | ||
77 | .close = ipath_vma_close, | ||
78 | }; | ||
79 | |||
80 | /** | ||
81 | * ipath_mmap - create a new mmap region | ||
82 | * @context: the IB user context of the process making the mmap() call | ||
83 | * @vma: the VMA to be initialized | ||
84 | * Return zero if the mmap is OK. Otherwise, return an errno. | ||
85 | */ | ||
86 | int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) | ||
87 | { | ||
88 | struct ipath_ibdev *dev = to_idev(context->device); | ||
89 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | ||
90 | unsigned long size = vma->vm_end - vma->vm_start; | ||
91 | struct ipath_mmap_info *ip, **pp; | ||
92 | int ret = -EINVAL; | ||
93 | |||
94 | /* | ||
95 | * Search the device's list of objects waiting for a mmap call. | ||
96 | * Normally, this list is very short since a call to create a | ||
97 | * CQ, QP, or SRQ is soon followed by a call to mmap(). | ||
98 | */ | ||
99 | spin_lock_irq(&dev->pending_lock); | ||
100 | for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) { | ||
101 | /* Only the creator is allowed to mmap the object */ | ||
102 | if (context != ip->context || (void *) offset != ip->obj) | ||
103 | continue; | ||
104 | /* Don't allow a mmap larger than the object. */ | ||
105 | if (size > ip->size) | ||
106 | break; | ||
107 | |||
108 | *pp = ip->next; | ||
109 | spin_unlock_irq(&dev->pending_lock); | ||
110 | |||
111 | ret = remap_vmalloc_range(vma, ip->obj, 0); | ||
112 | if (ret) | ||
113 | goto done; | ||
114 | vma->vm_ops = &ipath_vm_ops; | ||
115 | vma->vm_private_data = ip; | ||
116 | ipath_vma_open(vma); | ||
117 | goto done; | ||
118 | } | ||
119 | spin_unlock_irq(&dev->pending_lock); | ||
120 | done: | ||
121 | return ret; | ||
122 | } | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c index 4ac31a5da330..b36f6fb3e37a 100644 --- a/drivers/infiniband/hw/ipath/ipath_mr.c +++ b/drivers/infiniband/hw/ipath/ipath_mr.c | |||
@@ -36,6 +36,18 @@ | |||
36 | 36 | ||
37 | #include "ipath_verbs.h" | 37 | #include "ipath_verbs.h" |
38 | 38 | ||
39 | /* Fast memory region */ | ||
40 | struct ipath_fmr { | ||
41 | struct ib_fmr ibfmr; | ||
42 | u8 page_shift; | ||
43 | struct ipath_mregion mr; /* must be last */ | ||
44 | }; | ||
45 | |||
46 | static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr) | ||
47 | { | ||
48 | return container_of(ibfmr, struct ipath_fmr, ibfmr); | ||
49 | } | ||
50 | |||
39 | /** | 51 | /** |
40 | * ipath_get_dma_mr - get a DMA memory region | 52 | * ipath_get_dma_mr - get a DMA memory region |
41 | * @pd: protection domain for this memory region | 53 | * @pd: protection domain for this memory region |
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 83e557be591e..224b0f40767f 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c | |||
@@ -35,7 +35,7 @@ | |||
35 | #include <linux/vmalloc.h> | 35 | #include <linux/vmalloc.h> |
36 | 36 | ||
37 | #include "ipath_verbs.h" | 37 | #include "ipath_verbs.h" |
38 | #include "ipath_common.h" | 38 | #include "ipath_kernel.h" |
39 | 39 | ||
40 | #define BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE) | 40 | #define BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE) |
41 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) | 41 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) |
@@ -44,19 +44,6 @@ | |||
44 | #define find_next_offset(map, off) find_next_zero_bit((map)->page, \ | 44 | #define find_next_offset(map, off) find_next_zero_bit((map)->page, \ |
45 | BITS_PER_PAGE, off) | 45 | BITS_PER_PAGE, off) |
46 | 46 | ||
47 | #define TRANS_INVALID 0 | ||
48 | #define TRANS_ANY2RST 1 | ||
49 | #define TRANS_RST2INIT 2 | ||
50 | #define TRANS_INIT2INIT 3 | ||
51 | #define TRANS_INIT2RTR 4 | ||
52 | #define TRANS_RTR2RTS 5 | ||
53 | #define TRANS_RTS2RTS 6 | ||
54 | #define TRANS_SQERR2RTS 7 | ||
55 | #define TRANS_ANY2ERR 8 | ||
56 | #define TRANS_RTS2SQD 9 /* XXX Wait for expected ACKs & signal event */ | ||
57 | #define TRANS_SQD2SQD 10 /* error if not drained & parameter change */ | ||
58 | #define TRANS_SQD2RTS 11 /* error if not drained */ | ||
59 | |||
60 | /* | 47 | /* |
61 | * Convert the AETH credit code into the number of credits. | 48 | * Convert the AETH credit code into the number of credits. |
62 | */ | 49 | */ |
@@ -287,7 +274,7 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt) | |||
287 | free_qpn(qpt, qp->ibqp.qp_num); | 274 | free_qpn(qpt, qp->ibqp.qp_num); |
288 | if (!atomic_dec_and_test(&qp->refcount) || | 275 | if (!atomic_dec_and_test(&qp->refcount) || |
289 | !ipath_destroy_qp(&qp->ibqp)) | 276 | !ipath_destroy_qp(&qp->ibqp)) |
290 | _VERBS_INFO("QP memory leak!\n"); | 277 | ipath_dbg(KERN_INFO "QP memory leak!\n"); |
291 | qp = nqp; | 278 | qp = nqp; |
292 | } | 279 | } |
293 | } | 280 | } |
@@ -355,8 +342,10 @@ static void ipath_reset_qp(struct ipath_qp *qp) | |||
355 | qp->s_last = 0; | 342 | qp->s_last = 0; |
356 | qp->s_ssn = 1; | 343 | qp->s_ssn = 1; |
357 | qp->s_lsn = 0; | 344 | qp->s_lsn = 0; |
358 | qp->r_rq.head = 0; | 345 | if (qp->r_rq.wq) { |
359 | qp->r_rq.tail = 0; | 346 | qp->r_rq.wq->head = 0; |
347 | qp->r_rq.wq->tail = 0; | ||
348 | } | ||
360 | qp->r_reuse_sge = 0; | 349 | qp->r_reuse_sge = 0; |
361 | } | 350 | } |
362 | 351 | ||
@@ -373,8 +362,8 @@ void ipath_error_qp(struct ipath_qp *qp) | |||
373 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); | 362 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); |
374 | struct ib_wc wc; | 363 | struct ib_wc wc; |
375 | 364 | ||
376 | _VERBS_INFO("QP%d/%d in error state\n", | 365 | ipath_dbg(KERN_INFO "QP%d/%d in error state\n", |
377 | qp->ibqp.qp_num, qp->remote_qpn); | 366 | qp->ibqp.qp_num, qp->remote_qpn); |
378 | 367 | ||
379 | spin_lock(&dev->pending_lock); | 368 | spin_lock(&dev->pending_lock); |
380 | /* XXX What if its already removed by the timeout code? */ | 369 | /* XXX What if its already removed by the timeout code? */ |
@@ -410,15 +399,32 @@ void ipath_error_qp(struct ipath_qp *qp) | |||
410 | qp->s_hdrwords = 0; | 399 | qp->s_hdrwords = 0; |
411 | qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; | 400 | qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; |
412 | 401 | ||
413 | wc.opcode = IB_WC_RECV; | 402 | if (qp->r_rq.wq) { |
414 | spin_lock(&qp->r_rq.lock); | 403 | struct ipath_rwq *wq; |
415 | while (qp->r_rq.tail != qp->r_rq.head) { | 404 | u32 head; |
416 | wc.wr_id = get_rwqe_ptr(&qp->r_rq, qp->r_rq.tail)->wr_id; | 405 | u32 tail; |
417 | if (++qp->r_rq.tail >= qp->r_rq.size) | 406 | |
418 | qp->r_rq.tail = 0; | 407 | spin_lock(&qp->r_rq.lock); |
419 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); | 408 | |
409 | /* sanity check pointers before trusting them */ | ||
410 | wq = qp->r_rq.wq; | ||
411 | head = wq->head; | ||
412 | if (head >= qp->r_rq.size) | ||
413 | head = 0; | ||
414 | tail = wq->tail; | ||
415 | if (tail >= qp->r_rq.size) | ||
416 | tail = 0; | ||
417 | wc.opcode = IB_WC_RECV; | ||
418 | while (tail != head) { | ||
419 | wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id; | ||
420 | if (++tail >= qp->r_rq.size) | ||
421 | tail = 0; | ||
422 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); | ||
423 | } | ||
424 | wq->tail = tail; | ||
425 | |||
426 | spin_unlock(&qp->r_rq.lock); | ||
420 | } | 427 | } |
421 | spin_unlock(&qp->r_rq.lock); | ||
422 | } | 428 | } |
423 | 429 | ||
424 | /** | 430 | /** |
@@ -426,11 +432,12 @@ void ipath_error_qp(struct ipath_qp *qp) | |||
426 | * @ibqp: the queue pair who's attributes we're modifying | 432 | * @ibqp: the queue pair who's attributes we're modifying |
427 | * @attr: the new attributes | 433 | * @attr: the new attributes |
428 | * @attr_mask: the mask of attributes to modify | 434 | * @attr_mask: the mask of attributes to modify |
435 | * @udata: user data for ipathverbs.so | ||
429 | * | 436 | * |
430 | * Returns 0 on success, otherwise returns an errno. | 437 | * Returns 0 on success, otherwise returns an errno. |
431 | */ | 438 | */ |
432 | int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | 439 | int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, |
433 | int attr_mask) | 440 | int attr_mask, struct ib_udata *udata) |
434 | { | 441 | { |
435 | struct ipath_ibdev *dev = to_idev(ibqp->device); | 442 | struct ipath_ibdev *dev = to_idev(ibqp->device); |
436 | struct ipath_qp *qp = to_iqp(ibqp); | 443 | struct ipath_qp *qp = to_iqp(ibqp); |
@@ -448,19 +455,46 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
448 | attr_mask)) | 455 | attr_mask)) |
449 | goto inval; | 456 | goto inval; |
450 | 457 | ||
451 | if (attr_mask & IB_QP_AV) | 458 | if (attr_mask & IB_QP_AV) { |
452 | if (attr->ah_attr.dlid == 0 || | 459 | if (attr->ah_attr.dlid == 0 || |
453 | attr->ah_attr.dlid >= IPATH_MULTICAST_LID_BASE) | 460 | attr->ah_attr.dlid >= IPATH_MULTICAST_LID_BASE) |
454 | goto inval; | 461 | goto inval; |
455 | 462 | ||
463 | if ((attr->ah_attr.ah_flags & IB_AH_GRH) && | ||
464 | (attr->ah_attr.grh.sgid_index > 1)) | ||
465 | goto inval; | ||
466 | } | ||
467 | |||
456 | if (attr_mask & IB_QP_PKEY_INDEX) | 468 | if (attr_mask & IB_QP_PKEY_INDEX) |
457 | if (attr->pkey_index >= ipath_layer_get_npkeys(dev->dd)) | 469 | if (attr->pkey_index >= ipath_get_npkeys(dev->dd)) |
458 | goto inval; | 470 | goto inval; |
459 | 471 | ||
460 | if (attr_mask & IB_QP_MIN_RNR_TIMER) | 472 | if (attr_mask & IB_QP_MIN_RNR_TIMER) |
461 | if (attr->min_rnr_timer > 31) | 473 | if (attr->min_rnr_timer > 31) |
462 | goto inval; | 474 | goto inval; |
463 | 475 | ||
476 | if (attr_mask & IB_QP_PORT) | ||
477 | if (attr->port_num == 0 || | ||
478 | attr->port_num > ibqp->device->phys_port_cnt) | ||
479 | goto inval; | ||
480 | |||
481 | if (attr_mask & IB_QP_PATH_MTU) | ||
482 | if (attr->path_mtu > IB_MTU_4096) | ||
483 | goto inval; | ||
484 | |||
485 | if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) | ||
486 | if (attr->max_dest_rd_atomic > 1) | ||
487 | goto inval; | ||
488 | |||
489 | if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) | ||
490 | if (attr->max_rd_atomic > 1) | ||
491 | goto inval; | ||
492 | |||
493 | if (attr_mask & IB_QP_PATH_MIG_STATE) | ||
494 | if (attr->path_mig_state != IB_MIG_MIGRATED && | ||
495 | attr->path_mig_state != IB_MIG_REARM) | ||
496 | goto inval; | ||
497 | |||
464 | switch (new_state) { | 498 | switch (new_state) { |
465 | case IB_QPS_RESET: | 499 | case IB_QPS_RESET: |
466 | ipath_reset_qp(qp); | 500 | ipath_reset_qp(qp); |
@@ -511,6 +545,9 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
511 | if (attr_mask & IB_QP_MIN_RNR_TIMER) | 545 | if (attr_mask & IB_QP_MIN_RNR_TIMER) |
512 | qp->r_min_rnr_timer = attr->min_rnr_timer; | 546 | qp->r_min_rnr_timer = attr->min_rnr_timer; |
513 | 547 | ||
548 | if (attr_mask & IB_QP_TIMEOUT) | ||
549 | qp->timeout = attr->timeout; | ||
550 | |||
514 | if (attr_mask & IB_QP_QKEY) | 551 | if (attr_mask & IB_QP_QKEY) |
515 | qp->qkey = attr->qkey; | 552 | qp->qkey = attr->qkey; |
516 | 553 | ||
@@ -543,7 +580,7 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
543 | attr->dest_qp_num = qp->remote_qpn; | 580 | attr->dest_qp_num = qp->remote_qpn; |
544 | attr->qp_access_flags = qp->qp_access_flags; | 581 | attr->qp_access_flags = qp->qp_access_flags; |
545 | attr->cap.max_send_wr = qp->s_size - 1; | 582 | attr->cap.max_send_wr = qp->s_size - 1; |
546 | attr->cap.max_recv_wr = qp->r_rq.size - 1; | 583 | attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1; |
547 | attr->cap.max_send_sge = qp->s_max_sge; | 584 | attr->cap.max_send_sge = qp->s_max_sge; |
548 | attr->cap.max_recv_sge = qp->r_rq.max_sge; | 585 | attr->cap.max_recv_sge = qp->r_rq.max_sge; |
549 | attr->cap.max_inline_data = 0; | 586 | attr->cap.max_inline_data = 0; |
@@ -557,7 +594,7 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
557 | attr->max_dest_rd_atomic = 1; | 594 | attr->max_dest_rd_atomic = 1; |
558 | attr->min_rnr_timer = qp->r_min_rnr_timer; | 595 | attr->min_rnr_timer = qp->r_min_rnr_timer; |
559 | attr->port_num = 1; | 596 | attr->port_num = 1; |
560 | attr->timeout = 0; | 597 | attr->timeout = qp->timeout; |
561 | attr->retry_cnt = qp->s_retry_cnt; | 598 | attr->retry_cnt = qp->s_retry_cnt; |
562 | attr->rnr_retry = qp->s_rnr_retry; | 599 | attr->rnr_retry = qp->s_rnr_retry; |
563 | attr->alt_port_num = 0; | 600 | attr->alt_port_num = 0; |
@@ -569,9 +606,10 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
569 | init_attr->recv_cq = qp->ibqp.recv_cq; | 606 | init_attr->recv_cq = qp->ibqp.recv_cq; |
570 | init_attr->srq = qp->ibqp.srq; | 607 | init_attr->srq = qp->ibqp.srq; |
571 | init_attr->cap = attr->cap; | 608 | init_attr->cap = attr->cap; |
572 | init_attr->sq_sig_type = | 609 | if (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR)) |
573 | (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR)) | 610 | init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; |
574 | ? IB_SIGNAL_REQ_WR : 0; | 611 | else |
612 | init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; | ||
575 | init_attr->qp_type = qp->ibqp.qp_type; | 613 | init_attr->qp_type = qp->ibqp.qp_type; |
576 | init_attr->port_num = 1; | 614 | init_attr->port_num = 1; |
577 | return 0; | 615 | return 0; |
@@ -596,13 +634,23 @@ __be32 ipath_compute_aeth(struct ipath_qp *qp) | |||
596 | } else { | 634 | } else { |
597 | u32 min, max, x; | 635 | u32 min, max, x; |
598 | u32 credits; | 636 | u32 credits; |
599 | 637 | struct ipath_rwq *wq = qp->r_rq.wq; | |
638 | u32 head; | ||
639 | u32 tail; | ||
640 | |||
641 | /* sanity check pointers before trusting them */ | ||
642 | head = wq->head; | ||
643 | if (head >= qp->r_rq.size) | ||
644 | head = 0; | ||
645 | tail = wq->tail; | ||
646 | if (tail >= qp->r_rq.size) | ||
647 | tail = 0; | ||
600 | /* | 648 | /* |
601 | * Compute the number of credits available (RWQEs). | 649 | * Compute the number of credits available (RWQEs). |
602 | * XXX Not holding the r_rq.lock here so there is a small | 650 | * XXX Not holding the r_rq.lock here so there is a small |
603 | * chance that the pair of reads are not atomic. | 651 | * chance that the pair of reads are not atomic. |
604 | */ | 652 | */ |
605 | credits = qp->r_rq.head - qp->r_rq.tail; | 653 | credits = head - tail; |
606 | if ((int)credits < 0) | 654 | if ((int)credits < 0) |
607 | credits += qp->r_rq.size; | 655 | credits += qp->r_rq.size; |
608 | /* | 656 | /* |
@@ -679,27 +727,37 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, | |||
679 | case IB_QPT_UD: | 727 | case IB_QPT_UD: |
680 | case IB_QPT_SMI: | 728 | case IB_QPT_SMI: |
681 | case IB_QPT_GSI: | 729 | case IB_QPT_GSI: |
682 | qp = kmalloc(sizeof(*qp), GFP_KERNEL); | 730 | sz = sizeof(*qp); |
731 | if (init_attr->srq) { | ||
732 | struct ipath_srq *srq = to_isrq(init_attr->srq); | ||
733 | |||
734 | sz += sizeof(*qp->r_sg_list) * | ||
735 | srq->rq.max_sge; | ||
736 | } else | ||
737 | sz += sizeof(*qp->r_sg_list) * | ||
738 | init_attr->cap.max_recv_sge; | ||
739 | qp = kmalloc(sz, GFP_KERNEL); | ||
683 | if (!qp) { | 740 | if (!qp) { |
684 | vfree(swq); | ||
685 | ret = ERR_PTR(-ENOMEM); | 741 | ret = ERR_PTR(-ENOMEM); |
686 | goto bail; | 742 | goto bail_swq; |
687 | } | 743 | } |
688 | if (init_attr->srq) { | 744 | if (init_attr->srq) { |
745 | sz = 0; | ||
689 | qp->r_rq.size = 0; | 746 | qp->r_rq.size = 0; |
690 | qp->r_rq.max_sge = 0; | 747 | qp->r_rq.max_sge = 0; |
691 | qp->r_rq.wq = NULL; | 748 | qp->r_rq.wq = NULL; |
749 | init_attr->cap.max_recv_wr = 0; | ||
750 | init_attr->cap.max_recv_sge = 0; | ||
692 | } else { | 751 | } else { |
693 | qp->r_rq.size = init_attr->cap.max_recv_wr + 1; | 752 | qp->r_rq.size = init_attr->cap.max_recv_wr + 1; |
694 | qp->r_rq.max_sge = init_attr->cap.max_recv_sge; | 753 | qp->r_rq.max_sge = init_attr->cap.max_recv_sge; |
695 | sz = (sizeof(struct ipath_sge) * qp->r_rq.max_sge) + | 754 | sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) + |
696 | sizeof(struct ipath_rwqe); | 755 | sizeof(struct ipath_rwqe); |
697 | qp->r_rq.wq = vmalloc(qp->r_rq.size * sz); | 756 | qp->r_rq.wq = vmalloc_user(sizeof(struct ipath_rwq) + |
757 | qp->r_rq.size * sz); | ||
698 | if (!qp->r_rq.wq) { | 758 | if (!qp->r_rq.wq) { |
699 | kfree(qp); | ||
700 | vfree(swq); | ||
701 | ret = ERR_PTR(-ENOMEM); | 759 | ret = ERR_PTR(-ENOMEM); |
702 | goto bail; | 760 | goto bail_qp; |
703 | } | 761 | } |
704 | } | 762 | } |
705 | 763 | ||
@@ -719,24 +777,19 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, | |||
719 | qp->s_wq = swq; | 777 | qp->s_wq = swq; |
720 | qp->s_size = init_attr->cap.max_send_wr + 1; | 778 | qp->s_size = init_attr->cap.max_send_wr + 1; |
721 | qp->s_max_sge = init_attr->cap.max_send_sge; | 779 | qp->s_max_sge = init_attr->cap.max_send_sge; |
722 | qp->s_flags = init_attr->sq_sig_type == IB_SIGNAL_REQ_WR ? | 780 | if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR) |
723 | 1 << IPATH_S_SIGNAL_REQ_WR : 0; | 781 | qp->s_flags = 1 << IPATH_S_SIGNAL_REQ_WR; |
782 | else | ||
783 | qp->s_flags = 0; | ||
724 | dev = to_idev(ibpd->device); | 784 | dev = to_idev(ibpd->device); |
725 | err = ipath_alloc_qpn(&dev->qp_table, qp, | 785 | err = ipath_alloc_qpn(&dev->qp_table, qp, |
726 | init_attr->qp_type); | 786 | init_attr->qp_type); |
727 | if (err) { | 787 | if (err) { |
728 | vfree(swq); | ||
729 | vfree(qp->r_rq.wq); | ||
730 | kfree(qp); | ||
731 | ret = ERR_PTR(err); | 788 | ret = ERR_PTR(err); |
732 | goto bail; | 789 | goto bail_rwq; |
733 | } | 790 | } |
791 | qp->ip = NULL; | ||
734 | ipath_reset_qp(qp); | 792 | ipath_reset_qp(qp); |
735 | |||
736 | /* Tell the core driver that the kernel SMA is present. */ | ||
737 | if (init_attr->qp_type == IB_QPT_SMI) | ||
738 | ipath_layer_set_verbs_flags(dev->dd, | ||
739 | IPATH_VERBS_KERNEL_SMA); | ||
740 | break; | 793 | break; |
741 | 794 | ||
742 | default: | 795 | default: |
@@ -747,8 +800,63 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, | |||
747 | 800 | ||
748 | init_attr->cap.max_inline_data = 0; | 801 | init_attr->cap.max_inline_data = 0; |
749 | 802 | ||
803 | /* | ||
804 | * Return the address of the RWQ as the offset to mmap. | ||
805 | * See ipath_mmap() for details. | ||
806 | */ | ||
807 | if (udata && udata->outlen >= sizeof(__u64)) { | ||
808 | struct ipath_mmap_info *ip; | ||
809 | __u64 offset = (__u64) qp->r_rq.wq; | ||
810 | int err; | ||
811 | |||
812 | err = ib_copy_to_udata(udata, &offset, sizeof(offset)); | ||
813 | if (err) { | ||
814 | ret = ERR_PTR(err); | ||
815 | goto bail_rwq; | ||
816 | } | ||
817 | |||
818 | if (qp->r_rq.wq) { | ||
819 | /* Allocate info for ipath_mmap(). */ | ||
820 | ip = kmalloc(sizeof(*ip), GFP_KERNEL); | ||
821 | if (!ip) { | ||
822 | ret = ERR_PTR(-ENOMEM); | ||
823 | goto bail_rwq; | ||
824 | } | ||
825 | qp->ip = ip; | ||
826 | ip->context = ibpd->uobject->context; | ||
827 | ip->obj = qp->r_rq.wq; | ||
828 | kref_init(&ip->ref); | ||
829 | ip->mmap_cnt = 0; | ||
830 | ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + | ||
831 | qp->r_rq.size * sz); | ||
832 | spin_lock_irq(&dev->pending_lock); | ||
833 | ip->next = dev->pending_mmaps; | ||
834 | dev->pending_mmaps = ip; | ||
835 | spin_unlock_irq(&dev->pending_lock); | ||
836 | } | ||
837 | } | ||
838 | |||
839 | spin_lock(&dev->n_qps_lock); | ||
840 | if (dev->n_qps_allocated == ib_ipath_max_qps) { | ||
841 | spin_unlock(&dev->n_qps_lock); | ||
842 | ret = ERR_PTR(-ENOMEM); | ||
843 | goto bail_ip; | ||
844 | } | ||
845 | |||
846 | dev->n_qps_allocated++; | ||
847 | spin_unlock(&dev->n_qps_lock); | ||
848 | |||
750 | ret = &qp->ibqp; | 849 | ret = &qp->ibqp; |
850 | goto bail; | ||
751 | 851 | ||
852 | bail_ip: | ||
853 | kfree(qp->ip); | ||
854 | bail_rwq: | ||
855 | vfree(qp->r_rq.wq); | ||
856 | bail_qp: | ||
857 | kfree(qp); | ||
858 | bail_swq: | ||
859 | vfree(swq); | ||
752 | bail: | 860 | bail: |
753 | return ret; | 861 | return ret; |
754 | } | 862 | } |
@@ -768,15 +876,12 @@ int ipath_destroy_qp(struct ib_qp *ibqp) | |||
768 | struct ipath_ibdev *dev = to_idev(ibqp->device); | 876 | struct ipath_ibdev *dev = to_idev(ibqp->device); |
769 | unsigned long flags; | 877 | unsigned long flags; |
770 | 878 | ||
771 | /* Tell the core driver that the kernel SMA is gone. */ | 879 | spin_lock_irqsave(&qp->s_lock, flags); |
772 | if (qp->ibqp.qp_type == IB_QPT_SMI) | ||
773 | ipath_layer_set_verbs_flags(dev->dd, 0); | ||
774 | |||
775 | spin_lock_irqsave(&qp->r_rq.lock, flags); | ||
776 | spin_lock(&qp->s_lock); | ||
777 | qp->state = IB_QPS_ERR; | 880 | qp->state = IB_QPS_ERR; |
778 | spin_unlock(&qp->s_lock); | 881 | spin_unlock_irqrestore(&qp->s_lock, flags); |
779 | spin_unlock_irqrestore(&qp->r_rq.lock, flags); | 882 | spin_lock(&dev->n_qps_lock); |
883 | dev->n_qps_allocated--; | ||
884 | spin_unlock(&dev->n_qps_lock); | ||
780 | 885 | ||
781 | /* Stop the sending tasklet. */ | 886 | /* Stop the sending tasklet. */ |
782 | tasklet_kill(&qp->s_task); | 887 | tasklet_kill(&qp->s_task); |
@@ -797,8 +902,11 @@ int ipath_destroy_qp(struct ib_qp *ibqp) | |||
797 | if (atomic_read(&qp->refcount) != 0) | 902 | if (atomic_read(&qp->refcount) != 0) |
798 | ipath_free_qp(&dev->qp_table, qp); | 903 | ipath_free_qp(&dev->qp_table, qp); |
799 | 904 | ||
905 | if (qp->ip) | ||
906 | kref_put(&qp->ip->ref, ipath_release_mmap_info); | ||
907 | else | ||
908 | vfree(qp->r_rq.wq); | ||
800 | vfree(qp->s_wq); | 909 | vfree(qp->s_wq); |
801 | vfree(qp->r_rq.wq); | ||
802 | kfree(qp); | 910 | kfree(qp); |
803 | return 0; | 911 | return 0; |
804 | } | 912 | } |
@@ -850,8 +958,8 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc) | |||
850 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); | 958 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); |
851 | struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last); | 959 | struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last); |
852 | 960 | ||
853 | _VERBS_INFO("Send queue error on QP%d/%d: err: %d\n", | 961 | ipath_dbg(KERN_INFO "Send queue error on QP%d/%d: err: %d\n", |
854 | qp->ibqp.qp_num, qp->remote_qpn, wc->status); | 962 | qp->ibqp.qp_num, qp->remote_qpn, wc->status); |
855 | 963 | ||
856 | spin_lock(&dev->pending_lock); | 964 | spin_lock(&dev->pending_lock); |
857 | /* XXX What if its already removed by the timeout code? */ | 965 | /* XXX What if its already removed by the timeout code? */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 774d1615ce2f..a08654042c03 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c | |||
@@ -32,7 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include "ipath_verbs.h" | 34 | #include "ipath_verbs.h" |
35 | #include "ipath_common.h" | 35 | #include "ipath_kernel.h" |
36 | 36 | ||
37 | /* cut down ridiculously long IB macro names */ | 37 | /* cut down ridiculously long IB macro names */ |
38 | #define OP(x) IB_OPCODE_RC_##x | 38 | #define OP(x) IB_OPCODE_RC_##x |
@@ -540,7 +540,7 @@ static void send_rc_ack(struct ipath_qp *qp) | |||
540 | lrh0 = IPATH_LRH_GRH; | 540 | lrh0 = IPATH_LRH_GRH; |
541 | } | 541 | } |
542 | /* read pkey_index w/o lock (its atomic) */ | 542 | /* read pkey_index w/o lock (its atomic) */ |
543 | bth0 = ipath_layer_get_pkey(dev->dd, qp->s_pkey_index); | 543 | bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index); |
544 | if (qp->r_nak_state) | 544 | if (qp->r_nak_state) |
545 | ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) | | 545 | ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) | |
546 | (qp->r_nak_state << | 546 | (qp->r_nak_state << |
@@ -557,7 +557,7 @@ static void send_rc_ack(struct ipath_qp *qp) | |||
557 | hdr.lrh[0] = cpu_to_be16(lrh0); | 557 | hdr.lrh[0] = cpu_to_be16(lrh0); |
558 | hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); | 558 | hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); |
559 | hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC); | 559 | hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC); |
560 | hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd)); | 560 | hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid); |
561 | ohdr->bth[0] = cpu_to_be32(bth0); | 561 | ohdr->bth[0] = cpu_to_be32(bth0); |
562 | ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); | 562 | ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); |
563 | ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK); | 563 | ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK); |
@@ -1323,8 +1323,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
1323 | * the eager header buffer size to 56 bytes so the last 4 | 1323 | * the eager header buffer size to 56 bytes so the last 4 |
1324 | * bytes of the BTH header (PSN) is in the data buffer. | 1324 | * bytes of the BTH header (PSN) is in the data buffer. |
1325 | */ | 1325 | */ |
1326 | header_in_data = | 1326 | header_in_data = dev->dd->ipath_rcvhdrentsize == 16; |
1327 | ipath_layer_get_rcvhdrentsize(dev->dd) == 16; | ||
1328 | if (header_in_data) { | 1327 | if (header_in_data) { |
1329 | psn = be32_to_cpu(((__be32 *) data)[0]); | 1328 | psn = be32_to_cpu(((__be32 *) data)[0]); |
1330 | data += sizeof(__be32); | 1329 | data += sizeof(__be32); |
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h index 89df8f5ea998..6e23b3d632b8 100644 --- a/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/drivers/infiniband/hw/ipath/ipath_registers.h | |||
@@ -36,8 +36,7 @@ | |||
36 | 36 | ||
37 | /* | 37 | /* |
38 | * This file should only be included by kernel source, and by the diags. It | 38 | * This file should only be included by kernel source, and by the diags. It |
39 | * defines the registers, and their contents, for the InfiniPath HT-400 | 39 | * defines the registers, and their contents, for InfiniPath chips. |
40 | * chip. | ||
41 | */ | 40 | */ |
42 | 41 | ||
43 | /* | 42 | /* |
@@ -283,10 +282,12 @@ | |||
283 | #define INFINIPATH_XGXS_RESET 0x7ULL | 282 | #define INFINIPATH_XGXS_RESET 0x7ULL |
284 | #define INFINIPATH_XGXS_MDIOADDR_MASK 0xfULL | 283 | #define INFINIPATH_XGXS_MDIOADDR_MASK 0xfULL |
285 | #define INFINIPATH_XGXS_MDIOADDR_SHIFT 4 | 284 | #define INFINIPATH_XGXS_MDIOADDR_SHIFT 4 |
285 | #define INFINIPATH_XGXS_RX_POL_SHIFT 19 | ||
286 | #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL | ||
286 | 287 | ||
287 | #define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL /* 40 bits valid */ | 288 | #define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL /* 40 bits valid */ |
288 | 289 | ||
289 | /* TID entries (memory), HT400-only */ | 290 | /* TID entries (memory), HT-only */ |
290 | #define INFINIPATH_RT_VALID 0x8000000000000000ULL | 291 | #define INFINIPATH_RT_VALID 0x8000000000000000ULL |
291 | #define INFINIPATH_RT_ADDR_SHIFT 0 | 292 | #define INFINIPATH_RT_ADDR_SHIFT 0 |
292 | #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFF | 293 | #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFF |
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index 772bc59fb85c..5c1da2d25e03 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c | |||
@@ -32,7 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include "ipath_verbs.h" | 34 | #include "ipath_verbs.h" |
35 | #include "ipath_common.h" | 35 | #include "ipath_kernel.h" |
36 | 36 | ||
37 | /* | 37 | /* |
38 | * Convert the AETH RNR timeout code into the number of milliseconds. | 38 | * Convert the AETH RNR timeout code into the number of milliseconds. |
@@ -106,6 +106,54 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp) | |||
106 | spin_unlock_irqrestore(&dev->pending_lock, flags); | 106 | spin_unlock_irqrestore(&dev->pending_lock, flags); |
107 | } | 107 | } |
108 | 108 | ||
109 | static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe) | ||
110 | { | ||
111 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); | ||
112 | int user = to_ipd(qp->ibqp.pd)->user; | ||
113 | int i, j, ret; | ||
114 | struct ib_wc wc; | ||
115 | |||
116 | qp->r_len = 0; | ||
117 | for (i = j = 0; i < wqe->num_sge; i++) { | ||
118 | if (wqe->sg_list[i].length == 0) | ||
119 | continue; | ||
120 | /* Check LKEY */ | ||
121 | if ((user && wqe->sg_list[i].lkey == 0) || | ||
122 | !ipath_lkey_ok(&dev->lk_table, | ||
123 | &qp->r_sg_list[j], &wqe->sg_list[i], | ||
124 | IB_ACCESS_LOCAL_WRITE)) | ||
125 | goto bad_lkey; | ||
126 | qp->r_len += wqe->sg_list[i].length; | ||
127 | j++; | ||
128 | } | ||
129 | qp->r_sge.sge = qp->r_sg_list[0]; | ||
130 | qp->r_sge.sg_list = qp->r_sg_list + 1; | ||
131 | qp->r_sge.num_sge = j; | ||
132 | ret = 1; | ||
133 | goto bail; | ||
134 | |||
135 | bad_lkey: | ||
136 | wc.wr_id = wqe->wr_id; | ||
137 | wc.status = IB_WC_LOC_PROT_ERR; | ||
138 | wc.opcode = IB_WC_RECV; | ||
139 | wc.vendor_err = 0; | ||
140 | wc.byte_len = 0; | ||
141 | wc.imm_data = 0; | ||
142 | wc.qp_num = qp->ibqp.qp_num; | ||
143 | wc.src_qp = 0; | ||
144 | wc.wc_flags = 0; | ||
145 | wc.pkey_index = 0; | ||
146 | wc.slid = 0; | ||
147 | wc.sl = 0; | ||
148 | wc.dlid_path_bits = 0; | ||
149 | wc.port_num = 0; | ||
150 | /* Signal solicited completion event. */ | ||
151 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); | ||
152 | ret = 0; | ||
153 | bail: | ||
154 | return ret; | ||
155 | } | ||
156 | |||
109 | /** | 157 | /** |
110 | * ipath_get_rwqe - copy the next RWQE into the QP's RWQE | 158 | * ipath_get_rwqe - copy the next RWQE into the QP's RWQE |
111 | * @qp: the QP | 159 | * @qp: the QP |
@@ -119,71 +167,71 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) | |||
119 | { | 167 | { |
120 | unsigned long flags; | 168 | unsigned long flags; |
121 | struct ipath_rq *rq; | 169 | struct ipath_rq *rq; |
170 | struct ipath_rwq *wq; | ||
122 | struct ipath_srq *srq; | 171 | struct ipath_srq *srq; |
123 | struct ipath_rwqe *wqe; | 172 | struct ipath_rwqe *wqe; |
124 | int ret = 1; | 173 | void (*handler)(struct ib_event *, void *); |
174 | u32 tail; | ||
175 | int ret; | ||
125 | 176 | ||
126 | if (!qp->ibqp.srq) { | 177 | if (qp->ibqp.srq) { |
178 | srq = to_isrq(qp->ibqp.srq); | ||
179 | handler = srq->ibsrq.event_handler; | ||
180 | rq = &srq->rq; | ||
181 | } else { | ||
182 | srq = NULL; | ||
183 | handler = NULL; | ||
127 | rq = &qp->r_rq; | 184 | rq = &qp->r_rq; |
128 | spin_lock_irqsave(&rq->lock, flags); | ||
129 | |||
130 | if (unlikely(rq->tail == rq->head)) { | ||
131 | ret = 0; | ||
132 | goto done; | ||
133 | } | ||
134 | wqe = get_rwqe_ptr(rq, rq->tail); | ||
135 | qp->r_wr_id = wqe->wr_id; | ||
136 | if (!wr_id_only) { | ||
137 | qp->r_sge.sge = wqe->sg_list[0]; | ||
138 | qp->r_sge.sg_list = wqe->sg_list + 1; | ||
139 | qp->r_sge.num_sge = wqe->num_sge; | ||
140 | qp->r_len = wqe->length; | ||
141 | } | ||
142 | if (++rq->tail >= rq->size) | ||
143 | rq->tail = 0; | ||
144 | goto done; | ||
145 | } | 185 | } |
146 | 186 | ||
147 | srq = to_isrq(qp->ibqp.srq); | ||
148 | rq = &srq->rq; | ||
149 | spin_lock_irqsave(&rq->lock, flags); | 187 | spin_lock_irqsave(&rq->lock, flags); |
150 | 188 | wq = rq->wq; | |
151 | if (unlikely(rq->tail == rq->head)) { | 189 | tail = wq->tail; |
152 | ret = 0; | 190 | /* Validate tail before using it since it is user writable. */ |
153 | goto done; | 191 | if (tail >= rq->size) |
154 | } | 192 | tail = 0; |
155 | wqe = get_rwqe_ptr(rq, rq->tail); | 193 | do { |
194 | if (unlikely(tail == wq->head)) { | ||
195 | spin_unlock_irqrestore(&rq->lock, flags); | ||
196 | ret = 0; | ||
197 | goto bail; | ||
198 | } | ||
199 | wqe = get_rwqe_ptr(rq, tail); | ||
200 | if (++tail >= rq->size) | ||
201 | tail = 0; | ||
202 | } while (!wr_id_only && !init_sge(qp, wqe)); | ||
156 | qp->r_wr_id = wqe->wr_id; | 203 | qp->r_wr_id = wqe->wr_id; |
157 | if (!wr_id_only) { | 204 | wq->tail = tail; |
158 | qp->r_sge.sge = wqe->sg_list[0]; | 205 | |
159 | qp->r_sge.sg_list = wqe->sg_list + 1; | 206 | ret = 1; |
160 | qp->r_sge.num_sge = wqe->num_sge; | 207 | if (handler) { |
161 | qp->r_len = wqe->length; | ||
162 | } | ||
163 | if (++rq->tail >= rq->size) | ||
164 | rq->tail = 0; | ||
165 | if (srq->ibsrq.event_handler) { | ||
166 | struct ib_event ev; | ||
167 | u32 n; | 208 | u32 n; |
168 | 209 | ||
169 | if (rq->head < rq->tail) | 210 | /* |
170 | n = rq->size + rq->head - rq->tail; | 211 | * validate head pointer value and compute |
212 | * the number of remaining WQEs. | ||
213 | */ | ||
214 | n = wq->head; | ||
215 | if (n >= rq->size) | ||
216 | n = 0; | ||
217 | if (n < tail) | ||
218 | n += rq->size - tail; | ||
171 | else | 219 | else |
172 | n = rq->head - rq->tail; | 220 | n -= tail; |
173 | if (n < srq->limit) { | 221 | if (n < srq->limit) { |
222 | struct ib_event ev; | ||
223 | |||
174 | srq->limit = 0; | 224 | srq->limit = 0; |
175 | spin_unlock_irqrestore(&rq->lock, flags); | 225 | spin_unlock_irqrestore(&rq->lock, flags); |
176 | ev.device = qp->ibqp.device; | 226 | ev.device = qp->ibqp.device; |
177 | ev.element.srq = qp->ibqp.srq; | 227 | ev.element.srq = qp->ibqp.srq; |
178 | ev.event = IB_EVENT_SRQ_LIMIT_REACHED; | 228 | ev.event = IB_EVENT_SRQ_LIMIT_REACHED; |
179 | srq->ibsrq.event_handler(&ev, | 229 | handler(&ev, srq->ibsrq.srq_context); |
180 | srq->ibsrq.srq_context); | ||
181 | goto bail; | 230 | goto bail; |
182 | } | 231 | } |
183 | } | 232 | } |
184 | |||
185 | done: | ||
186 | spin_unlock_irqrestore(&rq->lock, flags); | 233 | spin_unlock_irqrestore(&rq->lock, flags); |
234 | |||
187 | bail: | 235 | bail: |
188 | return ret; | 236 | return ret; |
189 | } | 237 | } |
@@ -422,6 +470,15 @@ done: | |||
422 | wake_up(&qp->wait); | 470 | wake_up(&qp->wait); |
423 | } | 471 | } |
424 | 472 | ||
473 | static int want_buffer(struct ipath_devdata *dd) | ||
474 | { | ||
475 | set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); | ||
476 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | ||
477 | dd->ipath_sendctrl); | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
425 | /** | 482 | /** |
426 | * ipath_no_bufs_available - tell the layer driver we need buffers | 483 | * ipath_no_bufs_available - tell the layer driver we need buffers |
427 | * @qp: the QP that caused the problem | 484 | * @qp: the QP that caused the problem |
@@ -438,7 +495,7 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) | |||
438 | list_add_tail(&qp->piowait, &dev->piowait); | 495 | list_add_tail(&qp->piowait, &dev->piowait); |
439 | spin_unlock_irqrestore(&dev->pending_lock, flags); | 496 | spin_unlock_irqrestore(&dev->pending_lock, flags); |
440 | /* | 497 | /* |
441 | * Note that as soon as ipath_layer_want_buffer() is called and | 498 | * Note that as soon as want_buffer() is called and |
442 | * possibly before it returns, ipath_ib_piobufavail() | 499 | * possibly before it returns, ipath_ib_piobufavail() |
443 | * could be called. If we are still in the tasklet function, | 500 | * could be called. If we are still in the tasklet function, |
444 | * tasklet_hi_schedule() will not call us until the next time | 501 | * tasklet_hi_schedule() will not call us until the next time |
@@ -448,7 +505,7 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) | |||
448 | */ | 505 | */ |
449 | clear_bit(IPATH_S_BUSY, &qp->s_flags); | 506 | clear_bit(IPATH_S_BUSY, &qp->s_flags); |
450 | tasklet_unlock(&qp->s_task); | 507 | tasklet_unlock(&qp->s_task); |
451 | ipath_layer_want_buffer(dev->dd); | 508 | want_buffer(dev->dd); |
452 | dev->n_piowait++; | 509 | dev->n_piowait++; |
453 | } | 510 | } |
454 | 511 | ||
@@ -563,7 +620,7 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr, | |||
563 | hdr->hop_limit = grh->hop_limit; | 620 | hdr->hop_limit = grh->hop_limit; |
564 | /* The SGID is 32-bit aligned. */ | 621 | /* The SGID is 32-bit aligned. */ |
565 | hdr->sgid.global.subnet_prefix = dev->gid_prefix; | 622 | hdr->sgid.global.subnet_prefix = dev->gid_prefix; |
566 | hdr->sgid.global.interface_id = ipath_layer_get_guid(dev->dd); | 623 | hdr->sgid.global.interface_id = dev->dd->ipath_guid; |
567 | hdr->dgid = grh->dgid; | 624 | hdr->dgid = grh->dgid; |
568 | 625 | ||
569 | /* GRH header size in 32-bit words. */ | 626 | /* GRH header size in 32-bit words. */ |
@@ -595,8 +652,7 @@ void ipath_do_ruc_send(unsigned long data) | |||
595 | if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags)) | 652 | if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags)) |
596 | goto bail; | 653 | goto bail; |
597 | 654 | ||
598 | if (unlikely(qp->remote_ah_attr.dlid == | 655 | if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) { |
599 | ipath_layer_get_lid(dev->dd))) { | ||
600 | ipath_ruc_loopback(qp); | 656 | ipath_ruc_loopback(qp); |
601 | goto clear; | 657 | goto clear; |
602 | } | 658 | } |
@@ -663,8 +719,8 @@ again: | |||
663 | qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); | 719 | qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); |
664 | qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + | 720 | qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + |
665 | SIZE_OF_CRC); | 721 | SIZE_OF_CRC); |
666 | qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd)); | 722 | qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid); |
667 | bth0 |= ipath_layer_get_pkey(dev->dd, qp->s_pkey_index); | 723 | bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index); |
668 | bth0 |= extra_bytes << 20; | 724 | bth0 |= extra_bytes << 20; |
669 | ohdr->bth[0] = cpu_to_be32(bth0); | 725 | ohdr->bth[0] = cpu_to_be32(bth0); |
670 | ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); | 726 | ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); |
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c index f760434660bd..941e866d9517 100644 --- a/drivers/infiniband/hw/ipath/ipath_srq.c +++ b/drivers/infiniband/hw/ipath/ipath_srq.c | |||
@@ -48,66 +48,39 @@ int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
48 | struct ib_recv_wr **bad_wr) | 48 | struct ib_recv_wr **bad_wr) |
49 | { | 49 | { |
50 | struct ipath_srq *srq = to_isrq(ibsrq); | 50 | struct ipath_srq *srq = to_isrq(ibsrq); |
51 | struct ipath_ibdev *dev = to_idev(ibsrq->device); | 51 | struct ipath_rwq *wq; |
52 | unsigned long flags; | 52 | unsigned long flags; |
53 | int ret; | 53 | int ret; |
54 | 54 | ||
55 | for (; wr; wr = wr->next) { | 55 | for (; wr; wr = wr->next) { |
56 | struct ipath_rwqe *wqe; | 56 | struct ipath_rwqe *wqe; |
57 | u32 next; | 57 | u32 next; |
58 | int i, j; | 58 | int i; |
59 | 59 | ||
60 | if (wr->num_sge > srq->rq.max_sge) { | 60 | if ((unsigned) wr->num_sge > srq->rq.max_sge) { |
61 | *bad_wr = wr; | 61 | *bad_wr = wr; |
62 | ret = -ENOMEM; | 62 | ret = -ENOMEM; |
63 | goto bail; | 63 | goto bail; |
64 | } | 64 | } |
65 | 65 | ||
66 | spin_lock_irqsave(&srq->rq.lock, flags); | 66 | spin_lock_irqsave(&srq->rq.lock, flags); |
67 | next = srq->rq.head + 1; | 67 | wq = srq->rq.wq; |
68 | next = wq->head + 1; | ||
68 | if (next >= srq->rq.size) | 69 | if (next >= srq->rq.size) |
69 | next = 0; | 70 | next = 0; |
70 | if (next == srq->rq.tail) { | 71 | if (next == wq->tail) { |
71 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 72 | spin_unlock_irqrestore(&srq->rq.lock, flags); |
72 | *bad_wr = wr; | 73 | *bad_wr = wr; |
73 | ret = -ENOMEM; | 74 | ret = -ENOMEM; |
74 | goto bail; | 75 | goto bail; |
75 | } | 76 | } |
76 | 77 | ||
77 | wqe = get_rwqe_ptr(&srq->rq, srq->rq.head); | 78 | wqe = get_rwqe_ptr(&srq->rq, wq->head); |
78 | wqe->wr_id = wr->wr_id; | 79 | wqe->wr_id = wr->wr_id; |
79 | wqe->sg_list[0].mr = NULL; | 80 | wqe->num_sge = wr->num_sge; |
80 | wqe->sg_list[0].vaddr = NULL; | 81 | for (i = 0; i < wr->num_sge; i++) |
81 | wqe->sg_list[0].length = 0; | 82 | wqe->sg_list[i] = wr->sg_list[i]; |
82 | wqe->sg_list[0].sge_length = 0; | 83 | wq->head = next; |
83 | wqe->length = 0; | ||
84 | for (i = 0, j = 0; i < wr->num_sge; i++) { | ||
85 | /* Check LKEY */ | ||
86 | if (to_ipd(srq->ibsrq.pd)->user && | ||
87 | wr->sg_list[i].lkey == 0) { | ||
88 | spin_unlock_irqrestore(&srq->rq.lock, | ||
89 | flags); | ||
90 | *bad_wr = wr; | ||
91 | ret = -EINVAL; | ||
92 | goto bail; | ||
93 | } | ||
94 | if (wr->sg_list[i].length == 0) | ||
95 | continue; | ||
96 | if (!ipath_lkey_ok(&dev->lk_table, | ||
97 | &wqe->sg_list[j], | ||
98 | &wr->sg_list[i], | ||
99 | IB_ACCESS_LOCAL_WRITE)) { | ||
100 | spin_unlock_irqrestore(&srq->rq.lock, | ||
101 | flags); | ||
102 | *bad_wr = wr; | ||
103 | ret = -EINVAL; | ||
104 | goto bail; | ||
105 | } | ||
106 | wqe->length += wr->sg_list[i].length; | ||
107 | j++; | ||
108 | } | ||
109 | wqe->num_sge = j; | ||
110 | srq->rq.head = next; | ||
111 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 84 | spin_unlock_irqrestore(&srq->rq.lock, flags); |
112 | } | 85 | } |
113 | ret = 0; | 86 | ret = 0; |
@@ -133,53 +106,95 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, | |||
133 | 106 | ||
134 | if (dev->n_srqs_allocated == ib_ipath_max_srqs) { | 107 | if (dev->n_srqs_allocated == ib_ipath_max_srqs) { |
135 | ret = ERR_PTR(-ENOMEM); | 108 | ret = ERR_PTR(-ENOMEM); |
136 | goto bail; | 109 | goto done; |
137 | } | 110 | } |
138 | 111 | ||
139 | if (srq_init_attr->attr.max_wr == 0) { | 112 | if (srq_init_attr->attr.max_wr == 0) { |
140 | ret = ERR_PTR(-EINVAL); | 113 | ret = ERR_PTR(-EINVAL); |
141 | goto bail; | 114 | goto done; |
142 | } | 115 | } |
143 | 116 | ||
144 | if ((srq_init_attr->attr.max_sge > ib_ipath_max_srq_sges) || | 117 | if ((srq_init_attr->attr.max_sge > ib_ipath_max_srq_sges) || |
145 | (srq_init_attr->attr.max_wr > ib_ipath_max_srq_wrs)) { | 118 | (srq_init_attr->attr.max_wr > ib_ipath_max_srq_wrs)) { |
146 | ret = ERR_PTR(-EINVAL); | 119 | ret = ERR_PTR(-EINVAL); |
147 | goto bail; | 120 | goto done; |
148 | } | 121 | } |
149 | 122 | ||
150 | srq = kmalloc(sizeof(*srq), GFP_KERNEL); | 123 | srq = kmalloc(sizeof(*srq), GFP_KERNEL); |
151 | if (!srq) { | 124 | if (!srq) { |
152 | ret = ERR_PTR(-ENOMEM); | 125 | ret = ERR_PTR(-ENOMEM); |
153 | goto bail; | 126 | goto done; |
154 | } | 127 | } |
155 | 128 | ||
156 | /* | 129 | /* |
157 | * Need to use vmalloc() if we want to support large #s of entries. | 130 | * Need to use vmalloc() if we want to support large #s of entries. |
158 | */ | 131 | */ |
159 | srq->rq.size = srq_init_attr->attr.max_wr + 1; | 132 | srq->rq.size = srq_init_attr->attr.max_wr + 1; |
160 | sz = sizeof(struct ipath_sge) * srq_init_attr->attr.max_sge + | 133 | srq->rq.max_sge = srq_init_attr->attr.max_sge; |
134 | sz = sizeof(struct ib_sge) * srq->rq.max_sge + | ||
161 | sizeof(struct ipath_rwqe); | 135 | sizeof(struct ipath_rwqe); |
162 | srq->rq.wq = vmalloc(srq->rq.size * sz); | 136 | srq->rq.wq = vmalloc_user(sizeof(struct ipath_rwq) + srq->rq.size * sz); |
163 | if (!srq->rq.wq) { | 137 | if (!srq->rq.wq) { |
164 | kfree(srq); | ||
165 | ret = ERR_PTR(-ENOMEM); | 138 | ret = ERR_PTR(-ENOMEM); |
166 | goto bail; | 139 | goto bail_srq; |
167 | } | 140 | } |
168 | 141 | ||
169 | /* | 142 | /* |
143 | * Return the address of the RWQ as the offset to mmap. | ||
144 | * See ipath_mmap() for details. | ||
145 | */ | ||
146 | if (udata && udata->outlen >= sizeof(__u64)) { | ||
147 | struct ipath_mmap_info *ip; | ||
148 | __u64 offset = (__u64) srq->rq.wq; | ||
149 | int err; | ||
150 | |||
151 | err = ib_copy_to_udata(udata, &offset, sizeof(offset)); | ||
152 | if (err) { | ||
153 | ret = ERR_PTR(err); | ||
154 | goto bail_wq; | ||
155 | } | ||
156 | |||
157 | /* Allocate info for ipath_mmap(). */ | ||
158 | ip = kmalloc(sizeof(*ip), GFP_KERNEL); | ||
159 | if (!ip) { | ||
160 | ret = ERR_PTR(-ENOMEM); | ||
161 | goto bail_wq; | ||
162 | } | ||
163 | srq->ip = ip; | ||
164 | ip->context = ibpd->uobject->context; | ||
165 | ip->obj = srq->rq.wq; | ||
166 | kref_init(&ip->ref); | ||
167 | ip->mmap_cnt = 0; | ||
168 | ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + | ||
169 | srq->rq.size * sz); | ||
170 | spin_lock_irq(&dev->pending_lock); | ||
171 | ip->next = dev->pending_mmaps; | ||
172 | dev->pending_mmaps = ip; | ||
173 | spin_unlock_irq(&dev->pending_lock); | ||
174 | } else | ||
175 | srq->ip = NULL; | ||
176 | |||
177 | /* | ||
170 | * ib_create_srq() will initialize srq->ibsrq. | 178 | * ib_create_srq() will initialize srq->ibsrq. |
171 | */ | 179 | */ |
172 | spin_lock_init(&srq->rq.lock); | 180 | spin_lock_init(&srq->rq.lock); |
173 | srq->rq.head = 0; | 181 | srq->rq.wq->head = 0; |
174 | srq->rq.tail = 0; | 182 | srq->rq.wq->tail = 0; |
175 | srq->rq.max_sge = srq_init_attr->attr.max_sge; | 183 | srq->rq.max_sge = srq_init_attr->attr.max_sge; |
176 | srq->limit = srq_init_attr->attr.srq_limit; | 184 | srq->limit = srq_init_attr->attr.srq_limit; |
177 | 185 | ||
186 | dev->n_srqs_allocated++; | ||
187 | |||
178 | ret = &srq->ibsrq; | 188 | ret = &srq->ibsrq; |
189 | goto done; | ||
179 | 190 | ||
180 | dev->n_srqs_allocated++; | 191 | bail_wq: |
192 | vfree(srq->rq.wq); | ||
181 | 193 | ||
182 | bail: | 194 | bail_srq: |
195 | kfree(srq); | ||
196 | |||
197 | done: | ||
183 | return ret; | 198 | return ret; |
184 | } | 199 | } |
185 | 200 | ||
@@ -188,83 +203,130 @@ bail: | |||
188 | * @ibsrq: the SRQ to modify | 203 | * @ibsrq: the SRQ to modify |
189 | * @attr: the new attributes of the SRQ | 204 | * @attr: the new attributes of the SRQ |
190 | * @attr_mask: indicates which attributes to modify | 205 | * @attr_mask: indicates which attributes to modify |
206 | * @udata: user data for ipathverbs.so | ||
191 | */ | 207 | */ |
192 | int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, | 208 | int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, |
193 | enum ib_srq_attr_mask attr_mask) | 209 | enum ib_srq_attr_mask attr_mask, |
210 | struct ib_udata *udata) | ||
194 | { | 211 | { |
195 | struct ipath_srq *srq = to_isrq(ibsrq); | 212 | struct ipath_srq *srq = to_isrq(ibsrq); |
196 | unsigned long flags; | 213 | int ret = 0; |
197 | int ret; | ||
198 | 214 | ||
199 | if (attr_mask & IB_SRQ_MAX_WR) | 215 | if (attr_mask & IB_SRQ_MAX_WR) { |
200 | if ((attr->max_wr > ib_ipath_max_srq_wrs) || | 216 | struct ipath_rwq *owq; |
201 | (attr->max_sge > srq->rq.max_sge)) { | 217 | struct ipath_rwq *wq; |
202 | ret = -EINVAL; | 218 | struct ipath_rwqe *p; |
203 | goto bail; | 219 | u32 sz, size, n, head, tail; |
204 | } | ||
205 | 220 | ||
206 | if (attr_mask & IB_SRQ_LIMIT) | 221 | /* Check that the requested sizes are below the limits. */ |
207 | if (attr->srq_limit >= srq->rq.size) { | 222 | if ((attr->max_wr > ib_ipath_max_srq_wrs) || |
223 | ((attr_mask & IB_SRQ_LIMIT) ? | ||
224 | attr->srq_limit : srq->limit) > attr->max_wr) { | ||
208 | ret = -EINVAL; | 225 | ret = -EINVAL; |
209 | goto bail; | 226 | goto bail; |
210 | } | 227 | } |
211 | 228 | ||
212 | if (attr_mask & IB_SRQ_MAX_WR) { | ||
213 | struct ipath_rwqe *wq, *p; | ||
214 | u32 sz, size, n; | ||
215 | |||
216 | sz = sizeof(struct ipath_rwqe) + | 229 | sz = sizeof(struct ipath_rwqe) + |
217 | attr->max_sge * sizeof(struct ipath_sge); | 230 | srq->rq.max_sge * sizeof(struct ib_sge); |
218 | size = attr->max_wr + 1; | 231 | size = attr->max_wr + 1; |
219 | wq = vmalloc(size * sz); | 232 | wq = vmalloc_user(sizeof(struct ipath_rwq) + size * sz); |
220 | if (!wq) { | 233 | if (!wq) { |
221 | ret = -ENOMEM; | 234 | ret = -ENOMEM; |
222 | goto bail; | 235 | goto bail; |
223 | } | 236 | } |
224 | 237 | ||
225 | spin_lock_irqsave(&srq->rq.lock, flags); | 238 | /* |
226 | if (srq->rq.head < srq->rq.tail) | 239 | * Return the address of the RWQ as the offset to mmap. |
227 | n = srq->rq.size + srq->rq.head - srq->rq.tail; | 240 | * See ipath_mmap() for details. |
241 | */ | ||
242 | if (udata && udata->inlen >= sizeof(__u64)) { | ||
243 | __u64 offset_addr; | ||
244 | __u64 offset = (__u64) wq; | ||
245 | |||
246 | ret = ib_copy_from_udata(&offset_addr, udata, | ||
247 | sizeof(offset_addr)); | ||
248 | if (ret) { | ||
249 | vfree(wq); | ||
250 | goto bail; | ||
251 | } | ||
252 | udata->outbuf = (void __user *) offset_addr; | ||
253 | ret = ib_copy_to_udata(udata, &offset, | ||
254 | sizeof(offset)); | ||
255 | if (ret) { | ||
256 | vfree(wq); | ||
257 | goto bail; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | spin_lock_irq(&srq->rq.lock); | ||
262 | /* | ||
263 | * validate head pointer value and compute | ||
264 | * the number of remaining WQEs. | ||
265 | */ | ||
266 | owq = srq->rq.wq; | ||
267 | head = owq->head; | ||
268 | if (head >= srq->rq.size) | ||
269 | head = 0; | ||
270 | tail = owq->tail; | ||
271 | if (tail >= srq->rq.size) | ||
272 | tail = 0; | ||
273 | n = head; | ||
274 | if (n < tail) | ||
275 | n += srq->rq.size - tail; | ||
228 | else | 276 | else |
229 | n = srq->rq.head - srq->rq.tail; | 277 | n -= tail; |
230 | if (size <= n || size <= srq->limit) { | 278 | if (size <= n) { |
231 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 279 | spin_unlock_irq(&srq->rq.lock); |
232 | vfree(wq); | 280 | vfree(wq); |
233 | ret = -EINVAL; | 281 | ret = -EINVAL; |
234 | goto bail; | 282 | goto bail; |
235 | } | 283 | } |
236 | n = 0; | 284 | n = 0; |
237 | p = wq; | 285 | p = wq->wq; |
238 | while (srq->rq.tail != srq->rq.head) { | 286 | while (tail != head) { |
239 | struct ipath_rwqe *wqe; | 287 | struct ipath_rwqe *wqe; |
240 | int i; | 288 | int i; |
241 | 289 | ||
242 | wqe = get_rwqe_ptr(&srq->rq, srq->rq.tail); | 290 | wqe = get_rwqe_ptr(&srq->rq, tail); |
243 | p->wr_id = wqe->wr_id; | 291 | p->wr_id = wqe->wr_id; |
244 | p->length = wqe->length; | ||
245 | p->num_sge = wqe->num_sge; | 292 | p->num_sge = wqe->num_sge; |
246 | for (i = 0; i < wqe->num_sge; i++) | 293 | for (i = 0; i < wqe->num_sge; i++) |
247 | p->sg_list[i] = wqe->sg_list[i]; | 294 | p->sg_list[i] = wqe->sg_list[i]; |
248 | n++; | 295 | n++; |
249 | p = (struct ipath_rwqe *)((char *) p + sz); | 296 | p = (struct ipath_rwqe *)((char *) p + sz); |
250 | if (++srq->rq.tail >= srq->rq.size) | 297 | if (++tail >= srq->rq.size) |
251 | srq->rq.tail = 0; | 298 | tail = 0; |
252 | } | 299 | } |
253 | vfree(srq->rq.wq); | ||
254 | srq->rq.wq = wq; | 300 | srq->rq.wq = wq; |
255 | srq->rq.size = size; | 301 | srq->rq.size = size; |
256 | srq->rq.head = n; | 302 | wq->head = n; |
257 | srq->rq.tail = 0; | 303 | wq->tail = 0; |
258 | srq->rq.max_sge = attr->max_sge; | 304 | if (attr_mask & IB_SRQ_LIMIT) |
259 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 305 | srq->limit = attr->srq_limit; |
260 | } | 306 | spin_unlock_irq(&srq->rq.lock); |
261 | 307 | ||
262 | if (attr_mask & IB_SRQ_LIMIT) { | 308 | vfree(owq); |
263 | spin_lock_irqsave(&srq->rq.lock, flags); | 309 | |
264 | srq->limit = attr->srq_limit; | 310 | if (srq->ip) { |
265 | spin_unlock_irqrestore(&srq->rq.lock, flags); | 311 | struct ipath_mmap_info *ip = srq->ip; |
312 | struct ipath_ibdev *dev = to_idev(srq->ibsrq.device); | ||
313 | |||
314 | ip->obj = wq; | ||
315 | ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + | ||
316 | size * sz); | ||
317 | spin_lock_irq(&dev->pending_lock); | ||
318 | ip->next = dev->pending_mmaps; | ||
319 | dev->pending_mmaps = ip; | ||
320 | spin_unlock_irq(&dev->pending_lock); | ||
321 | } | ||
322 | } else if (attr_mask & IB_SRQ_LIMIT) { | ||
323 | spin_lock_irq(&srq->rq.lock); | ||
324 | if (attr->srq_limit >= srq->rq.size) | ||
325 | ret = -EINVAL; | ||
326 | else | ||
327 | srq->limit = attr->srq_limit; | ||
328 | spin_unlock_irq(&srq->rq.lock); | ||
266 | } | 329 | } |
267 | ret = 0; | ||
268 | 330 | ||
269 | bail: | 331 | bail: |
270 | return ret; | 332 | return ret; |
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c index 70351b7e35c0..30a825928fcf 100644 --- a/drivers/infiniband/hw/ipath/ipath_stats.c +++ b/drivers/infiniband/hw/ipath/ipath_stats.c | |||
@@ -271,33 +271,6 @@ void ipath_get_faststats(unsigned long opaque) | |||
271 | } | 271 | } |
272 | } | 272 | } |
273 | 273 | ||
274 | if (dd->ipath_nosma_bufs) { | ||
275 | dd->ipath_nosma_secs += 5; | ||
276 | if (dd->ipath_nosma_secs >= 30) { | ||
277 | ipath_cdbg(SMA, "No SMA bufs avail %u seconds; " | ||
278 | "cancelling pending sends\n", | ||
279 | dd->ipath_nosma_secs); | ||
280 | /* | ||
281 | * issue an abort as well, in case we have a packet | ||
282 | * stuck in launch fifo. This could corrupt an | ||
283 | * outgoing user packet in the worst case, | ||
284 | * but this is a pretty catastrophic, anyway. | ||
285 | */ | ||
286 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | ||
287 | INFINIPATH_S_ABORT); | ||
288 | ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf, | ||
289 | dd->ipath_piobcnt2k + | ||
290 | dd->ipath_piobcnt4k - | ||
291 | dd->ipath_lastport_piobuf); | ||
292 | /* start again, if necessary */ | ||
293 | dd->ipath_nosma_secs = 0; | ||
294 | } else | ||
295 | ipath_cdbg(SMA, "No SMA bufs avail %u tries, " | ||
296 | "after %u seconds\n", | ||
297 | dd->ipath_nosma_bufs, | ||
298 | dd->ipath_nosma_secs); | ||
299 | } | ||
300 | |||
301 | done: | 274 | done: |
302 | mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5); | 275 | mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5); |
303 | } | 276 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index b98821d7801d..e299148c4b68 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/pci.h> | 35 | #include <linux/pci.h> |
36 | 36 | ||
37 | #include "ipath_kernel.h" | 37 | #include "ipath_kernel.h" |
38 | #include "ipath_layer.h" | ||
39 | #include "ipath_common.h" | 38 | #include "ipath_common.h" |
40 | 39 | ||
41 | /** | 40 | /** |
@@ -76,7 +75,7 @@ bail: | |||
76 | static ssize_t show_version(struct device_driver *dev, char *buf) | 75 | static ssize_t show_version(struct device_driver *dev, char *buf) |
77 | { | 76 | { |
78 | /* The string printed here is already newline-terminated. */ | 77 | /* The string printed here is already newline-terminated. */ |
79 | return scnprintf(buf, PAGE_SIZE, "%s", ipath_core_version); | 78 | return scnprintf(buf, PAGE_SIZE, "%s", ib_ipath_version); |
80 | } | 79 | } |
81 | 80 | ||
82 | static ssize_t show_num_units(struct device_driver *dev, char *buf) | 81 | static ssize_t show_num_units(struct device_driver *dev, char *buf) |
@@ -108,8 +107,8 @@ static const char *ipath_status_str[] = { | |||
108 | "Initted", | 107 | "Initted", |
109 | "Disabled", | 108 | "Disabled", |
110 | "Admin_Disabled", | 109 | "Admin_Disabled", |
111 | "OIB_SMA", | 110 | "", /* This used to be the old "OIB_SMA" status. */ |
112 | "SMA", | 111 | "", /* This used to be the old "SMA" status. */ |
113 | "Present", | 112 | "Present", |
114 | "IB_link_up", | 113 | "IB_link_up", |
115 | "IB_configured", | 114 | "IB_configured", |
@@ -227,7 +226,6 @@ static ssize_t store_mlid(struct device *dev, | |||
227 | unit = dd->ipath_unit; | 226 | unit = dd->ipath_unit; |
228 | 227 | ||
229 | dd->ipath_mlid = mlid; | 228 | dd->ipath_mlid = mlid; |
230 | ipath_layer_intr(dd, IPATH_LAYER_INT_BCAST); | ||
231 | 229 | ||
232 | goto bail; | 230 | goto bail; |
233 | invalid: | 231 | invalid: |
@@ -467,7 +465,7 @@ static ssize_t store_link_state(struct device *dev, | |||
467 | if (ret < 0) | 465 | if (ret < 0) |
468 | goto invalid; | 466 | goto invalid; |
469 | 467 | ||
470 | r = ipath_layer_set_linkstate(dd, state); | 468 | r = ipath_set_linkstate(dd, state); |
471 | if (r < 0) { | 469 | if (r < 0) { |
472 | ret = r; | 470 | ret = r; |
473 | goto bail; | 471 | goto bail; |
@@ -502,7 +500,7 @@ static ssize_t store_mtu(struct device *dev, | |||
502 | if (ret < 0) | 500 | if (ret < 0) |
503 | goto invalid; | 501 | goto invalid; |
504 | 502 | ||
505 | r = ipath_layer_set_mtu(dd, mtu); | 503 | r = ipath_set_mtu(dd, mtu); |
506 | if (r < 0) | 504 | if (r < 0) |
507 | ret = r; | 505 | ret = r; |
508 | 506 | ||
@@ -563,6 +561,33 @@ bail: | |||
563 | return ret; | 561 | return ret; |
564 | } | 562 | } |
565 | 563 | ||
564 | static ssize_t store_rx_pol_inv(struct device *dev, | ||
565 | struct device_attribute *attr, | ||
566 | const char *buf, | ||
567 | size_t count) | ||
568 | { | ||
569 | struct ipath_devdata *dd = dev_get_drvdata(dev); | ||
570 | int ret, r; | ||
571 | u16 val; | ||
572 | |||
573 | ret = ipath_parse_ushort(buf, &val); | ||
574 | if (ret < 0) | ||
575 | goto invalid; | ||
576 | |||
577 | r = ipath_set_rx_pol_inv(dd, val); | ||
578 | if (r < 0) { | ||
579 | ret = r; | ||
580 | goto bail; | ||
581 | } | ||
582 | |||
583 | goto bail; | ||
584 | invalid: | ||
585 | ipath_dev_err(dd, "attempt to set invalid Rx Polarity invert\n"); | ||
586 | bail: | ||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | |||
566 | static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); | 591 | static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); |
567 | static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); | 592 | static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); |
568 | 593 | ||
@@ -589,6 +614,7 @@ static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); | |||
589 | static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL); | 614 | static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL); |
590 | static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); | 615 | static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); |
591 | static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); | 616 | static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); |
617 | static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv); | ||
592 | 618 | ||
593 | static struct attribute *dev_attributes[] = { | 619 | static struct attribute *dev_attributes[] = { |
594 | &dev_attr_guid.attr, | 620 | &dev_attr_guid.attr, |
@@ -603,6 +629,7 @@ static struct attribute *dev_attributes[] = { | |||
603 | &dev_attr_boardversion.attr, | 629 | &dev_attr_boardversion.attr, |
604 | &dev_attr_unit.attr, | 630 | &dev_attr_unit.attr, |
605 | &dev_attr_enabled.attr, | 631 | &dev_attr_enabled.attr, |
632 | &dev_attr_rx_pol_inv.attr, | ||
606 | NULL | 633 | NULL |
607 | }; | 634 | }; |
608 | 635 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index c33abea2d5a7..0fd3cded16ba 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c | |||
@@ -32,7 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include "ipath_verbs.h" | 34 | #include "ipath_verbs.h" |
35 | #include "ipath_common.h" | 35 | #include "ipath_kernel.h" |
36 | 36 | ||
37 | /* cut down ridiculously long IB macro names */ | 37 | /* cut down ridiculously long IB macro names */ |
38 | #define OP(x) IB_OPCODE_UC_##x | 38 | #define OP(x) IB_OPCODE_UC_##x |
@@ -261,8 +261,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
261 | * size to 56 bytes so the last 4 bytes of | 261 | * size to 56 bytes so the last 4 bytes of |
262 | * the BTH header (PSN) is in the data buffer. | 262 | * the BTH header (PSN) is in the data buffer. |
263 | */ | 263 | */ |
264 | header_in_data = | 264 | header_in_data = dev->dd->ipath_rcvhdrentsize == 16; |
265 | ipath_layer_get_rcvhdrentsize(dev->dd) == 16; | ||
266 | if (header_in_data) { | 265 | if (header_in_data) { |
267 | psn = be32_to_cpu(((__be32 *) data)[0]); | 266 | psn = be32_to_cpu(((__be32 *) data)[0]); |
268 | data += sizeof(__be32); | 267 | data += sizeof(__be32); |
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 3466129af804..6991d1d74e3c 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c | |||
@@ -34,7 +34,54 @@ | |||
34 | #include <rdma/ib_smi.h> | 34 | #include <rdma/ib_smi.h> |
35 | 35 | ||
36 | #include "ipath_verbs.h" | 36 | #include "ipath_verbs.h" |
37 | #include "ipath_common.h" | 37 | #include "ipath_kernel.h" |
38 | |||
39 | static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, | ||
40 | u32 *lengthp, struct ipath_sge_state *ss) | ||
41 | { | ||
42 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); | ||
43 | int user = to_ipd(qp->ibqp.pd)->user; | ||
44 | int i, j, ret; | ||
45 | struct ib_wc wc; | ||
46 | |||
47 | *lengthp = 0; | ||
48 | for (i = j = 0; i < wqe->num_sge; i++) { | ||
49 | if (wqe->sg_list[i].length == 0) | ||
50 | continue; | ||
51 | /* Check LKEY */ | ||
52 | if ((user && wqe->sg_list[i].lkey == 0) || | ||
53 | !ipath_lkey_ok(&dev->lk_table, | ||
54 | j ? &ss->sg_list[j - 1] : &ss->sge, | ||
55 | &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE)) | ||
56 | goto bad_lkey; | ||
57 | *lengthp += wqe->sg_list[i].length; | ||
58 | j++; | ||
59 | } | ||
60 | ss->num_sge = j; | ||
61 | ret = 1; | ||
62 | goto bail; | ||
63 | |||
64 | bad_lkey: | ||
65 | wc.wr_id = wqe->wr_id; | ||
66 | wc.status = IB_WC_LOC_PROT_ERR; | ||
67 | wc.opcode = IB_WC_RECV; | ||
68 | wc.vendor_err = 0; | ||
69 | wc.byte_len = 0; | ||
70 | wc.imm_data = 0; | ||
71 | wc.qp_num = qp->ibqp.qp_num; | ||
72 | wc.src_qp = 0; | ||
73 | wc.wc_flags = 0; | ||
74 | wc.pkey_index = 0; | ||
75 | wc.slid = 0; | ||
76 | wc.sl = 0; | ||
77 | wc.dlid_path_bits = 0; | ||
78 | wc.port_num = 0; | ||
79 | /* Signal solicited completion event. */ | ||
80 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); | ||
81 | ret = 0; | ||
82 | bail: | ||
83 | return ret; | ||
84 | } | ||
38 | 85 | ||
39 | /** | 86 | /** |
40 | * ipath_ud_loopback - handle send on loopback QPs | 87 | * ipath_ud_loopback - handle send on loopback QPs |
@@ -46,6 +93,8 @@ | |||
46 | * | 93 | * |
47 | * This is called from ipath_post_ud_send() to forward a WQE addressed | 94 | * This is called from ipath_post_ud_send() to forward a WQE addressed |
48 | * to the same HCA. | 95 | * to the same HCA. |
96 | * Note that the receive interrupt handler may be calling ipath_ud_rcv() | ||
97 | * while this is being called. | ||
49 | */ | 98 | */ |
50 | static void ipath_ud_loopback(struct ipath_qp *sqp, | 99 | static void ipath_ud_loopback(struct ipath_qp *sqp, |
51 | struct ipath_sge_state *ss, | 100 | struct ipath_sge_state *ss, |
@@ -60,7 +109,11 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, | |||
60 | struct ipath_srq *srq; | 109 | struct ipath_srq *srq; |
61 | struct ipath_sge_state rsge; | 110 | struct ipath_sge_state rsge; |
62 | struct ipath_sge *sge; | 111 | struct ipath_sge *sge; |
112 | struct ipath_rwq *wq; | ||
63 | struct ipath_rwqe *wqe; | 113 | struct ipath_rwqe *wqe; |
114 | void (*handler)(struct ib_event *, void *); | ||
115 | u32 tail; | ||
116 | u32 rlen; | ||
64 | 117 | ||
65 | qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn); | 118 | qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn); |
66 | if (!qp) | 119 | if (!qp) |
@@ -94,6 +147,13 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, | |||
94 | wc->imm_data = 0; | 147 | wc->imm_data = 0; |
95 | } | 148 | } |
96 | 149 | ||
150 | if (wr->num_sge > 1) { | ||
151 | rsge.sg_list = kmalloc((wr->num_sge - 1) * | ||
152 | sizeof(struct ipath_sge), | ||
153 | GFP_ATOMIC); | ||
154 | } else | ||
155 | rsge.sg_list = NULL; | ||
156 | |||
97 | /* | 157 | /* |
98 | * Get the next work request entry to find where to put the data. | 158 | * Get the next work request entry to find where to put the data. |
99 | * Note that it is safe to drop the lock after changing rq->tail | 159 | * Note that it is safe to drop the lock after changing rq->tail |
@@ -101,37 +161,52 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, | |||
101 | */ | 161 | */ |
102 | if (qp->ibqp.srq) { | 162 | if (qp->ibqp.srq) { |
103 | srq = to_isrq(qp->ibqp.srq); | 163 | srq = to_isrq(qp->ibqp.srq); |
164 | handler = srq->ibsrq.event_handler; | ||
104 | rq = &srq->rq; | 165 | rq = &srq->rq; |
105 | } else { | 166 | } else { |
106 | srq = NULL; | 167 | srq = NULL; |
168 | handler = NULL; | ||
107 | rq = &qp->r_rq; | 169 | rq = &qp->r_rq; |
108 | } | 170 | } |
171 | |||
109 | spin_lock_irqsave(&rq->lock, flags); | 172 | spin_lock_irqsave(&rq->lock, flags); |
110 | if (rq->tail == rq->head) { | 173 | wq = rq->wq; |
111 | spin_unlock_irqrestore(&rq->lock, flags); | 174 | tail = wq->tail; |
112 | dev->n_pkt_drops++; | 175 | while (1) { |
113 | goto done; | 176 | if (unlikely(tail == wq->head)) { |
177 | spin_unlock_irqrestore(&rq->lock, flags); | ||
178 | dev->n_pkt_drops++; | ||
179 | goto bail_sge; | ||
180 | } | ||
181 | wqe = get_rwqe_ptr(rq, tail); | ||
182 | if (++tail >= rq->size) | ||
183 | tail = 0; | ||
184 | if (init_sge(qp, wqe, &rlen, &rsge)) | ||
185 | break; | ||
186 | wq->tail = tail; | ||
114 | } | 187 | } |
115 | /* Silently drop packets which are too big. */ | 188 | /* Silently drop packets which are too big. */ |
116 | wqe = get_rwqe_ptr(rq, rq->tail); | 189 | if (wc->byte_len > rlen) { |
117 | if (wc->byte_len > wqe->length) { | ||
118 | spin_unlock_irqrestore(&rq->lock, flags); | 190 | spin_unlock_irqrestore(&rq->lock, flags); |
119 | dev->n_pkt_drops++; | 191 | dev->n_pkt_drops++; |
120 | goto done; | 192 | goto bail_sge; |
121 | } | 193 | } |
194 | wq->tail = tail; | ||
122 | wc->wr_id = wqe->wr_id; | 195 | wc->wr_id = wqe->wr_id; |
123 | rsge.sge = wqe->sg_list[0]; | 196 | if (handler) { |
124 | rsge.sg_list = wqe->sg_list + 1; | ||
125 | rsge.num_sge = wqe->num_sge; | ||
126 | if (++rq->tail >= rq->size) | ||
127 | rq->tail = 0; | ||
128 | if (srq && srq->ibsrq.event_handler) { | ||
129 | u32 n; | 197 | u32 n; |
130 | 198 | ||
131 | if (rq->head < rq->tail) | 199 | /* |
132 | n = rq->size + rq->head - rq->tail; | 200 | * validate head pointer value and compute |
201 | * the number of remaining WQEs. | ||
202 | */ | ||
203 | n = wq->head; | ||
204 | if (n >= rq->size) | ||
205 | n = 0; | ||
206 | if (n < tail) | ||
207 | n += rq->size - tail; | ||
133 | else | 208 | else |
134 | n = rq->head - rq->tail; | 209 | n -= tail; |
135 | if (n < srq->limit) { | 210 | if (n < srq->limit) { |
136 | struct ib_event ev; | 211 | struct ib_event ev; |
137 | 212 | ||
@@ -140,12 +215,12 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, | |||
140 | ev.device = qp->ibqp.device; | 215 | ev.device = qp->ibqp.device; |
141 | ev.element.srq = qp->ibqp.srq; | 216 | ev.element.srq = qp->ibqp.srq; |
142 | ev.event = IB_EVENT_SRQ_LIMIT_REACHED; | 217 | ev.event = IB_EVENT_SRQ_LIMIT_REACHED; |
143 | srq->ibsrq.event_handler(&ev, | 218 | handler(&ev, srq->ibsrq.srq_context); |
144 | srq->ibsrq.srq_context); | ||
145 | } else | 219 | } else |
146 | spin_unlock_irqrestore(&rq->lock, flags); | 220 | spin_unlock_irqrestore(&rq->lock, flags); |
147 | } else | 221 | } else |
148 | spin_unlock_irqrestore(&rq->lock, flags); | 222 | spin_unlock_irqrestore(&rq->lock, flags); |
223 | |||
149 | ah_attr = &to_iah(wr->wr.ud.ah)->attr; | 224 | ah_attr = &to_iah(wr->wr.ud.ah)->attr; |
150 | if (ah_attr->ah_flags & IB_AH_GRH) { | 225 | if (ah_attr->ah_flags & IB_AH_GRH) { |
151 | ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh)); | 226 | ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh)); |
@@ -186,7 +261,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, | |||
186 | wc->src_qp = sqp->ibqp.qp_num; | 261 | wc->src_qp = sqp->ibqp.qp_num; |
187 | /* XXX do we know which pkey matched? Only needed for GSI. */ | 262 | /* XXX do we know which pkey matched? Only needed for GSI. */ |
188 | wc->pkey_index = 0; | 263 | wc->pkey_index = 0; |
189 | wc->slid = ipath_layer_get_lid(dev->dd) | | 264 | wc->slid = dev->dd->ipath_lid | |
190 | (ah_attr->src_path_bits & | 265 | (ah_attr->src_path_bits & |
191 | ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1)); | 266 | ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1)); |
192 | wc->sl = ah_attr->sl; | 267 | wc->sl = ah_attr->sl; |
@@ -196,6 +271,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, | |||
196 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc, | 271 | ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc, |
197 | wr->send_flags & IB_SEND_SOLICITED); | 272 | wr->send_flags & IB_SEND_SOLICITED); |
198 | 273 | ||
274 | bail_sge: | ||
275 | kfree(rsge.sg_list); | ||
199 | done: | 276 | done: |
200 | if (atomic_dec_and_test(&qp->refcount)) | 277 | if (atomic_dec_and_test(&qp->refcount)) |
201 | wake_up(&qp->wait); | 278 | wake_up(&qp->wait); |
@@ -276,7 +353,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) | |||
276 | ss.num_sge++; | 353 | ss.num_sge++; |
277 | } | 354 | } |
278 | /* Check for invalid packet size. */ | 355 | /* Check for invalid packet size. */ |
279 | if (len > ipath_layer_get_ibmtu(dev->dd)) { | 356 | if (len > dev->dd->ipath_ibmtu) { |
280 | ret = -EINVAL; | 357 | ret = -EINVAL; |
281 | goto bail; | 358 | goto bail; |
282 | } | 359 | } |
@@ -298,7 +375,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) | |||
298 | dev->n_unicast_xmit++; | 375 | dev->n_unicast_xmit++; |
299 | lid = ah_attr->dlid & | 376 | lid = ah_attr->dlid & |
300 | ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); | 377 | ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); |
301 | if (unlikely(lid == ipath_layer_get_lid(dev->dd))) { | 378 | if (unlikely(lid == dev->dd->ipath_lid)) { |
302 | /* | 379 | /* |
303 | * Pass in an uninitialized ib_wc to save stack | 380 | * Pass in an uninitialized ib_wc to save stack |
304 | * space. | 381 | * space. |
@@ -327,7 +404,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) | |||
327 | qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = | 404 | qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = |
328 | dev->gid_prefix; | 405 | dev->gid_prefix; |
329 | qp->s_hdr.u.l.grh.sgid.global.interface_id = | 406 | qp->s_hdr.u.l.grh.sgid.global.interface_id = |
330 | ipath_layer_get_guid(dev->dd); | 407 | dev->dd->ipath_guid; |
331 | qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid; | 408 | qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid; |
332 | /* | 409 | /* |
333 | * Don't worry about sending to locally attached multicast | 410 | * Don't worry about sending to locally attached multicast |
@@ -357,7 +434,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) | |||
357 | qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); | 434 | qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); |
358 | qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */ | 435 | qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */ |
359 | qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC); | 436 | qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC); |
360 | lid = ipath_layer_get_lid(dev->dd); | 437 | lid = dev->dd->ipath_lid; |
361 | if (lid) { | 438 | if (lid) { |
362 | lid |= ah_attr->src_path_bits & | 439 | lid |= ah_attr->src_path_bits & |
363 | ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); | 440 | ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); |
@@ -368,7 +445,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) | |||
368 | bth0 |= 1 << 23; | 445 | bth0 |= 1 << 23; |
369 | bth0 |= extra_bytes << 20; | 446 | bth0 |= extra_bytes << 20; |
370 | bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY : | 447 | bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY : |
371 | ipath_layer_get_pkey(dev->dd, qp->s_pkey_index); | 448 | ipath_get_pkey(dev->dd, qp->s_pkey_index); |
372 | ohdr->bth[0] = cpu_to_be32(bth0); | 449 | ohdr->bth[0] = cpu_to_be32(bth0); |
373 | /* | 450 | /* |
374 | * Use the multicast QP if the destination LID is a multicast LID. | 451 | * Use the multicast QP if the destination LID is a multicast LID. |
@@ -433,13 +510,9 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
433 | int opcode; | 510 | int opcode; |
434 | u32 hdrsize; | 511 | u32 hdrsize; |
435 | u32 pad; | 512 | u32 pad; |
436 | unsigned long flags; | ||
437 | struct ib_wc wc; | 513 | struct ib_wc wc; |
438 | u32 qkey; | 514 | u32 qkey; |
439 | u32 src_qp; | 515 | u32 src_qp; |
440 | struct ipath_rq *rq; | ||
441 | struct ipath_srq *srq; | ||
442 | struct ipath_rwqe *wqe; | ||
443 | u16 dlid; | 516 | u16 dlid; |
444 | int header_in_data; | 517 | int header_in_data; |
445 | 518 | ||
@@ -458,8 +531,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
458 | * the eager header buffer size to 56 bytes so the last 12 | 531 | * the eager header buffer size to 56 bytes so the last 12 |
459 | * bytes of the IB header is in the data buffer. | 532 | * bytes of the IB header is in the data buffer. |
460 | */ | 533 | */ |
461 | header_in_data = | 534 | header_in_data = dev->dd->ipath_rcvhdrentsize == 16; |
462 | ipath_layer_get_rcvhdrentsize(dev->dd) == 16; | ||
463 | if (header_in_data) { | 535 | if (header_in_data) { |
464 | qkey = be32_to_cpu(((__be32 *) data)[1]); | 536 | qkey = be32_to_cpu(((__be32 *) data)[1]); |
465 | src_qp = be32_to_cpu(((__be32 *) data)[2]); | 537 | src_qp = be32_to_cpu(((__be32 *) data)[2]); |
@@ -547,19 +619,10 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
547 | 619 | ||
548 | /* | 620 | /* |
549 | * Get the next work request entry to find where to put the data. | 621 | * Get the next work request entry to find where to put the data. |
550 | * Note that it is safe to drop the lock after changing rq->tail | ||
551 | * since ipath_post_receive() won't fill the empty slot. | ||
552 | */ | 622 | */ |
553 | if (qp->ibqp.srq) { | 623 | if (qp->r_reuse_sge) |
554 | srq = to_isrq(qp->ibqp.srq); | 624 | qp->r_reuse_sge = 0; |
555 | rq = &srq->rq; | 625 | else if (!ipath_get_rwqe(qp, 0)) { |
556 | } else { | ||
557 | srq = NULL; | ||
558 | rq = &qp->r_rq; | ||
559 | } | ||
560 | spin_lock_irqsave(&rq->lock, flags); | ||
561 | if (rq->tail == rq->head) { | ||
562 | spin_unlock_irqrestore(&rq->lock, flags); | ||
563 | /* | 626 | /* |
564 | * Count VL15 packets dropped due to no receive buffer. | 627 | * Count VL15 packets dropped due to no receive buffer. |
565 | * Otherwise, count them as buffer overruns since usually, | 628 | * Otherwise, count them as buffer overruns since usually, |
@@ -573,39 +636,11 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
573 | goto bail; | 636 | goto bail; |
574 | } | 637 | } |
575 | /* Silently drop packets which are too big. */ | 638 | /* Silently drop packets which are too big. */ |
576 | wqe = get_rwqe_ptr(rq, rq->tail); | 639 | if (wc.byte_len > qp->r_len) { |
577 | if (wc.byte_len > wqe->length) { | 640 | qp->r_reuse_sge = 1; |
578 | spin_unlock_irqrestore(&rq->lock, flags); | ||
579 | dev->n_pkt_drops++; | 641 | dev->n_pkt_drops++; |
580 | goto bail; | 642 | goto bail; |
581 | } | 643 | } |
582 | wc.wr_id = wqe->wr_id; | ||
583 | qp->r_sge.sge = wqe->sg_list[0]; | ||
584 | qp->r_sge.sg_list = wqe->sg_list + 1; | ||
585 | qp->r_sge.num_sge = wqe->num_sge; | ||
586 | if (++rq->tail >= rq->size) | ||
587 | rq->tail = 0; | ||
588 | if (srq && srq->ibsrq.event_handler) { | ||
589 | u32 n; | ||
590 | |||
591 | if (rq->head < rq->tail) | ||
592 | n = rq->size + rq->head - rq->tail; | ||
593 | else | ||
594 | n = rq->head - rq->tail; | ||
595 | if (n < srq->limit) { | ||
596 | struct ib_event ev; | ||
597 | |||
598 | srq->limit = 0; | ||
599 | spin_unlock_irqrestore(&rq->lock, flags); | ||
600 | ev.device = qp->ibqp.device; | ||
601 | ev.element.srq = qp->ibqp.srq; | ||
602 | ev.event = IB_EVENT_SRQ_LIMIT_REACHED; | ||
603 | srq->ibsrq.event_handler(&ev, | ||
604 | srq->ibsrq.srq_context); | ||
605 | } else | ||
606 | spin_unlock_irqrestore(&rq->lock, flags); | ||
607 | } else | ||
608 | spin_unlock_irqrestore(&rq->lock, flags); | ||
609 | if (has_grh) { | 644 | if (has_grh) { |
610 | ipath_copy_sge(&qp->r_sge, &hdr->u.l.grh, | 645 | ipath_copy_sge(&qp->r_sge, &hdr->u.l.grh, |
611 | sizeof(struct ib_grh)); | 646 | sizeof(struct ib_grh)); |
@@ -614,6 +649,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, | |||
614 | ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh)); | 649 | ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh)); |
615 | ipath_copy_sge(&qp->r_sge, data, | 650 | ipath_copy_sge(&qp->r_sge, data, |
616 | wc.byte_len - sizeof(struct ib_grh)); | 651 | wc.byte_len - sizeof(struct ib_grh)); |
652 | wc.wr_id = qp->r_wr_id; | ||
617 | wc.status = IB_WC_SUCCESS; | 653 | wc.status = IB_WC_SUCCESS; |
618 | wc.opcode = IB_WC_RECV; | 654 | wc.opcode = IB_WC_RECV; |
619 | wc.vendor_err = 0; | 655 | wc.vendor_err = 0; |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index d70a9b6b5239..b8381c5e72bd 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -33,15 +33,13 @@ | |||
33 | 33 | ||
34 | #include <rdma/ib_mad.h> | 34 | #include <rdma/ib_mad.h> |
35 | #include <rdma/ib_user_verbs.h> | 35 | #include <rdma/ib_user_verbs.h> |
36 | #include <linux/io.h> | ||
36 | #include <linux/utsname.h> | 37 | #include <linux/utsname.h> |
37 | 38 | ||
38 | #include "ipath_kernel.h" | 39 | #include "ipath_kernel.h" |
39 | #include "ipath_verbs.h" | 40 | #include "ipath_verbs.h" |
40 | #include "ipath_common.h" | 41 | #include "ipath_common.h" |
41 | 42 | ||
42 | /* Not static, because we don't want the compiler removing it */ | ||
43 | const char ipath_verbs_version[] = "ipath_verbs " IPATH_IDSTR; | ||
44 | |||
45 | static unsigned int ib_ipath_qp_table_size = 251; | 43 | static unsigned int ib_ipath_qp_table_size = 251; |
46 | module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO); | 44 | module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO); |
47 | MODULE_PARM_DESC(qp_table_size, "QP table size"); | 45 | MODULE_PARM_DESC(qp_table_size, "QP table size"); |
@@ -52,10 +50,6 @@ module_param_named(lkey_table_size, ib_ipath_lkey_table_size, uint, | |||
52 | MODULE_PARM_DESC(lkey_table_size, | 50 | MODULE_PARM_DESC(lkey_table_size, |
53 | "LKEY table size in bits (2^n, 1 <= n <= 23)"); | 51 | "LKEY table size in bits (2^n, 1 <= n <= 23)"); |
54 | 52 | ||
55 | unsigned int ib_ipath_debug; /* debug mask */ | ||
56 | module_param_named(debug, ib_ipath_debug, uint, S_IWUSR | S_IRUGO); | ||
57 | MODULE_PARM_DESC(debug, "Verbs debug mask"); | ||
58 | |||
59 | static unsigned int ib_ipath_max_pds = 0xFFFF; | 53 | static unsigned int ib_ipath_max_pds = 0xFFFF; |
60 | module_param_named(max_pds, ib_ipath_max_pds, uint, S_IWUSR | S_IRUGO); | 54 | module_param_named(max_pds, ib_ipath_max_pds, uint, S_IWUSR | S_IRUGO); |
61 | MODULE_PARM_DESC(max_pds, | 55 | MODULE_PARM_DESC(max_pds, |
@@ -79,6 +73,10 @@ module_param_named(max_qp_wrs, ib_ipath_max_qp_wrs, uint, | |||
79 | S_IWUSR | S_IRUGO); | 73 | S_IWUSR | S_IRUGO); |
80 | MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support"); | 74 | MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support"); |
81 | 75 | ||
76 | unsigned int ib_ipath_max_qps = 16384; | ||
77 | module_param_named(max_qps, ib_ipath_max_qps, uint, S_IWUSR | S_IRUGO); | ||
78 | MODULE_PARM_DESC(max_qps, "Maximum number of QPs to support"); | ||
79 | |||
82 | unsigned int ib_ipath_max_sges = 0x60; | 80 | unsigned int ib_ipath_max_sges = 0x60; |
83 | module_param_named(max_sges, ib_ipath_max_sges, uint, S_IWUSR | S_IRUGO); | 81 | module_param_named(max_sges, ib_ipath_max_sges, uint, S_IWUSR | S_IRUGO); |
84 | MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support"); | 82 | MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support"); |
@@ -109,9 +107,9 @@ module_param_named(max_srq_wrs, ib_ipath_max_srq_wrs, | |||
109 | uint, S_IWUSR | S_IRUGO); | 107 | uint, S_IWUSR | S_IRUGO); |
110 | MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support"); | 108 | MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support"); |
111 | 109 | ||
112 | MODULE_LICENSE("GPL"); | 110 | static unsigned int ib_ipath_disable_sma; |
113 | MODULE_AUTHOR("QLogic <support@pathscale.com>"); | 111 | module_param_named(disable_sma, ib_ipath_disable_sma, uint, S_IWUSR | S_IRUGO); |
114 | MODULE_DESCRIPTION("QLogic InfiniPath driver"); | 112 | MODULE_PARM_DESC(ib_ipath_disable_sma, "Disable the SMA"); |
115 | 113 | ||
116 | const int ib_ipath_state_ops[IB_QPS_ERR + 1] = { | 114 | const int ib_ipath_state_ops[IB_QPS_ERR + 1] = { |
117 | [IB_QPS_RESET] = 0, | 115 | [IB_QPS_RESET] = 0, |
@@ -125,6 +123,16 @@ const int ib_ipath_state_ops[IB_QPS_ERR + 1] = { | |||
125 | [IB_QPS_ERR] = 0, | 123 | [IB_QPS_ERR] = 0, |
126 | }; | 124 | }; |
127 | 125 | ||
126 | struct ipath_ucontext { | ||
127 | struct ib_ucontext ibucontext; | ||
128 | }; | ||
129 | |||
130 | static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext | ||
131 | *ibucontext) | ||
132 | { | ||
133 | return container_of(ibucontext, struct ipath_ucontext, ibucontext); | ||
134 | } | ||
135 | |||
128 | /* | 136 | /* |
129 | * Translate ib_wr_opcode into ib_wc_opcode. | 137 | * Translate ib_wr_opcode into ib_wc_opcode. |
130 | */ | 138 | */ |
@@ -277,11 +285,12 @@ static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
277 | struct ib_recv_wr **bad_wr) | 285 | struct ib_recv_wr **bad_wr) |
278 | { | 286 | { |
279 | struct ipath_qp *qp = to_iqp(ibqp); | 287 | struct ipath_qp *qp = to_iqp(ibqp); |
288 | struct ipath_rwq *wq = qp->r_rq.wq; | ||
280 | unsigned long flags; | 289 | unsigned long flags; |
281 | int ret; | 290 | int ret; |
282 | 291 | ||
283 | /* Check that state is OK to post receive. */ | 292 | /* Check that state is OK to post receive. */ |
284 | if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK)) { | 293 | if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK) || !wq) { |
285 | *bad_wr = wr; | 294 | *bad_wr = wr; |
286 | ret = -EINVAL; | 295 | ret = -EINVAL; |
287 | goto bail; | 296 | goto bail; |
@@ -290,59 +299,31 @@ static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
290 | for (; wr; wr = wr->next) { | 299 | for (; wr; wr = wr->next) { |
291 | struct ipath_rwqe *wqe; | 300 | struct ipath_rwqe *wqe; |
292 | u32 next; | 301 | u32 next; |
293 | int i, j; | 302 | int i; |
294 | 303 | ||
295 | if (wr->num_sge > qp->r_rq.max_sge) { | 304 | if ((unsigned) wr->num_sge > qp->r_rq.max_sge) { |
296 | *bad_wr = wr; | 305 | *bad_wr = wr; |
297 | ret = -ENOMEM; | 306 | ret = -ENOMEM; |
298 | goto bail; | 307 | goto bail; |
299 | } | 308 | } |
300 | 309 | ||
301 | spin_lock_irqsave(&qp->r_rq.lock, flags); | 310 | spin_lock_irqsave(&qp->r_rq.lock, flags); |
302 | next = qp->r_rq.head + 1; | 311 | next = wq->head + 1; |
303 | if (next >= qp->r_rq.size) | 312 | if (next >= qp->r_rq.size) |
304 | next = 0; | 313 | next = 0; |
305 | if (next == qp->r_rq.tail) { | 314 | if (next == wq->tail) { |
306 | spin_unlock_irqrestore(&qp->r_rq.lock, flags); | 315 | spin_unlock_irqrestore(&qp->r_rq.lock, flags); |
307 | *bad_wr = wr; | 316 | *bad_wr = wr; |
308 | ret = -ENOMEM; | 317 | ret = -ENOMEM; |
309 | goto bail; | 318 | goto bail; |
310 | } | 319 | } |
311 | 320 | ||
312 | wqe = get_rwqe_ptr(&qp->r_rq, qp->r_rq.head); | 321 | wqe = get_rwqe_ptr(&qp->r_rq, wq->head); |
313 | wqe->wr_id = wr->wr_id; | 322 | wqe->wr_id = wr->wr_id; |
314 | wqe->sg_list[0].mr = NULL; | 323 | wqe->num_sge = wr->num_sge; |
315 | wqe->sg_list[0].vaddr = NULL; | 324 | for (i = 0; i < wr->num_sge; i++) |
316 | wqe->sg_list[0].length = 0; | 325 | wqe->sg_list[i] = wr->sg_list[i]; |
317 | wqe->sg_list[0].sge_length = 0; | 326 | wq->head = next; |
318 | wqe->length = 0; | ||
319 | for (i = 0, j = 0; i < wr->num_sge; i++) { | ||
320 | /* Check LKEY */ | ||
321 | if (to_ipd(qp->ibqp.pd)->user && | ||
322 | wr->sg_list[i].lkey == 0) { | ||
323 | spin_unlock_irqrestore(&qp->r_rq.lock, | ||
324 | flags); | ||
325 | *bad_wr = wr; | ||
326 | ret = -EINVAL; | ||
327 | goto bail; | ||
328 | } | ||
329 | if (wr->sg_list[i].length == 0) | ||
330 | continue; | ||
331 | if (!ipath_lkey_ok( | ||
332 | &to_idev(qp->ibqp.device)->lk_table, | ||
333 | &wqe->sg_list[j], &wr->sg_list[i], | ||
334 | IB_ACCESS_LOCAL_WRITE)) { | ||
335 | spin_unlock_irqrestore(&qp->r_rq.lock, | ||
336 | flags); | ||
337 | *bad_wr = wr; | ||
338 | ret = -EINVAL; | ||
339 | goto bail; | ||
340 | } | ||
341 | wqe->length += wr->sg_list[i].length; | ||
342 | j++; | ||
343 | } | ||
344 | wqe->num_sge = j; | ||
345 | qp->r_rq.head = next; | ||
346 | spin_unlock_irqrestore(&qp->r_rq.lock, flags); | 327 | spin_unlock_irqrestore(&qp->r_rq.lock, flags); |
347 | } | 328 | } |
348 | ret = 0; | 329 | ret = 0; |
@@ -377,6 +358,9 @@ static void ipath_qp_rcv(struct ipath_ibdev *dev, | |||
377 | switch (qp->ibqp.qp_type) { | 358 | switch (qp->ibqp.qp_type) { |
378 | case IB_QPT_SMI: | 359 | case IB_QPT_SMI: |
379 | case IB_QPT_GSI: | 360 | case IB_QPT_GSI: |
361 | if (ib_ipath_disable_sma) | ||
362 | break; | ||
363 | /* FALLTHROUGH */ | ||
380 | case IB_QPT_UD: | 364 | case IB_QPT_UD: |
381 | ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp); | 365 | ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp); |
382 | break; | 366 | break; |
@@ -395,7 +379,7 @@ static void ipath_qp_rcv(struct ipath_ibdev *dev, | |||
395 | } | 379 | } |
396 | 380 | ||
397 | /** | 381 | /** |
398 | * ipath_ib_rcv - process and incoming packet | 382 | * ipath_ib_rcv - process an incoming packet |
399 | * @arg: the device pointer | 383 | * @arg: the device pointer |
400 | * @rhdr: the header of the packet | 384 | * @rhdr: the header of the packet |
401 | * @data: the packet data | 385 | * @data: the packet data |
@@ -404,9 +388,9 @@ static void ipath_qp_rcv(struct ipath_ibdev *dev, | |||
404 | * This is called from ipath_kreceive() to process an incoming packet at | 388 | * This is called from ipath_kreceive() to process an incoming packet at |
405 | * interrupt level. Tlen is the length of the header + data + CRC in bytes. | 389 | * interrupt level. Tlen is the length of the header + data + CRC in bytes. |
406 | */ | 390 | */ |
407 | static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen) | 391 | void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data, |
392 | u32 tlen) | ||
408 | { | 393 | { |
409 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
410 | struct ipath_ib_header *hdr = rhdr; | 394 | struct ipath_ib_header *hdr = rhdr; |
411 | struct ipath_other_headers *ohdr; | 395 | struct ipath_other_headers *ohdr; |
412 | struct ipath_qp *qp; | 396 | struct ipath_qp *qp; |
@@ -427,7 +411,7 @@ static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen) | |||
427 | lid = be16_to_cpu(hdr->lrh[1]); | 411 | lid = be16_to_cpu(hdr->lrh[1]); |
428 | if (lid < IPATH_MULTICAST_LID_BASE) { | 412 | if (lid < IPATH_MULTICAST_LID_BASE) { |
429 | lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); | 413 | lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); |
430 | if (unlikely(lid != ipath_layer_get_lid(dev->dd))) { | 414 | if (unlikely(lid != dev->dd->ipath_lid)) { |
431 | dev->rcv_errors++; | 415 | dev->rcv_errors++; |
432 | goto bail; | 416 | goto bail; |
433 | } | 417 | } |
@@ -495,9 +479,8 @@ bail:; | |||
495 | * This is called from ipath_do_rcv_timer() at interrupt level to check for | 479 | * This is called from ipath_do_rcv_timer() at interrupt level to check for |
496 | * QPs which need retransmits and to collect performance numbers. | 480 | * QPs which need retransmits and to collect performance numbers. |
497 | */ | 481 | */ |
498 | static void ipath_ib_timer(void *arg) | 482 | void ipath_ib_timer(struct ipath_ibdev *dev) |
499 | { | 483 | { |
500 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
501 | struct ipath_qp *resend = NULL; | 484 | struct ipath_qp *resend = NULL; |
502 | struct list_head *last; | 485 | struct list_head *last; |
503 | struct ipath_qp *qp; | 486 | struct ipath_qp *qp; |
@@ -539,19 +522,19 @@ static void ipath_ib_timer(void *arg) | |||
539 | if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED && | 522 | if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED && |
540 | --dev->pma_sample_start == 0) { | 523 | --dev->pma_sample_start == 0) { |
541 | dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING; | 524 | dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING; |
542 | ipath_layer_snapshot_counters(dev->dd, &dev->ipath_sword, | 525 | ipath_snapshot_counters(dev->dd, &dev->ipath_sword, |
543 | &dev->ipath_rword, | 526 | &dev->ipath_rword, |
544 | &dev->ipath_spkts, | 527 | &dev->ipath_spkts, |
545 | &dev->ipath_rpkts, | 528 | &dev->ipath_rpkts, |
546 | &dev->ipath_xmit_wait); | 529 | &dev->ipath_xmit_wait); |
547 | } | 530 | } |
548 | if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) { | 531 | if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) { |
549 | if (dev->pma_sample_interval == 0) { | 532 | if (dev->pma_sample_interval == 0) { |
550 | u64 ta, tb, tc, td, te; | 533 | u64 ta, tb, tc, td, te; |
551 | 534 | ||
552 | dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE; | 535 | dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE; |
553 | ipath_layer_snapshot_counters(dev->dd, &ta, &tb, | 536 | ipath_snapshot_counters(dev->dd, &ta, &tb, |
554 | &tc, &td, &te); | 537 | &tc, &td, &te); |
555 | 538 | ||
556 | dev->ipath_sword = ta - dev->ipath_sword; | 539 | dev->ipath_sword = ta - dev->ipath_sword; |
557 | dev->ipath_rword = tb - dev->ipath_rword; | 540 | dev->ipath_rword = tb - dev->ipath_rword; |
@@ -581,6 +564,362 @@ static void ipath_ib_timer(void *arg) | |||
581 | } | 564 | } |
582 | } | 565 | } |
583 | 566 | ||
567 | static void update_sge(struct ipath_sge_state *ss, u32 length) | ||
568 | { | ||
569 | struct ipath_sge *sge = &ss->sge; | ||
570 | |||
571 | sge->vaddr += length; | ||
572 | sge->length -= length; | ||
573 | sge->sge_length -= length; | ||
574 | if (sge->sge_length == 0) { | ||
575 | if (--ss->num_sge) | ||
576 | *sge = *ss->sg_list++; | ||
577 | } else if (sge->length == 0 && sge->mr != NULL) { | ||
578 | if (++sge->n >= IPATH_SEGSZ) { | ||
579 | if (++sge->m >= sge->mr->mapsz) | ||
580 | return; | ||
581 | sge->n = 0; | ||
582 | } | ||
583 | sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr; | ||
584 | sge->length = sge->mr->map[sge->m]->segs[sge->n].length; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | #ifdef __LITTLE_ENDIAN | ||
589 | static inline u32 get_upper_bits(u32 data, u32 shift) | ||
590 | { | ||
591 | return data >> shift; | ||
592 | } | ||
593 | |||
594 | static inline u32 set_upper_bits(u32 data, u32 shift) | ||
595 | { | ||
596 | return data << shift; | ||
597 | } | ||
598 | |||
599 | static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) | ||
600 | { | ||
601 | data <<= ((sizeof(u32) - n) * BITS_PER_BYTE); | ||
602 | data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE); | ||
603 | return data; | ||
604 | } | ||
605 | #else | ||
606 | static inline u32 get_upper_bits(u32 data, u32 shift) | ||
607 | { | ||
608 | return data << shift; | ||
609 | } | ||
610 | |||
611 | static inline u32 set_upper_bits(u32 data, u32 shift) | ||
612 | { | ||
613 | return data >> shift; | ||
614 | } | ||
615 | |||
616 | static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) | ||
617 | { | ||
618 | data >>= ((sizeof(u32) - n) * BITS_PER_BYTE); | ||
619 | data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE); | ||
620 | return data; | ||
621 | } | ||
622 | #endif | ||
623 | |||
624 | static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, | ||
625 | u32 length) | ||
626 | { | ||
627 | u32 extra = 0; | ||
628 | u32 data = 0; | ||
629 | u32 last; | ||
630 | |||
631 | while (1) { | ||
632 | u32 len = ss->sge.length; | ||
633 | u32 off; | ||
634 | |||
635 | BUG_ON(len == 0); | ||
636 | if (len > length) | ||
637 | len = length; | ||
638 | if (len > ss->sge.sge_length) | ||
639 | len = ss->sge.sge_length; | ||
640 | /* If the source address is not aligned, try to align it. */ | ||
641 | off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1); | ||
642 | if (off) { | ||
643 | u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr & | ||
644 | ~(sizeof(u32) - 1)); | ||
645 | u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE); | ||
646 | u32 y; | ||
647 | |||
648 | y = sizeof(u32) - off; | ||
649 | if (len > y) | ||
650 | len = y; | ||
651 | if (len + extra >= sizeof(u32)) { | ||
652 | data |= set_upper_bits(v, extra * | ||
653 | BITS_PER_BYTE); | ||
654 | len = sizeof(u32) - extra; | ||
655 | if (len == length) { | ||
656 | last = data; | ||
657 | break; | ||
658 | } | ||
659 | __raw_writel(data, piobuf); | ||
660 | piobuf++; | ||
661 | extra = 0; | ||
662 | data = 0; | ||
663 | } else { | ||
664 | /* Clear unused upper bytes */ | ||
665 | data |= clear_upper_bytes(v, len, extra); | ||
666 | if (len == length) { | ||
667 | last = data; | ||
668 | break; | ||
669 | } | ||
670 | extra += len; | ||
671 | } | ||
672 | } else if (extra) { | ||
673 | /* Source address is aligned. */ | ||
674 | u32 *addr = (u32 *) ss->sge.vaddr; | ||
675 | int shift = extra * BITS_PER_BYTE; | ||
676 | int ushift = 32 - shift; | ||
677 | u32 l = len; | ||
678 | |||
679 | while (l >= sizeof(u32)) { | ||
680 | u32 v = *addr; | ||
681 | |||
682 | data |= set_upper_bits(v, shift); | ||
683 | __raw_writel(data, piobuf); | ||
684 | data = get_upper_bits(v, ushift); | ||
685 | piobuf++; | ||
686 | addr++; | ||
687 | l -= sizeof(u32); | ||
688 | } | ||
689 | /* | ||
690 | * We still have 'extra' number of bytes leftover. | ||
691 | */ | ||
692 | if (l) { | ||
693 | u32 v = *addr; | ||
694 | |||
695 | if (l + extra >= sizeof(u32)) { | ||
696 | data |= set_upper_bits(v, shift); | ||
697 | len -= l + extra - sizeof(u32); | ||
698 | if (len == length) { | ||
699 | last = data; | ||
700 | break; | ||
701 | } | ||
702 | __raw_writel(data, piobuf); | ||
703 | piobuf++; | ||
704 | extra = 0; | ||
705 | data = 0; | ||
706 | } else { | ||
707 | /* Clear unused upper bytes */ | ||
708 | data |= clear_upper_bytes(v, l, | ||
709 | extra); | ||
710 | if (len == length) { | ||
711 | last = data; | ||
712 | break; | ||
713 | } | ||
714 | extra += l; | ||
715 | } | ||
716 | } else if (len == length) { | ||
717 | last = data; | ||
718 | break; | ||
719 | } | ||
720 | } else if (len == length) { | ||
721 | u32 w; | ||
722 | |||
723 | /* | ||
724 | * Need to round up for the last dword in the | ||
725 | * packet. | ||
726 | */ | ||
727 | w = (len + 3) >> 2; | ||
728 | __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1); | ||
729 | piobuf += w - 1; | ||
730 | last = ((u32 *) ss->sge.vaddr)[w - 1]; | ||
731 | break; | ||
732 | } else { | ||
733 | u32 w = len >> 2; | ||
734 | |||
735 | __iowrite32_copy(piobuf, ss->sge.vaddr, w); | ||
736 | piobuf += w; | ||
737 | |||
738 | extra = len & (sizeof(u32) - 1); | ||
739 | if (extra) { | ||
740 | u32 v = ((u32 *) ss->sge.vaddr)[w]; | ||
741 | |||
742 | /* Clear unused upper bytes */ | ||
743 | data = clear_upper_bytes(v, extra, 0); | ||
744 | } | ||
745 | } | ||
746 | update_sge(ss, len); | ||
747 | length -= len; | ||
748 | } | ||
749 | /* Update address before sending packet. */ | ||
750 | update_sge(ss, length); | ||
751 | /* must flush early everything before trigger word */ | ||
752 | ipath_flush_wc(); | ||
753 | __raw_writel(last, piobuf); | ||
754 | /* be sure trigger word is written */ | ||
755 | ipath_flush_wc(); | ||
756 | } | ||
757 | |||
758 | /** | ||
759 | * ipath_verbs_send - send a packet | ||
760 | * @dd: the infinipath device | ||
761 | * @hdrwords: the number of words in the header | ||
762 | * @hdr: the packet header | ||
763 | * @len: the length of the packet in bytes | ||
764 | * @ss: the SGE to send | ||
765 | */ | ||
766 | int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, | ||
767 | u32 *hdr, u32 len, struct ipath_sge_state *ss) | ||
768 | { | ||
769 | u32 __iomem *piobuf; | ||
770 | u32 plen; | ||
771 | int ret; | ||
772 | |||
773 | /* +1 is for the qword padding of pbc */ | ||
774 | plen = hdrwords + ((len + 3) >> 2) + 1; | ||
775 | if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) { | ||
776 | ipath_dbg("packet len 0x%x too long, failing\n", plen); | ||
777 | ret = -EINVAL; | ||
778 | goto bail; | ||
779 | } | ||
780 | |||
781 | /* Get a PIO buffer to use. */ | ||
782 | piobuf = ipath_getpiobuf(dd, NULL); | ||
783 | if (unlikely(piobuf == NULL)) { | ||
784 | ret = -EBUSY; | ||
785 | goto bail; | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * Write len to control qword, no flags. | ||
790 | * We have to flush after the PBC for correctness on some cpus | ||
791 | * or WC buffer can be written out of order. | ||
792 | */ | ||
793 | writeq(plen, piobuf); | ||
794 | ipath_flush_wc(); | ||
795 | piobuf += 2; | ||
796 | if (len == 0) { | ||
797 | /* | ||
798 | * If there is just the header portion, must flush before | ||
799 | * writing last word of header for correctness, and after | ||
800 | * the last header word (trigger word). | ||
801 | */ | ||
802 | __iowrite32_copy(piobuf, hdr, hdrwords - 1); | ||
803 | ipath_flush_wc(); | ||
804 | __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1); | ||
805 | ipath_flush_wc(); | ||
806 | ret = 0; | ||
807 | goto bail; | ||
808 | } | ||
809 | |||
810 | __iowrite32_copy(piobuf, hdr, hdrwords); | ||
811 | piobuf += hdrwords; | ||
812 | |||
813 | /* The common case is aligned and contained in one segment. */ | ||
814 | if (likely(ss->num_sge == 1 && len <= ss->sge.length && | ||
815 | !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) { | ||
816 | u32 w; | ||
817 | u32 *addr = (u32 *) ss->sge.vaddr; | ||
818 | |||
819 | /* Update address before sending packet. */ | ||
820 | update_sge(ss, len); | ||
821 | /* Need to round up for the last dword in the packet. */ | ||
822 | w = (len + 3) >> 2; | ||
823 | __iowrite32_copy(piobuf, addr, w - 1); | ||
824 | /* must flush early everything before trigger word */ | ||
825 | ipath_flush_wc(); | ||
826 | __raw_writel(addr[w - 1], piobuf + w - 1); | ||
827 | /* be sure trigger word is written */ | ||
828 | ipath_flush_wc(); | ||
829 | ret = 0; | ||
830 | goto bail; | ||
831 | } | ||
832 | copy_io(piobuf, ss, len); | ||
833 | ret = 0; | ||
834 | |||
835 | bail: | ||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords, | ||
840 | u64 *rwords, u64 *spkts, u64 *rpkts, | ||
841 | u64 *xmit_wait) | ||
842 | { | ||
843 | int ret; | ||
844 | |||
845 | if (!(dd->ipath_flags & IPATH_INITTED)) { | ||
846 | /* no hardware, freeze, etc. */ | ||
847 | ipath_dbg("unit %u not usable\n", dd->ipath_unit); | ||
848 | ret = -EINVAL; | ||
849 | goto bail; | ||
850 | } | ||
851 | *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); | ||
852 | *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); | ||
853 | *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); | ||
854 | *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); | ||
855 | *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt); | ||
856 | |||
857 | ret = 0; | ||
858 | |||
859 | bail: | ||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | /** | ||
864 | * ipath_get_counters - get various chip counters | ||
865 | * @dd: the infinipath device | ||
866 | * @cntrs: counters are placed here | ||
867 | * | ||
868 | * Return the counters needed by recv_pma_get_portcounters(). | ||
869 | */ | ||
870 | int ipath_get_counters(struct ipath_devdata *dd, | ||
871 | struct ipath_verbs_counters *cntrs) | ||
872 | { | ||
873 | int ret; | ||
874 | |||
875 | if (!(dd->ipath_flags & IPATH_INITTED)) { | ||
876 | /* no hardware, freeze, etc. */ | ||
877 | ipath_dbg("unit %u not usable\n", dd->ipath_unit); | ||
878 | ret = -EINVAL; | ||
879 | goto bail; | ||
880 | } | ||
881 | cntrs->symbol_error_counter = | ||
882 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt); | ||
883 | cntrs->link_error_recovery_counter = | ||
884 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt); | ||
885 | /* | ||
886 | * The link downed counter counts when the other side downs the | ||
887 | * connection. We add in the number of times we downed the link | ||
888 | * due to local link integrity errors to compensate. | ||
889 | */ | ||
890 | cntrs->link_downed_counter = | ||
891 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt); | ||
892 | cntrs->port_rcv_errors = | ||
893 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) + | ||
894 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) + | ||
895 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) + | ||
896 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) + | ||
897 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) + | ||
898 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) + | ||
899 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) + | ||
900 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) + | ||
901 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt); | ||
902 | cntrs->port_rcv_remphys_errors = | ||
903 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt); | ||
904 | cntrs->port_xmit_discards = | ||
905 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt); | ||
906 | cntrs->port_xmit_data = | ||
907 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); | ||
908 | cntrs->port_rcv_data = | ||
909 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); | ||
910 | cntrs->port_xmit_packets = | ||
911 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); | ||
912 | cntrs->port_rcv_packets = | ||
913 | ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); | ||
914 | cntrs->local_link_integrity_errors = dd->ipath_lli_errors; | ||
915 | cntrs->excessive_buffer_overrun_errors = 0; /* XXX */ | ||
916 | |||
917 | ret = 0; | ||
918 | |||
919 | bail: | ||
920 | return ret; | ||
921 | } | ||
922 | |||
584 | /** | 923 | /** |
585 | * ipath_ib_piobufavail - callback when a PIO buffer is available | 924 | * ipath_ib_piobufavail - callback when a PIO buffer is available |
586 | * @arg: the device pointer | 925 | * @arg: the device pointer |
@@ -591,9 +930,8 @@ static void ipath_ib_timer(void *arg) | |||
591 | * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and | 930 | * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and |
592 | * return zero). | 931 | * return zero). |
593 | */ | 932 | */ |
594 | static int ipath_ib_piobufavail(void *arg) | 933 | int ipath_ib_piobufavail(struct ipath_ibdev *dev) |
595 | { | 934 | { |
596 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
597 | struct ipath_qp *qp; | 935 | struct ipath_qp *qp; |
598 | unsigned long flags; | 936 | unsigned long flags; |
599 | 937 | ||
@@ -624,14 +962,14 @@ static int ipath_query_device(struct ib_device *ibdev, | |||
624 | IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT | | 962 | IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT | |
625 | IB_DEVICE_SYS_IMAGE_GUID; | 963 | IB_DEVICE_SYS_IMAGE_GUID; |
626 | props->page_size_cap = PAGE_SIZE; | 964 | props->page_size_cap = PAGE_SIZE; |
627 | props->vendor_id = ipath_layer_get_vendorid(dev->dd); | 965 | props->vendor_id = dev->dd->ipath_vendorid; |
628 | props->vendor_part_id = ipath_layer_get_deviceid(dev->dd); | 966 | props->vendor_part_id = dev->dd->ipath_deviceid; |
629 | props->hw_ver = ipath_layer_get_pcirev(dev->dd); | 967 | props->hw_ver = dev->dd->ipath_pcirev; |
630 | 968 | ||
631 | props->sys_image_guid = dev->sys_image_guid; | 969 | props->sys_image_guid = dev->sys_image_guid; |
632 | 970 | ||
633 | props->max_mr_size = ~0ull; | 971 | props->max_mr_size = ~0ull; |
634 | props->max_qp = dev->qp_table.max; | 972 | props->max_qp = ib_ipath_max_qps; |
635 | props->max_qp_wr = ib_ipath_max_qp_wrs; | 973 | props->max_qp_wr = ib_ipath_max_qp_wrs; |
636 | props->max_sge = ib_ipath_max_sges; | 974 | props->max_sge = ib_ipath_max_sges; |
637 | props->max_cq = ib_ipath_max_cqs; | 975 | props->max_cq = ib_ipath_max_cqs; |
@@ -647,7 +985,7 @@ static int ipath_query_device(struct ib_device *ibdev, | |||
647 | props->max_srq_sge = ib_ipath_max_srq_sges; | 985 | props->max_srq_sge = ib_ipath_max_srq_sges; |
648 | /* props->local_ca_ack_delay */ | 986 | /* props->local_ca_ack_delay */ |
649 | props->atomic_cap = IB_ATOMIC_HCA; | 987 | props->atomic_cap = IB_ATOMIC_HCA; |
650 | props->max_pkeys = ipath_layer_get_npkeys(dev->dd); | 988 | props->max_pkeys = ipath_get_npkeys(dev->dd); |
651 | props->max_mcast_grp = ib_ipath_max_mcast_grps; | 989 | props->max_mcast_grp = ib_ipath_max_mcast_grps; |
652 | props->max_mcast_qp_attach = ib_ipath_max_mcast_qp_attached; | 990 | props->max_mcast_qp_attach = ib_ipath_max_mcast_qp_attached; |
653 | props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * | 991 | props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * |
@@ -672,12 +1010,17 @@ const u8 ipath_cvt_physportstate[16] = { | |||
672 | [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6, | 1010 | [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6, |
673 | }; | 1011 | }; |
674 | 1012 | ||
1013 | u32 ipath_get_cr_errpkey(struct ipath_devdata *dd) | ||
1014 | { | ||
1015 | return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey); | ||
1016 | } | ||
1017 | |||
675 | static int ipath_query_port(struct ib_device *ibdev, | 1018 | static int ipath_query_port(struct ib_device *ibdev, |
676 | u8 port, struct ib_port_attr *props) | 1019 | u8 port, struct ib_port_attr *props) |
677 | { | 1020 | { |
678 | struct ipath_ibdev *dev = to_idev(ibdev); | 1021 | struct ipath_ibdev *dev = to_idev(ibdev); |
679 | enum ib_mtu mtu; | 1022 | enum ib_mtu mtu; |
680 | u16 lid = ipath_layer_get_lid(dev->dd); | 1023 | u16 lid = dev->dd->ipath_lid; |
681 | u64 ibcstat; | 1024 | u64 ibcstat; |
682 | 1025 | ||
683 | memset(props, 0, sizeof(*props)); | 1026 | memset(props, 0, sizeof(*props)); |
@@ -685,16 +1028,16 @@ static int ipath_query_port(struct ib_device *ibdev, | |||
685 | props->lmc = dev->mkeyprot_resv_lmc & 7; | 1028 | props->lmc = dev->mkeyprot_resv_lmc & 7; |
686 | props->sm_lid = dev->sm_lid; | 1029 | props->sm_lid = dev->sm_lid; |
687 | props->sm_sl = dev->sm_sl; | 1030 | props->sm_sl = dev->sm_sl; |
688 | ibcstat = ipath_layer_get_lastibcstat(dev->dd); | 1031 | ibcstat = dev->dd->ipath_lastibcstat; |
689 | props->state = ((ibcstat >> 4) & 0x3) + 1; | 1032 | props->state = ((ibcstat >> 4) & 0x3) + 1; |
690 | /* See phys_state_show() */ | 1033 | /* See phys_state_show() */ |
691 | props->phys_state = ipath_cvt_physportstate[ | 1034 | props->phys_state = ipath_cvt_physportstate[ |
692 | ipath_layer_get_lastibcstat(dev->dd) & 0xf]; | 1035 | dev->dd->ipath_lastibcstat & 0xf]; |
693 | props->port_cap_flags = dev->port_cap_flags; | 1036 | props->port_cap_flags = dev->port_cap_flags; |
694 | props->gid_tbl_len = 1; | 1037 | props->gid_tbl_len = 1; |
695 | props->max_msg_sz = 0x80000000; | 1038 | props->max_msg_sz = 0x80000000; |
696 | props->pkey_tbl_len = ipath_layer_get_npkeys(dev->dd); | 1039 | props->pkey_tbl_len = ipath_get_npkeys(dev->dd); |
697 | props->bad_pkey_cntr = ipath_layer_get_cr_errpkey(dev->dd) - | 1040 | props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) - |
698 | dev->z_pkey_violations; | 1041 | dev->z_pkey_violations; |
699 | props->qkey_viol_cntr = dev->qkey_violations; | 1042 | props->qkey_viol_cntr = dev->qkey_violations; |
700 | props->active_width = IB_WIDTH_4X; | 1043 | props->active_width = IB_WIDTH_4X; |
@@ -704,7 +1047,7 @@ static int ipath_query_port(struct ib_device *ibdev, | |||
704 | props->init_type_reply = 0; | 1047 | props->init_type_reply = 0; |
705 | 1048 | ||
706 | props->max_mtu = IB_MTU_4096; | 1049 | props->max_mtu = IB_MTU_4096; |
707 | switch (ipath_layer_get_ibmtu(dev->dd)) { | 1050 | switch (dev->dd->ipath_ibmtu) { |
708 | case 4096: | 1051 | case 4096: |
709 | mtu = IB_MTU_4096; | 1052 | mtu = IB_MTU_4096; |
710 | break; | 1053 | break; |
@@ -763,7 +1106,7 @@ static int ipath_modify_port(struct ib_device *ibdev, | |||
763 | dev->port_cap_flags |= props->set_port_cap_mask; | 1106 | dev->port_cap_flags |= props->set_port_cap_mask; |
764 | dev->port_cap_flags &= ~props->clr_port_cap_mask; | 1107 | dev->port_cap_flags &= ~props->clr_port_cap_mask; |
765 | if (port_modify_mask & IB_PORT_SHUTDOWN) | 1108 | if (port_modify_mask & IB_PORT_SHUTDOWN) |
766 | ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKDOWN); | 1109 | ipath_set_linkstate(dev->dd, IPATH_IB_LINKDOWN); |
767 | if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR) | 1110 | if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR) |
768 | dev->qkey_violations = 0; | 1111 | dev->qkey_violations = 0; |
769 | return 0; | 1112 | return 0; |
@@ -780,7 +1123,7 @@ static int ipath_query_gid(struct ib_device *ibdev, u8 port, | |||
780 | goto bail; | 1123 | goto bail; |
781 | } | 1124 | } |
782 | gid->global.subnet_prefix = dev->gid_prefix; | 1125 | gid->global.subnet_prefix = dev->gid_prefix; |
783 | gid->global.interface_id = ipath_layer_get_guid(dev->dd); | 1126 | gid->global.interface_id = dev->dd->ipath_guid; |
784 | 1127 | ||
785 | ret = 0; | 1128 | ret = 0; |
786 | 1129 | ||
@@ -803,18 +1146,22 @@ static struct ib_pd *ipath_alloc_pd(struct ib_device *ibdev, | |||
803 | * we allow allocations of more than we report for this value. | 1146 | * we allow allocations of more than we report for this value. |
804 | */ | 1147 | */ |
805 | 1148 | ||
806 | if (dev->n_pds_allocated == ib_ipath_max_pds) { | 1149 | pd = kmalloc(sizeof *pd, GFP_KERNEL); |
1150 | if (!pd) { | ||
807 | ret = ERR_PTR(-ENOMEM); | 1151 | ret = ERR_PTR(-ENOMEM); |
808 | goto bail; | 1152 | goto bail; |
809 | } | 1153 | } |
810 | 1154 | ||
811 | pd = kmalloc(sizeof *pd, GFP_KERNEL); | 1155 | spin_lock(&dev->n_pds_lock); |
812 | if (!pd) { | 1156 | if (dev->n_pds_allocated == ib_ipath_max_pds) { |
1157 | spin_unlock(&dev->n_pds_lock); | ||
1158 | kfree(pd); | ||
813 | ret = ERR_PTR(-ENOMEM); | 1159 | ret = ERR_PTR(-ENOMEM); |
814 | goto bail; | 1160 | goto bail; |
815 | } | 1161 | } |
816 | 1162 | ||
817 | dev->n_pds_allocated++; | 1163 | dev->n_pds_allocated++; |
1164 | spin_unlock(&dev->n_pds_lock); | ||
818 | 1165 | ||
819 | /* ib_alloc_pd() will initialize pd->ibpd. */ | 1166 | /* ib_alloc_pd() will initialize pd->ibpd. */ |
820 | pd->user = udata != NULL; | 1167 | pd->user = udata != NULL; |
@@ -830,7 +1177,9 @@ static int ipath_dealloc_pd(struct ib_pd *ibpd) | |||
830 | struct ipath_pd *pd = to_ipd(ibpd); | 1177 | struct ipath_pd *pd = to_ipd(ibpd); |
831 | struct ipath_ibdev *dev = to_idev(ibpd->device); | 1178 | struct ipath_ibdev *dev = to_idev(ibpd->device); |
832 | 1179 | ||
1180 | spin_lock(&dev->n_pds_lock); | ||
833 | dev->n_pds_allocated--; | 1181 | dev->n_pds_allocated--; |
1182 | spin_unlock(&dev->n_pds_lock); | ||
834 | 1183 | ||
835 | kfree(pd); | 1184 | kfree(pd); |
836 | 1185 | ||
@@ -851,11 +1200,6 @@ static struct ib_ah *ipath_create_ah(struct ib_pd *pd, | |||
851 | struct ib_ah *ret; | 1200 | struct ib_ah *ret; |
852 | struct ipath_ibdev *dev = to_idev(pd->device); | 1201 | struct ipath_ibdev *dev = to_idev(pd->device); |
853 | 1202 | ||
854 | if (dev->n_ahs_allocated == ib_ipath_max_ahs) { | ||
855 | ret = ERR_PTR(-ENOMEM); | ||
856 | goto bail; | ||
857 | } | ||
858 | |||
859 | /* A multicast address requires a GRH (see ch. 8.4.1). */ | 1203 | /* A multicast address requires a GRH (see ch. 8.4.1). */ |
860 | if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE && | 1204 | if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE && |
861 | ah_attr->dlid != IPATH_PERMISSIVE_LID && | 1205 | ah_attr->dlid != IPATH_PERMISSIVE_LID && |
@@ -881,7 +1225,16 @@ static struct ib_ah *ipath_create_ah(struct ib_pd *pd, | |||
881 | goto bail; | 1225 | goto bail; |
882 | } | 1226 | } |
883 | 1227 | ||
1228 | spin_lock(&dev->n_ahs_lock); | ||
1229 | if (dev->n_ahs_allocated == ib_ipath_max_ahs) { | ||
1230 | spin_unlock(&dev->n_ahs_lock); | ||
1231 | kfree(ah); | ||
1232 | ret = ERR_PTR(-ENOMEM); | ||
1233 | goto bail; | ||
1234 | } | ||
1235 | |||
884 | dev->n_ahs_allocated++; | 1236 | dev->n_ahs_allocated++; |
1237 | spin_unlock(&dev->n_ahs_lock); | ||
885 | 1238 | ||
886 | /* ib_create_ah() will initialize ah->ibah. */ | 1239 | /* ib_create_ah() will initialize ah->ibah. */ |
887 | ah->attr = *ah_attr; | 1240 | ah->attr = *ah_attr; |
@@ -903,7 +1256,9 @@ static int ipath_destroy_ah(struct ib_ah *ibah) | |||
903 | struct ipath_ibdev *dev = to_idev(ibah->device); | 1256 | struct ipath_ibdev *dev = to_idev(ibah->device); |
904 | struct ipath_ah *ah = to_iah(ibah); | 1257 | struct ipath_ah *ah = to_iah(ibah); |
905 | 1258 | ||
1259 | spin_lock(&dev->n_ahs_lock); | ||
906 | dev->n_ahs_allocated--; | 1260 | dev->n_ahs_allocated--; |
1261 | spin_unlock(&dev->n_ahs_lock); | ||
907 | 1262 | ||
908 | kfree(ah); | 1263 | kfree(ah); |
909 | 1264 | ||
@@ -919,25 +1274,50 @@ static int ipath_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) | |||
919 | return 0; | 1274 | return 0; |
920 | } | 1275 | } |
921 | 1276 | ||
1277 | /** | ||
1278 | * ipath_get_npkeys - return the size of the PKEY table for port 0 | ||
1279 | * @dd: the infinipath device | ||
1280 | */ | ||
1281 | unsigned ipath_get_npkeys(struct ipath_devdata *dd) | ||
1282 | { | ||
1283 | return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys); | ||
1284 | } | ||
1285 | |||
1286 | /** | ||
1287 | * ipath_get_pkey - return the indexed PKEY from the port 0 PKEY table | ||
1288 | * @dd: the infinipath device | ||
1289 | * @index: the PKEY index | ||
1290 | */ | ||
1291 | unsigned ipath_get_pkey(struct ipath_devdata *dd, unsigned index) | ||
1292 | { | ||
1293 | unsigned ret; | ||
1294 | |||
1295 | if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys)) | ||
1296 | ret = 0; | ||
1297 | else | ||
1298 | ret = dd->ipath_pd[0]->port_pkeys[index]; | ||
1299 | |||
1300 | return ret; | ||
1301 | } | ||
1302 | |||
922 | static int ipath_query_pkey(struct ib_device *ibdev, u8 port, u16 index, | 1303 | static int ipath_query_pkey(struct ib_device *ibdev, u8 port, u16 index, |
923 | u16 *pkey) | 1304 | u16 *pkey) |
924 | { | 1305 | { |
925 | struct ipath_ibdev *dev = to_idev(ibdev); | 1306 | struct ipath_ibdev *dev = to_idev(ibdev); |
926 | int ret; | 1307 | int ret; |
927 | 1308 | ||
928 | if (index >= ipath_layer_get_npkeys(dev->dd)) { | 1309 | if (index >= ipath_get_npkeys(dev->dd)) { |
929 | ret = -EINVAL; | 1310 | ret = -EINVAL; |
930 | goto bail; | 1311 | goto bail; |
931 | } | 1312 | } |
932 | 1313 | ||
933 | *pkey = ipath_layer_get_pkey(dev->dd, index); | 1314 | *pkey = ipath_get_pkey(dev->dd, index); |
934 | ret = 0; | 1315 | ret = 0; |
935 | 1316 | ||
936 | bail: | 1317 | bail: |
937 | return ret; | 1318 | return ret; |
938 | } | 1319 | } |
939 | 1320 | ||
940 | |||
941 | /** | 1321 | /** |
942 | * ipath_alloc_ucontext - allocate a ucontest | 1322 | * ipath_alloc_ucontext - allocate a ucontest |
943 | * @ibdev: the infiniband device | 1323 | * @ibdev: the infiniband device |
@@ -970,26 +1350,91 @@ static int ipath_dealloc_ucontext(struct ib_ucontext *context) | |||
970 | 1350 | ||
971 | static int ipath_verbs_register_sysfs(struct ib_device *dev); | 1351 | static int ipath_verbs_register_sysfs(struct ib_device *dev); |
972 | 1352 | ||
1353 | static void __verbs_timer(unsigned long arg) | ||
1354 | { | ||
1355 | struct ipath_devdata *dd = (struct ipath_devdata *) arg; | ||
1356 | |||
1357 | /* | ||
1358 | * If port 0 receive packet interrupts are not available, or | ||
1359 | * can be missed, poll the receive queue | ||
1360 | */ | ||
1361 | if (dd->ipath_flags & IPATH_POLL_RX_INTR) | ||
1362 | ipath_kreceive(dd); | ||
1363 | |||
1364 | /* Handle verbs layer timeouts. */ | ||
1365 | ipath_ib_timer(dd->verbs_dev); | ||
1366 | |||
1367 | mod_timer(&dd->verbs_timer, jiffies + 1); | ||
1368 | } | ||
1369 | |||
1370 | static int enable_timer(struct ipath_devdata *dd) | ||
1371 | { | ||
1372 | /* | ||
1373 | * Early chips had a design flaw where the chip and kernel idea | ||
1374 | * of the tail register don't always agree, and therefore we won't | ||
1375 | * get an interrupt on the next packet received. | ||
1376 | * If the board supports per packet receive interrupts, use it. | ||
1377 | * Otherwise, the timer function periodically checks for packets | ||
1378 | * to cover this case. | ||
1379 | * Either way, the timer is needed for verbs layer related | ||
1380 | * processing. | ||
1381 | */ | ||
1382 | if (dd->ipath_flags & IPATH_GPIO_INTR) { | ||
1383 | ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect, | ||
1384 | 0x2074076542310ULL); | ||
1385 | /* Enable GPIO bit 2 interrupt */ | ||
1386 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, | ||
1387 | (u64) (1 << 2)); | ||
1388 | } | ||
1389 | |||
1390 | init_timer(&dd->verbs_timer); | ||
1391 | dd->verbs_timer.function = __verbs_timer; | ||
1392 | dd->verbs_timer.data = (unsigned long)dd; | ||
1393 | dd->verbs_timer.expires = jiffies + 1; | ||
1394 | add_timer(&dd->verbs_timer); | ||
1395 | |||
1396 | return 0; | ||
1397 | } | ||
1398 | |||
1399 | static int disable_timer(struct ipath_devdata *dd) | ||
1400 | { | ||
1401 | /* Disable GPIO bit 2 interrupt */ | ||
1402 | if (dd->ipath_flags & IPATH_GPIO_INTR) | ||
1403 | ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, 0); | ||
1404 | |||
1405 | del_timer_sync(&dd->verbs_timer); | ||
1406 | |||
1407 | return 0; | ||
1408 | } | ||
1409 | |||
973 | /** | 1410 | /** |
974 | * ipath_register_ib_device - register our device with the infiniband core | 1411 | * ipath_register_ib_device - register our device with the infiniband core |
975 | * @unit: the device number to register | ||
976 | * @dd: the device data structure | 1412 | * @dd: the device data structure |
977 | * Return the allocated ipath_ibdev pointer or NULL on error. | 1413 | * Return the allocated ipath_ibdev pointer or NULL on error. |
978 | */ | 1414 | */ |
979 | static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) | 1415 | int ipath_register_ib_device(struct ipath_devdata *dd) |
980 | { | 1416 | { |
981 | struct ipath_layer_counters cntrs; | 1417 | struct ipath_verbs_counters cntrs; |
982 | struct ipath_ibdev *idev; | 1418 | struct ipath_ibdev *idev; |
983 | struct ib_device *dev; | 1419 | struct ib_device *dev; |
984 | int ret; | 1420 | int ret; |
985 | 1421 | ||
986 | idev = (struct ipath_ibdev *)ib_alloc_device(sizeof *idev); | 1422 | idev = (struct ipath_ibdev *)ib_alloc_device(sizeof *idev); |
987 | if (idev == NULL) | 1423 | if (idev == NULL) { |
1424 | ret = -ENOMEM; | ||
988 | goto bail; | 1425 | goto bail; |
1426 | } | ||
989 | 1427 | ||
990 | dev = &idev->ibdev; | 1428 | dev = &idev->ibdev; |
991 | 1429 | ||
992 | /* Only need to initialize non-zero fields. */ | 1430 | /* Only need to initialize non-zero fields. */ |
1431 | spin_lock_init(&idev->n_pds_lock); | ||
1432 | spin_lock_init(&idev->n_ahs_lock); | ||
1433 | spin_lock_init(&idev->n_cqs_lock); | ||
1434 | spin_lock_init(&idev->n_qps_lock); | ||
1435 | spin_lock_init(&idev->n_srqs_lock); | ||
1436 | spin_lock_init(&idev->n_mcast_grps_lock); | ||
1437 | |||
993 | spin_lock_init(&idev->qp_table.lock); | 1438 | spin_lock_init(&idev->qp_table.lock); |
994 | spin_lock_init(&idev->lk_table.lock); | 1439 | spin_lock_init(&idev->lk_table.lock); |
995 | idev->sm_lid = __constant_be16_to_cpu(IB_LID_PERMISSIVE); | 1440 | idev->sm_lid = __constant_be16_to_cpu(IB_LID_PERMISSIVE); |
@@ -1030,7 +1475,7 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) | |||
1030 | idev->link_width_enabled = 3; /* 1x or 4x */ | 1475 | idev->link_width_enabled = 3; /* 1x or 4x */ |
1031 | 1476 | ||
1032 | /* Snapshot current HW counters to "clear" them. */ | 1477 | /* Snapshot current HW counters to "clear" them. */ |
1033 | ipath_layer_get_counters(dd, &cntrs); | 1478 | ipath_get_counters(dd, &cntrs); |
1034 | idev->z_symbol_error_counter = cntrs.symbol_error_counter; | 1479 | idev->z_symbol_error_counter = cntrs.symbol_error_counter; |
1035 | idev->z_link_error_recovery_counter = | 1480 | idev->z_link_error_recovery_counter = |
1036 | cntrs.link_error_recovery_counter; | 1481 | cntrs.link_error_recovery_counter; |
@@ -1054,14 +1499,14 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) | |||
1054 | * device types in the system, we can't be sure this is unique. | 1499 | * device types in the system, we can't be sure this is unique. |
1055 | */ | 1500 | */ |
1056 | if (!sys_image_guid) | 1501 | if (!sys_image_guid) |
1057 | sys_image_guid = ipath_layer_get_guid(dd); | 1502 | sys_image_guid = dd->ipath_guid; |
1058 | idev->sys_image_guid = sys_image_guid; | 1503 | idev->sys_image_guid = sys_image_guid; |
1059 | idev->ib_unit = unit; | 1504 | idev->ib_unit = dd->ipath_unit; |
1060 | idev->dd = dd; | 1505 | idev->dd = dd; |
1061 | 1506 | ||
1062 | strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX); | 1507 | strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX); |
1063 | dev->owner = THIS_MODULE; | 1508 | dev->owner = THIS_MODULE; |
1064 | dev->node_guid = ipath_layer_get_guid(dd); | 1509 | dev->node_guid = dd->ipath_guid; |
1065 | dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION; | 1510 | dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION; |
1066 | dev->uverbs_cmd_mask = | 1511 | dev->uverbs_cmd_mask = |
1067 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | | 1512 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | |
@@ -1093,9 +1538,9 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) | |||
1093 | (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | | 1538 | (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | |
1094 | (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | | 1539 | (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | |
1095 | (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV); | 1540 | (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV); |
1096 | dev->node_type = IB_NODE_CA; | 1541 | dev->node_type = RDMA_NODE_IB_CA; |
1097 | dev->phys_port_cnt = 1; | 1542 | dev->phys_port_cnt = 1; |
1098 | dev->dma_device = ipath_layer_get_device(dd); | 1543 | dev->dma_device = &dd->pcidev->dev; |
1099 | dev->class_dev.dev = dev->dma_device; | 1544 | dev->class_dev.dev = dev->dma_device; |
1100 | dev->query_device = ipath_query_device; | 1545 | dev->query_device = ipath_query_device; |
1101 | dev->modify_device = ipath_modify_device; | 1546 | dev->modify_device = ipath_modify_device; |
@@ -1137,9 +1582,10 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) | |||
1137 | dev->attach_mcast = ipath_multicast_attach; | 1582 | dev->attach_mcast = ipath_multicast_attach; |
1138 | dev->detach_mcast = ipath_multicast_detach; | 1583 | dev->detach_mcast = ipath_multicast_detach; |
1139 | dev->process_mad = ipath_process_mad; | 1584 | dev->process_mad = ipath_process_mad; |
1585 | dev->mmap = ipath_mmap; | ||
1140 | 1586 | ||
1141 | snprintf(dev->node_desc, sizeof(dev->node_desc), | 1587 | snprintf(dev->node_desc, sizeof(dev->node_desc), |
1142 | IPATH_IDSTR " %s kernel_SMA", system_utsname.nodename); | 1588 | IPATH_IDSTR " %s", system_utsname.nodename); |
1143 | 1589 | ||
1144 | ret = ib_register_device(dev); | 1590 | ret = ib_register_device(dev); |
1145 | if (ret) | 1591 | if (ret) |
@@ -1148,7 +1594,7 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) | |||
1148 | if (ipath_verbs_register_sysfs(dev)) | 1594 | if (ipath_verbs_register_sysfs(dev)) |
1149 | goto err_class; | 1595 | goto err_class; |
1150 | 1596 | ||
1151 | ipath_layer_enable_timer(dd); | 1597 | enable_timer(dd); |
1152 | 1598 | ||
1153 | goto bail; | 1599 | goto bail; |
1154 | 1600 | ||
@@ -1160,37 +1606,32 @@ err_lk: | |||
1160 | kfree(idev->qp_table.table); | 1606 | kfree(idev->qp_table.table); |
1161 | err_qp: | 1607 | err_qp: |
1162 | ib_dealloc_device(dev); | 1608 | ib_dealloc_device(dev); |
1163 | _VERBS_ERROR("ib_ipath%d cannot register verbs (%d)!\n", | 1609 | ipath_dev_err(dd, "cannot register verbs: %d!\n", -ret); |
1164 | unit, -ret); | ||
1165 | idev = NULL; | 1610 | idev = NULL; |
1166 | 1611 | ||
1167 | bail: | 1612 | bail: |
1168 | return idev; | 1613 | dd->verbs_dev = idev; |
1614 | return ret; | ||
1169 | } | 1615 | } |
1170 | 1616 | ||
1171 | static void ipath_unregister_ib_device(void *arg) | 1617 | void ipath_unregister_ib_device(struct ipath_ibdev *dev) |
1172 | { | 1618 | { |
1173 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
1174 | struct ib_device *ibdev = &dev->ibdev; | 1619 | struct ib_device *ibdev = &dev->ibdev; |
1175 | 1620 | ||
1176 | ipath_layer_disable_timer(dev->dd); | 1621 | disable_timer(dev->dd); |
1177 | 1622 | ||
1178 | ib_unregister_device(ibdev); | 1623 | ib_unregister_device(ibdev); |
1179 | 1624 | ||
1180 | if (!list_empty(&dev->pending[0]) || | 1625 | if (!list_empty(&dev->pending[0]) || |
1181 | !list_empty(&dev->pending[1]) || | 1626 | !list_empty(&dev->pending[1]) || |
1182 | !list_empty(&dev->pending[2])) | 1627 | !list_empty(&dev->pending[2])) |
1183 | _VERBS_ERROR("ipath%d pending list not empty!\n", | 1628 | ipath_dev_err(dev->dd, "pending list not empty!\n"); |
1184 | dev->ib_unit); | ||
1185 | if (!list_empty(&dev->piowait)) | 1629 | if (!list_empty(&dev->piowait)) |
1186 | _VERBS_ERROR("ipath%d piowait list not empty!\n", | 1630 | ipath_dev_err(dev->dd, "piowait list not empty!\n"); |
1187 | dev->ib_unit); | ||
1188 | if (!list_empty(&dev->rnrwait)) | 1631 | if (!list_empty(&dev->rnrwait)) |
1189 | _VERBS_ERROR("ipath%d rnrwait list not empty!\n", | 1632 | ipath_dev_err(dev->dd, "rnrwait list not empty!\n"); |
1190 | dev->ib_unit); | ||
1191 | if (!ipath_mcast_tree_empty()) | 1633 | if (!ipath_mcast_tree_empty()) |
1192 | _VERBS_ERROR("ipath%d multicast table memory leak!\n", | 1634 | ipath_dev_err(dev->dd, "multicast table memory leak!\n"); |
1193 | dev->ib_unit); | ||
1194 | /* | 1635 | /* |
1195 | * Note that ipath_unregister_ib_device() can be called before all | 1636 | * Note that ipath_unregister_ib_device() can be called before all |
1196 | * the QPs are destroyed! | 1637 | * the QPs are destroyed! |
@@ -1201,25 +1642,12 @@ static void ipath_unregister_ib_device(void *arg) | |||
1201 | ib_dealloc_device(ibdev); | 1642 | ib_dealloc_device(ibdev); |
1202 | } | 1643 | } |
1203 | 1644 | ||
1204 | static int __init ipath_verbs_init(void) | ||
1205 | { | ||
1206 | return ipath_verbs_register(ipath_register_ib_device, | ||
1207 | ipath_unregister_ib_device, | ||
1208 | ipath_ib_piobufavail, ipath_ib_rcv, | ||
1209 | ipath_ib_timer); | ||
1210 | } | ||
1211 | |||
1212 | static void __exit ipath_verbs_cleanup(void) | ||
1213 | { | ||
1214 | ipath_verbs_unregister(); | ||
1215 | } | ||
1216 | |||
1217 | static ssize_t show_rev(struct class_device *cdev, char *buf) | 1645 | static ssize_t show_rev(struct class_device *cdev, char *buf) |
1218 | { | 1646 | { |
1219 | struct ipath_ibdev *dev = | 1647 | struct ipath_ibdev *dev = |
1220 | container_of(cdev, struct ipath_ibdev, ibdev.class_dev); | 1648 | container_of(cdev, struct ipath_ibdev, ibdev.class_dev); |
1221 | 1649 | ||
1222 | return sprintf(buf, "%x\n", ipath_layer_get_pcirev(dev->dd)); | 1650 | return sprintf(buf, "%x\n", dev->dd->ipath_pcirev); |
1223 | } | 1651 | } |
1224 | 1652 | ||
1225 | static ssize_t show_hca(struct class_device *cdev, char *buf) | 1653 | static ssize_t show_hca(struct class_device *cdev, char *buf) |
@@ -1228,7 +1656,7 @@ static ssize_t show_hca(struct class_device *cdev, char *buf) | |||
1228 | container_of(cdev, struct ipath_ibdev, ibdev.class_dev); | 1656 | container_of(cdev, struct ipath_ibdev, ibdev.class_dev); |
1229 | int ret; | 1657 | int ret; |
1230 | 1658 | ||
1231 | ret = ipath_layer_get_boardname(dev->dd, buf, 128); | 1659 | ret = dev->dd->ipath_f_get_boardname(dev->dd, buf, 128); |
1232 | if (ret < 0) | 1660 | if (ret < 0) |
1233 | goto bail; | 1661 | goto bail; |
1234 | strcat(buf, "\n"); | 1662 | strcat(buf, "\n"); |
@@ -1305,6 +1733,3 @@ static int ipath_verbs_register_sysfs(struct ib_device *dev) | |||
1305 | bail: | 1733 | bail: |
1306 | return ret; | 1734 | return ret; |
1307 | } | 1735 | } |
1308 | |||
1309 | module_init(ipath_verbs_init); | ||
1310 | module_exit(ipath_verbs_cleanup); | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 2df684727dc1..09bbb3f9a217 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h | |||
@@ -38,10 +38,10 @@ | |||
38 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
39 | #include <linux/kernel.h> | 39 | #include <linux/kernel.h> |
40 | #include <linux/interrupt.h> | 40 | #include <linux/interrupt.h> |
41 | #include <linux/kref.h> | ||
41 | #include <rdma/ib_pack.h> | 42 | #include <rdma/ib_pack.h> |
42 | 43 | ||
43 | #include "ipath_layer.h" | 44 | #include "ipath_layer.h" |
44 | #include "verbs_debug.h" | ||
45 | 45 | ||
46 | #define QPN_MAX (1 << 24) | 46 | #define QPN_MAX (1 << 24) |
47 | #define QPNMAP_ENTRIES (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE) | 47 | #define QPNMAP_ENTRIES (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE) |
@@ -50,7 +50,7 @@ | |||
50 | * Increment this value if any changes that break userspace ABI | 50 | * Increment this value if any changes that break userspace ABI |
51 | * compatibility are made. | 51 | * compatibility are made. |
52 | */ | 52 | */ |
53 | #define IPATH_UVERBS_ABI_VERSION 1 | 53 | #define IPATH_UVERBS_ABI_VERSION 2 |
54 | 54 | ||
55 | /* | 55 | /* |
56 | * Define an ib_cq_notify value that is not valid so we know when CQ | 56 | * Define an ib_cq_notify value that is not valid so we know when CQ |
@@ -152,19 +152,6 @@ struct ipath_mcast { | |||
152 | int n_attached; | 152 | int n_attached; |
153 | }; | 153 | }; |
154 | 154 | ||
155 | /* Memory region */ | ||
156 | struct ipath_mr { | ||
157 | struct ib_mr ibmr; | ||
158 | struct ipath_mregion mr; /* must be last */ | ||
159 | }; | ||
160 | |||
161 | /* Fast memory region */ | ||
162 | struct ipath_fmr { | ||
163 | struct ib_fmr ibfmr; | ||
164 | u8 page_shift; | ||
165 | struct ipath_mregion mr; /* must be last */ | ||
166 | }; | ||
167 | |||
168 | /* Protection domain */ | 155 | /* Protection domain */ |
169 | struct ipath_pd { | 156 | struct ipath_pd { |
170 | struct ib_pd ibpd; | 157 | struct ib_pd ibpd; |
@@ -178,58 +165,89 @@ struct ipath_ah { | |||
178 | }; | 165 | }; |
179 | 166 | ||
180 | /* | 167 | /* |
181 | * Quick description of our CQ/QP locking scheme: | 168 | * This structure is used by ipath_mmap() to validate an offset |
182 | * | 169 | * when an mmap() request is made. The vm_area_struct then uses |
183 | * We have one global lock that protects dev->cq/qp_table. Each | 170 | * this as its vm_private_data. |
184 | * struct ipath_cq/qp also has its own lock. An individual qp lock | 171 | */ |
185 | * may be taken inside of an individual cq lock. Both cqs attached to | 172 | struct ipath_mmap_info { |
186 | * a qp may be locked, with the send cq locked first. No other | 173 | struct ipath_mmap_info *next; |
187 | * nesting should be done. | 174 | struct ib_ucontext *context; |
188 | * | 175 | void *obj; |
189 | * Each struct ipath_cq/qp also has an atomic_t ref count. The | 176 | struct kref ref; |
190 | * pointer from the cq/qp_table to the struct counts as one reference. | 177 | unsigned size; |
191 | * This reference also is good for access through the consumer API, so | 178 | unsigned mmap_cnt; |
192 | * modifying the CQ/QP etc doesn't need to take another reference. | 179 | }; |
193 | * Access because of a completion being polled does need a reference. | 180 | |
194 | * | 181 | /* |
195 | * Finally, each struct ipath_cq/qp has a wait_queue_head_t for the | 182 | * This structure is used to contain the head pointer, tail pointer, |
196 | * destroy function to sleep on. | 183 | * and completion queue entries as a single memory allocation so |
197 | * | 184 | * it can be mmap'ed into user space. |
198 | * This means that access from the consumer API requires nothing but | ||
199 | * taking the struct's lock. | ||
200 | * | ||
201 | * Access because of a completion event should go as follows: | ||
202 | * - lock cq/qp_table and look up struct | ||
203 | * - increment ref count in struct | ||
204 | * - drop cq/qp_table lock | ||
205 | * - lock struct, do your thing, and unlock struct | ||
206 | * - decrement ref count; if zero, wake up waiters | ||
207 | * | ||
208 | * To destroy a CQ/QP, we can do the following: | ||
209 | * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock | ||
210 | * - decrement ref count | ||
211 | * - wait_event until ref count is zero | ||
212 | * | ||
213 | * It is the consumer's responsibilty to make sure that no QP | ||
214 | * operations (WQE posting or state modification) are pending when the | ||
215 | * QP is destroyed. Also, the consumer must make sure that calls to | ||
216 | * qp_modify are serialized. | ||
217 | * | ||
218 | * Possible optimizations (wait for profile data to see if/where we | ||
219 | * have locks bouncing between CPUs): | ||
220 | * - split cq/qp table lock into n separate (cache-aligned) locks, | ||
221 | * indexed (say) by the page in the table | ||
222 | */ | 185 | */ |
186 | struct ipath_cq_wc { | ||
187 | u32 head; /* index of next entry to fill */ | ||
188 | u32 tail; /* index of next ib_poll_cq() entry */ | ||
189 | struct ib_wc queue[1]; /* this is actually size ibcq.cqe + 1 */ | ||
190 | }; | ||
223 | 191 | ||
192 | /* | ||
193 | * The completion queue structure. | ||
194 | */ | ||
224 | struct ipath_cq { | 195 | struct ipath_cq { |
225 | struct ib_cq ibcq; | 196 | struct ib_cq ibcq; |
226 | struct tasklet_struct comptask; | 197 | struct tasklet_struct comptask; |
227 | spinlock_t lock; | 198 | spinlock_t lock; |
228 | u8 notify; | 199 | u8 notify; |
229 | u8 triggered; | 200 | u8 triggered; |
230 | u32 head; /* new records added to the head */ | 201 | struct ipath_cq_wc *queue; |
231 | u32 tail; /* poll_cq() reads from here. */ | 202 | struct ipath_mmap_info *ip; |
232 | struct ib_wc *queue; /* this is actually ibcq.cqe + 1 */ | 203 | }; |
204 | |||
205 | /* | ||
206 | * A segment is a linear region of low physical memory. | ||
207 | * XXX Maybe we should use phys addr here and kmap()/kunmap(). | ||
208 | * Used by the verbs layer. | ||
209 | */ | ||
210 | struct ipath_seg { | ||
211 | void *vaddr; | ||
212 | size_t length; | ||
213 | }; | ||
214 | |||
215 | /* The number of ipath_segs that fit in a page. */ | ||
216 | #define IPATH_SEGSZ (PAGE_SIZE / sizeof (struct ipath_seg)) | ||
217 | |||
218 | struct ipath_segarray { | ||
219 | struct ipath_seg segs[IPATH_SEGSZ]; | ||
220 | }; | ||
221 | |||
222 | struct ipath_mregion { | ||
223 | u64 user_base; /* User's address for this region */ | ||
224 | u64 iova; /* IB start address of this region */ | ||
225 | size_t length; | ||
226 | u32 lkey; | ||
227 | u32 offset; /* offset (bytes) to start of region */ | ||
228 | int access_flags; | ||
229 | u32 max_segs; /* number of ipath_segs in all the arrays */ | ||
230 | u32 mapsz; /* size of the map array */ | ||
231 | struct ipath_segarray *map[0]; /* the segments */ | ||
232 | }; | ||
233 | |||
234 | /* | ||
235 | * These keep track of the copy progress within a memory region. | ||
236 | * Used by the verbs layer. | ||
237 | */ | ||
238 | struct ipath_sge { | ||
239 | struct ipath_mregion *mr; | ||
240 | void *vaddr; /* current pointer into the segment */ | ||
241 | u32 sge_length; /* length of the SGE */ | ||
242 | u32 length; /* remaining length of the segment */ | ||
243 | u16 m; /* current index: mr->map[m] */ | ||
244 | u16 n; /* current index: mr->map[m]->segs[n] */ | ||
245 | }; | ||
246 | |||
247 | /* Memory region */ | ||
248 | struct ipath_mr { | ||
249 | struct ib_mr ibmr; | ||
250 | struct ipath_mregion mr; /* must be last */ | ||
233 | }; | 251 | }; |
234 | 252 | ||
235 | /* | 253 | /* |
@@ -248,32 +266,50 @@ struct ipath_swqe { | |||
248 | 266 | ||
249 | /* | 267 | /* |
250 | * Receive work request queue entry. | 268 | * Receive work request queue entry. |
251 | * The size of the sg_list is determined when the QP is created and stored | 269 | * The size of the sg_list is determined when the QP (or SRQ) is created |
252 | * in qp->r_max_sge. | 270 | * and stored in qp->r_rq.max_sge (or srq->rq.max_sge). |
253 | */ | 271 | */ |
254 | struct ipath_rwqe { | 272 | struct ipath_rwqe { |
255 | u64 wr_id; | 273 | u64 wr_id; |
256 | u32 length; /* total length of data in sg_list */ | ||
257 | u8 num_sge; | 274 | u8 num_sge; |
258 | struct ipath_sge sg_list[0]; | 275 | struct ib_sge sg_list[0]; |
259 | }; | 276 | }; |
260 | 277 | ||
261 | struct ipath_rq { | 278 | /* |
262 | spinlock_t lock; | 279 | * This structure is used to contain the head pointer, tail pointer, |
280 | * and receive work queue entries as a single memory allocation so | ||
281 | * it can be mmap'ed into user space. | ||
282 | * Note that the wq array elements are variable size so you can't | ||
283 | * just index into the array to get the N'th element; | ||
284 | * use get_rwqe_ptr() instead. | ||
285 | */ | ||
286 | struct ipath_rwq { | ||
263 | u32 head; /* new work requests posted to the head */ | 287 | u32 head; /* new work requests posted to the head */ |
264 | u32 tail; /* receives pull requests from here. */ | 288 | u32 tail; /* receives pull requests from here. */ |
289 | struct ipath_rwqe wq[0]; | ||
290 | }; | ||
291 | |||
292 | struct ipath_rq { | ||
293 | struct ipath_rwq *wq; | ||
294 | spinlock_t lock; | ||
265 | u32 size; /* size of RWQE array */ | 295 | u32 size; /* size of RWQE array */ |
266 | u8 max_sge; | 296 | u8 max_sge; |
267 | struct ipath_rwqe *wq; /* RWQE array */ | ||
268 | }; | 297 | }; |
269 | 298 | ||
270 | struct ipath_srq { | 299 | struct ipath_srq { |
271 | struct ib_srq ibsrq; | 300 | struct ib_srq ibsrq; |
272 | struct ipath_rq rq; | 301 | struct ipath_rq rq; |
302 | struct ipath_mmap_info *ip; | ||
273 | /* send signal when number of RWQEs < limit */ | 303 | /* send signal when number of RWQEs < limit */ |
274 | u32 limit; | 304 | u32 limit; |
275 | }; | 305 | }; |
276 | 306 | ||
307 | struct ipath_sge_state { | ||
308 | struct ipath_sge *sg_list; /* next SGE to be used if any */ | ||
309 | struct ipath_sge sge; /* progress state for the current SGE */ | ||
310 | u8 num_sge; | ||
311 | }; | ||
312 | |||
277 | /* | 313 | /* |
278 | * Variables prefixed with s_ are for the requester (sender). | 314 | * Variables prefixed with s_ are for the requester (sender). |
279 | * Variables prefixed with r_ are for the responder (receiver). | 315 | * Variables prefixed with r_ are for the responder (receiver). |
@@ -293,6 +329,7 @@ struct ipath_qp { | |||
293 | atomic_t refcount; | 329 | atomic_t refcount; |
294 | wait_queue_head_t wait; | 330 | wait_queue_head_t wait; |
295 | struct tasklet_struct s_task; | 331 | struct tasklet_struct s_task; |
332 | struct ipath_mmap_info *ip; | ||
296 | struct ipath_sge_state *s_cur_sge; | 333 | struct ipath_sge_state *s_cur_sge; |
297 | struct ipath_sge_state s_sge; /* current send request data */ | 334 | struct ipath_sge_state s_sge; /* current send request data */ |
298 | /* current RDMA read send data */ | 335 | /* current RDMA read send data */ |
@@ -334,6 +371,7 @@ struct ipath_qp { | |||
334 | u8 s_retry; /* requester retry counter */ | 371 | u8 s_retry; /* requester retry counter */ |
335 | u8 s_rnr_retry; /* requester RNR retry counter */ | 372 | u8 s_rnr_retry; /* requester RNR retry counter */ |
336 | u8 s_pkey_index; /* PKEY index to use */ | 373 | u8 s_pkey_index; /* PKEY index to use */ |
374 | u8 timeout; /* Timeout for this QP */ | ||
337 | enum ib_mtu path_mtu; | 375 | enum ib_mtu path_mtu; |
338 | u32 remote_qpn; | 376 | u32 remote_qpn; |
339 | u32 qkey; /* QKEY for this QP (for UD or RD) */ | 377 | u32 qkey; /* QKEY for this QP (for UD or RD) */ |
@@ -345,7 +383,8 @@ struct ipath_qp { | |||
345 | u32 s_ssn; /* SSN of tail entry */ | 383 | u32 s_ssn; /* SSN of tail entry */ |
346 | u32 s_lsn; /* limit sequence number (credit) */ | 384 | u32 s_lsn; /* limit sequence number (credit) */ |
347 | struct ipath_swqe *s_wq; /* send work queue */ | 385 | struct ipath_swqe *s_wq; /* send work queue */ |
348 | struct ipath_rq r_rq; /* receive work queue */ | 386 | struct ipath_rq r_rq; /* receive work queue */ |
387 | struct ipath_sge r_sg_list[0]; /* verified SGEs */ | ||
349 | }; | 388 | }; |
350 | 389 | ||
351 | /* | 390 | /* |
@@ -369,15 +408,15 @@ static inline struct ipath_swqe *get_swqe_ptr(struct ipath_qp *qp, | |||
369 | 408 | ||
370 | /* | 409 | /* |
371 | * Since struct ipath_rwqe is not a fixed size, we can't simply index into | 410 | * Since struct ipath_rwqe is not a fixed size, we can't simply index into |
372 | * struct ipath_rq.wq. This function does the array index computation. | 411 | * struct ipath_rwq.wq. This function does the array index computation. |
373 | */ | 412 | */ |
374 | static inline struct ipath_rwqe *get_rwqe_ptr(struct ipath_rq *rq, | 413 | static inline struct ipath_rwqe *get_rwqe_ptr(struct ipath_rq *rq, |
375 | unsigned n) | 414 | unsigned n) |
376 | { | 415 | { |
377 | return (struct ipath_rwqe *) | 416 | return (struct ipath_rwqe *) |
378 | ((char *) rq->wq + | 417 | ((char *) rq->wq->wq + |
379 | (sizeof(struct ipath_rwqe) + | 418 | (sizeof(struct ipath_rwqe) + |
380 | rq->max_sge * sizeof(struct ipath_sge)) * n); | 419 | rq->max_sge * sizeof(struct ib_sge)) * n); |
381 | } | 420 | } |
382 | 421 | ||
383 | /* | 422 | /* |
@@ -417,6 +456,7 @@ struct ipath_ibdev { | |||
417 | struct ib_device ibdev; | 456 | struct ib_device ibdev; |
418 | struct list_head dev_list; | 457 | struct list_head dev_list; |
419 | struct ipath_devdata *dd; | 458 | struct ipath_devdata *dd; |
459 | struct ipath_mmap_info *pending_mmaps; | ||
420 | int ib_unit; /* This is the device number */ | 460 | int ib_unit; /* This is the device number */ |
421 | u16 sm_lid; /* in host order */ | 461 | u16 sm_lid; /* in host order */ |
422 | u8 sm_sl; | 462 | u8 sm_sl; |
@@ -435,11 +475,20 @@ struct ipath_ibdev { | |||
435 | __be64 sys_image_guid; /* in network order */ | 475 | __be64 sys_image_guid; /* in network order */ |
436 | __be64 gid_prefix; /* in network order */ | 476 | __be64 gid_prefix; /* in network order */ |
437 | __be64 mkey; | 477 | __be64 mkey; |
478 | |||
438 | u32 n_pds_allocated; /* number of PDs allocated for device */ | 479 | u32 n_pds_allocated; /* number of PDs allocated for device */ |
480 | spinlock_t n_pds_lock; | ||
439 | u32 n_ahs_allocated; /* number of AHs allocated for device */ | 481 | u32 n_ahs_allocated; /* number of AHs allocated for device */ |
482 | spinlock_t n_ahs_lock; | ||
440 | u32 n_cqs_allocated; /* number of CQs allocated for device */ | 483 | u32 n_cqs_allocated; /* number of CQs allocated for device */ |
484 | spinlock_t n_cqs_lock; | ||
485 | u32 n_qps_allocated; /* number of QPs allocated for device */ | ||
486 | spinlock_t n_qps_lock; | ||
441 | u32 n_srqs_allocated; /* number of SRQs allocated for device */ | 487 | u32 n_srqs_allocated; /* number of SRQs allocated for device */ |
488 | spinlock_t n_srqs_lock; | ||
442 | u32 n_mcast_grps_allocated; /* number of mcast groups allocated */ | 489 | u32 n_mcast_grps_allocated; /* number of mcast groups allocated */ |
490 | spinlock_t n_mcast_grps_lock; | ||
491 | |||
443 | u64 ipath_sword; /* total dwords sent (sample result) */ | 492 | u64 ipath_sword; /* total dwords sent (sample result) */ |
444 | u64 ipath_rword; /* total dwords received (sample result) */ | 493 | u64 ipath_rword; /* total dwords received (sample result) */ |
445 | u64 ipath_spkts; /* total packets sent (sample result) */ | 494 | u64 ipath_spkts; /* total packets sent (sample result) */ |
@@ -494,8 +543,19 @@ struct ipath_ibdev { | |||
494 | struct ipath_opcode_stats opstats[128]; | 543 | struct ipath_opcode_stats opstats[128]; |
495 | }; | 544 | }; |
496 | 545 | ||
497 | struct ipath_ucontext { | 546 | struct ipath_verbs_counters { |
498 | struct ib_ucontext ibucontext; | 547 | u64 symbol_error_counter; |
548 | u64 link_error_recovery_counter; | ||
549 | u64 link_downed_counter; | ||
550 | u64 port_rcv_errors; | ||
551 | u64 port_rcv_remphys_errors; | ||
552 | u64 port_xmit_discards; | ||
553 | u64 port_xmit_data; | ||
554 | u64 port_rcv_data; | ||
555 | u64 port_xmit_packets; | ||
556 | u64 port_rcv_packets; | ||
557 | u32 local_link_integrity_errors; | ||
558 | u32 excessive_buffer_overrun_errors; | ||
499 | }; | 559 | }; |
500 | 560 | ||
501 | static inline struct ipath_mr *to_imr(struct ib_mr *ibmr) | 561 | static inline struct ipath_mr *to_imr(struct ib_mr *ibmr) |
@@ -503,11 +563,6 @@ static inline struct ipath_mr *to_imr(struct ib_mr *ibmr) | |||
503 | return container_of(ibmr, struct ipath_mr, ibmr); | 563 | return container_of(ibmr, struct ipath_mr, ibmr); |
504 | } | 564 | } |
505 | 565 | ||
506 | static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr) | ||
507 | { | ||
508 | return container_of(ibfmr, struct ipath_fmr, ibfmr); | ||
509 | } | ||
510 | |||
511 | static inline struct ipath_pd *to_ipd(struct ib_pd *ibpd) | 566 | static inline struct ipath_pd *to_ipd(struct ib_pd *ibpd) |
512 | { | 567 | { |
513 | return container_of(ibpd, struct ipath_pd, ibpd); | 568 | return container_of(ibpd, struct ipath_pd, ibpd); |
@@ -545,12 +600,6 @@ int ipath_process_mad(struct ib_device *ibdev, | |||
545 | struct ib_grh *in_grh, | 600 | struct ib_grh *in_grh, |
546 | struct ib_mad *in_mad, struct ib_mad *out_mad); | 601 | struct ib_mad *in_mad, struct ib_mad *out_mad); |
547 | 602 | ||
548 | static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext | ||
549 | *ibucontext) | ||
550 | { | ||
551 | return container_of(ibucontext, struct ipath_ucontext, ibucontext); | ||
552 | } | ||
553 | |||
554 | /* | 603 | /* |
555 | * Compare the lower 24 bits of the two values. | 604 | * Compare the lower 24 bits of the two values. |
556 | * Returns an integer <, ==, or > than zero. | 605 | * Returns an integer <, ==, or > than zero. |
@@ -562,6 +611,13 @@ static inline int ipath_cmp24(u32 a, u32 b) | |||
562 | 611 | ||
563 | struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid); | 612 | struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid); |
564 | 613 | ||
614 | int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords, | ||
615 | u64 *rwords, u64 *spkts, u64 *rpkts, | ||
616 | u64 *xmit_wait); | ||
617 | |||
618 | int ipath_get_counters(struct ipath_devdata *dd, | ||
619 | struct ipath_verbs_counters *cntrs); | ||
620 | |||
565 | int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); | 621 | int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); |
566 | 622 | ||
567 | int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); | 623 | int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); |
@@ -579,7 +635,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, | |||
579 | int ipath_destroy_qp(struct ib_qp *ibqp); | 635 | int ipath_destroy_qp(struct ib_qp *ibqp); |
580 | 636 | ||
581 | int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | 637 | int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, |
582 | int attr_mask); | 638 | int attr_mask, struct ib_udata *udata); |
583 | 639 | ||
584 | int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | 640 | int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, |
585 | int attr_mask, struct ib_qp_init_attr *init_attr); | 641 | int attr_mask, struct ib_qp_init_attr *init_attr); |
@@ -592,6 +648,9 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc); | |||
592 | 648 | ||
593 | void ipath_get_credit(struct ipath_qp *qp, u32 aeth); | 649 | void ipath_get_credit(struct ipath_qp *qp, u32 aeth); |
594 | 650 | ||
651 | int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, | ||
652 | u32 *hdr, u32 len, struct ipath_sge_state *ss); | ||
653 | |||
595 | void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); | 654 | void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); |
596 | 655 | ||
597 | int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss, | 656 | int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss, |
@@ -638,7 +697,8 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, | |||
638 | struct ib_udata *udata); | 697 | struct ib_udata *udata); |
639 | 698 | ||
640 | int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, | 699 | int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, |
641 | enum ib_srq_attr_mask attr_mask); | 700 | enum ib_srq_attr_mask attr_mask, |
701 | struct ib_udata *udata); | ||
642 | 702 | ||
643 | int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); | 703 | int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); |
644 | 704 | ||
@@ -680,6 +740,10 @@ int ipath_unmap_fmr(struct list_head *fmr_list); | |||
680 | 740 | ||
681 | int ipath_dealloc_fmr(struct ib_fmr *ibfmr); | 741 | int ipath_dealloc_fmr(struct ib_fmr *ibfmr); |
682 | 742 | ||
743 | void ipath_release_mmap_info(struct kref *ref); | ||
744 | |||
745 | int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); | ||
746 | |||
683 | void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev); | 747 | void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev); |
684 | 748 | ||
685 | void ipath_insert_rnr_queue(struct ipath_qp *qp); | 749 | void ipath_insert_rnr_queue(struct ipath_qp *qp); |
@@ -700,6 +764,22 @@ int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, | |||
700 | int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, | 764 | int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, |
701 | u32 pmtu, u32 *bth0p, u32 *bth2p); | 765 | u32 pmtu, u32 *bth0p, u32 *bth2p); |
702 | 766 | ||
767 | int ipath_register_ib_device(struct ipath_devdata *); | ||
768 | |||
769 | void ipath_unregister_ib_device(struct ipath_ibdev *); | ||
770 | |||
771 | void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32); | ||
772 | |||
773 | int ipath_ib_piobufavail(struct ipath_ibdev *); | ||
774 | |||
775 | void ipath_ib_timer(struct ipath_ibdev *); | ||
776 | |||
777 | unsigned ipath_get_npkeys(struct ipath_devdata *); | ||
778 | |||
779 | u32 ipath_get_cr_errpkey(struct ipath_devdata *); | ||
780 | |||
781 | unsigned ipath_get_pkey(struct ipath_devdata *, unsigned); | ||
782 | |||
703 | extern const enum ib_wc_opcode ib_ipath_wc_opcode[]; | 783 | extern const enum ib_wc_opcode ib_ipath_wc_opcode[]; |
704 | 784 | ||
705 | extern const u8 ipath_cvt_physportstate[]; | 785 | extern const u8 ipath_cvt_physportstate[]; |
@@ -714,6 +794,8 @@ extern unsigned int ib_ipath_max_cqs; | |||
714 | 794 | ||
715 | extern unsigned int ib_ipath_max_qp_wrs; | 795 | extern unsigned int ib_ipath_max_qp_wrs; |
716 | 796 | ||
797 | extern unsigned int ib_ipath_max_qps; | ||
798 | |||
717 | extern unsigned int ib_ipath_max_sges; | 799 | extern unsigned int ib_ipath_max_sges; |
718 | 800 | ||
719 | extern unsigned int ib_ipath_max_mcast_grps; | 801 | extern unsigned int ib_ipath_max_mcast_grps; |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c index ee0e1d96d723..085e28b939ec 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c | |||
@@ -207,12 +207,17 @@ static int ipath_mcast_add(struct ipath_ibdev *dev, | |||
207 | goto bail; | 207 | goto bail; |
208 | } | 208 | } |
209 | 209 | ||
210 | spin_lock(&dev->n_mcast_grps_lock); | ||
210 | if (dev->n_mcast_grps_allocated == ib_ipath_max_mcast_grps) { | 211 | if (dev->n_mcast_grps_allocated == ib_ipath_max_mcast_grps) { |
212 | spin_unlock(&dev->n_mcast_grps_lock); | ||
211 | ret = ENOMEM; | 213 | ret = ENOMEM; |
212 | goto bail; | 214 | goto bail; |
213 | } | 215 | } |
214 | 216 | ||
215 | dev->n_mcast_grps_allocated++; | 217 | dev->n_mcast_grps_allocated++; |
218 | spin_unlock(&dev->n_mcast_grps_lock); | ||
219 | |||
220 | mcast->n_attached++; | ||
216 | 221 | ||
217 | list_add_tail_rcu(&mqp->list, &mcast->qp_list); | 222 | list_add_tail_rcu(&mqp->list, &mcast->qp_list); |
218 | 223 | ||
@@ -343,7 +348,9 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | |||
343 | atomic_dec(&mcast->refcount); | 348 | atomic_dec(&mcast->refcount); |
344 | wait_event(mcast->wait, !atomic_read(&mcast->refcount)); | 349 | wait_event(mcast->wait, !atomic_read(&mcast->refcount)); |
345 | ipath_mcast_free(mcast); | 350 | ipath_mcast_free(mcast); |
351 | spin_lock(&dev->n_mcast_grps_lock); | ||
346 | dev->n_mcast_grps_allocated--; | 352 | dev->n_mcast_grps_allocated--; |
353 | spin_unlock(&dev->n_mcast_grps_lock); | ||
347 | } | 354 | } |
348 | 355 | ||
349 | ret = 0; | 356 | ret = 0; |
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c new file mode 100644 index 000000000000..036fde662aa9 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 QLogic, Inc. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | * This file is conditionally built on PowerPC only. Otherwise weak symbol | ||
35 | * versions of the functions exported from here are used. | ||
36 | */ | ||
37 | |||
38 | #include "ipath_kernel.h" | ||
39 | |||
40 | /** | ||
41 | * ipath_unordered_wc - indicate whether write combining is ordered | ||
42 | * | ||
43 | * PowerPC systems (at least those in the 970 processor family) | ||
44 | * write partially filled store buffers in address order, but will write | ||
45 | * completely filled store buffers in "random" order, and therefore must | ||
46 | * have serialization for correctness with current InfiniPath chips. | ||
47 | * | ||
48 | */ | ||
49 | int ipath_unordered_wc(void) | ||
50 | { | ||
51 | return 1; | ||
52 | } | ||
diff --git a/drivers/infiniband/hw/ipath/verbs_debug.h b/drivers/infiniband/hw/ipath/verbs_debug.h deleted file mode 100644 index 6186676f2a16..000000000000 --- a/drivers/infiniband/hw/ipath/verbs_debug.h +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 QLogic, Inc. All rights reserved. | ||
3 | * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #ifndef _VERBS_DEBUG_H | ||
35 | #define _VERBS_DEBUG_H | ||
36 | |||
37 | /* | ||
38 | * This file contains tracing code for the ib_ipath kernel module. | ||
39 | */ | ||
40 | #ifndef _VERBS_DEBUGGING /* tracing enabled or not */ | ||
41 | #define _VERBS_DEBUGGING 1 | ||
42 | #endif | ||
43 | |||
44 | extern unsigned ib_ipath_debug; | ||
45 | |||
46 | #define _VERBS_ERROR(fmt,...) \ | ||
47 | do { \ | ||
48 | printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \ | ||
49 | } while(0) | ||
50 | |||
51 | #define _VERBS_UNIT_ERROR(unit,fmt,...) \ | ||
52 | do { \ | ||
53 | printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \ | ||
54 | } while(0) | ||
55 | |||
56 | #if _VERBS_DEBUGGING | ||
57 | |||
58 | /* | ||
59 | * Mask values for debugging. The scheme allows us to compile out any | ||
60 | * of the debug tracing stuff, and if compiled in, to enable or | ||
61 | * disable dynamically. | ||
62 | * This can be set at modprobe time also: | ||
63 | * modprobe ib_path ib_ipath_debug=3 | ||
64 | */ | ||
65 | |||
66 | #define __VERBS_INFO 0x1 /* generic low verbosity stuff */ | ||
67 | #define __VERBS_DBG 0x2 /* generic debug */ | ||
68 | #define __VERBS_VDBG 0x4 /* verbose debug */ | ||
69 | #define __VERBS_SMADBG 0x8000 /* sma packet debug */ | ||
70 | |||
71 | #define _VERBS_INFO(fmt,...) \ | ||
72 | do { \ | ||
73 | if (unlikely(ib_ipath_debug&__VERBS_INFO)) \ | ||
74 | printk(KERN_INFO "%s: " fmt,"ib_ipath", \ | ||
75 | ##__VA_ARGS__); \ | ||
76 | } while(0) | ||
77 | |||
78 | #define _VERBS_DBG(fmt,...) \ | ||
79 | do { \ | ||
80 | if (unlikely(ib_ipath_debug&__VERBS_DBG)) \ | ||
81 | printk(KERN_DEBUG "%s: " fmt, __func__, \ | ||
82 | ##__VA_ARGS__); \ | ||
83 | } while(0) | ||
84 | |||
85 | #define _VERBS_VDBG(fmt,...) \ | ||
86 | do { \ | ||
87 | if (unlikely(ib_ipath_debug&__VERBS_VDBG)) \ | ||
88 | printk(KERN_DEBUG "%s: " fmt, __func__, \ | ||
89 | ##__VA_ARGS__); \ | ||
90 | } while(0) | ||
91 | |||
92 | #define _VERBS_SMADBG(fmt,...) \ | ||
93 | do { \ | ||
94 | if (unlikely(ib_ipath_debug&__VERBS_SMADBG)) \ | ||
95 | printk(KERN_DEBUG "%s: " fmt, __func__, \ | ||
96 | ##__VA_ARGS__); \ | ||
97 | } while(0) | ||
98 | |||
99 | #else /* ! _VERBS_DEBUGGING */ | ||
100 | |||
101 | #define _VERBS_INFO(fmt,...) | ||
102 | #define _VERBS_DBG(fmt,...) | ||
103 | #define _VERBS_VDBG(fmt,...) | ||
104 | #define _VERBS_SMADBG(fmt,...) | ||
105 | |||
106 | #endif /* _VERBS_DEBUGGING */ | ||
107 | |||
108 | #endif /* _VERBS_DEBUG_H */ | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c index e215041b2db9..69599455aca2 100644 --- a/drivers/infiniband/hw/mthca/mthca_av.c +++ b/drivers/infiniband/hw/mthca/mthca_av.c | |||
@@ -90,7 +90,7 @@ static enum ib_rate tavor_rate_to_ib(u8 mthca_rate, u8 port_rate) | |||
90 | case MTHCA_RATE_TAVOR_1X: return IB_RATE_2_5_GBPS; | 90 | case MTHCA_RATE_TAVOR_1X: return IB_RATE_2_5_GBPS; |
91 | case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS; | 91 | case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS; |
92 | case MTHCA_RATE_TAVOR_4X: return IB_RATE_10_GBPS; | 92 | case MTHCA_RATE_TAVOR_4X: return IB_RATE_10_GBPS; |
93 | default: return port_rate; | 93 | default: return mult_to_ib_rate(port_rate); |
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index c3bec7490f52..cd044ea2dfa4 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <linux/jiffies.h> | 35 | #include <linux/jiffies.h> |
36 | #include <linux/timer.h> | 36 | #include <linux/timer.h> |
37 | #include <linux/workqueue.h> | ||
37 | 38 | ||
38 | #include "mthca_dev.h" | 39 | #include "mthca_dev.h" |
39 | 40 | ||
@@ -48,9 +49,41 @@ enum { | |||
48 | 49 | ||
49 | static DEFINE_SPINLOCK(catas_lock); | 50 | static DEFINE_SPINLOCK(catas_lock); |
50 | 51 | ||
52 | static LIST_HEAD(catas_list); | ||
53 | static struct workqueue_struct *catas_wq; | ||
54 | static struct work_struct catas_work; | ||
55 | |||
56 | static int catas_reset_disable; | ||
57 | module_param_named(catas_reset_disable, catas_reset_disable, int, 0644); | ||
58 | MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero"); | ||
59 | |||
60 | static void catas_reset(void *work_ptr) | ||
61 | { | ||
62 | struct mthca_dev *dev, *tmpdev; | ||
63 | LIST_HEAD(tlist); | ||
64 | int ret; | ||
65 | |||
66 | mutex_lock(&mthca_device_mutex); | ||
67 | |||
68 | spin_lock_irq(&catas_lock); | ||
69 | list_splice_init(&catas_list, &tlist); | ||
70 | spin_unlock_irq(&catas_lock); | ||
71 | |||
72 | list_for_each_entry_safe(dev, tmpdev, &tlist, catas_err.list) { | ||
73 | ret = __mthca_restart_one(dev->pdev); | ||
74 | if (ret) | ||
75 | mthca_err(dev, "Reset failed (%d)\n", ret); | ||
76 | else | ||
77 | mthca_dbg(dev, "Reset succeeded\n"); | ||
78 | } | ||
79 | |||
80 | mutex_unlock(&mthca_device_mutex); | ||
81 | } | ||
82 | |||
51 | static void handle_catas(struct mthca_dev *dev) | 83 | static void handle_catas(struct mthca_dev *dev) |
52 | { | 84 | { |
53 | struct ib_event event; | 85 | struct ib_event event; |
86 | unsigned long flags; | ||
54 | const char *type; | 87 | const char *type; |
55 | int i; | 88 | int i; |
56 | 89 | ||
@@ -82,6 +115,14 @@ static void handle_catas(struct mthca_dev *dev) | |||
82 | for (i = 0; i < dev->catas_err.size; ++i) | 115 | for (i = 0; i < dev->catas_err.size; ++i) |
83 | mthca_err(dev, " buf[%02x]: %08x\n", | 116 | mthca_err(dev, " buf[%02x]: %08x\n", |
84 | i, swab32(readl(dev->catas_err.map + i))); | 117 | i, swab32(readl(dev->catas_err.map + i))); |
118 | |||
119 | if (catas_reset_disable) | ||
120 | return; | ||
121 | |||
122 | spin_lock_irqsave(&catas_lock, flags); | ||
123 | list_add(&dev->catas_err.list, &catas_list); | ||
124 | queue_work(catas_wq, &catas_work); | ||
125 | spin_unlock_irqrestore(&catas_lock, flags); | ||
85 | } | 126 | } |
86 | 127 | ||
87 | static void poll_catas(unsigned long dev_ptr) | 128 | static void poll_catas(unsigned long dev_ptr) |
@@ -135,6 +176,7 @@ void mthca_start_catas_poll(struct mthca_dev *dev) | |||
135 | dev->catas_err.timer.data = (unsigned long) dev; | 176 | dev->catas_err.timer.data = (unsigned long) dev; |
136 | dev->catas_err.timer.function = poll_catas; | 177 | dev->catas_err.timer.function = poll_catas; |
137 | dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL; | 178 | dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL; |
179 | INIT_LIST_HEAD(&dev->catas_err.list); | ||
138 | add_timer(&dev->catas_err.timer); | 180 | add_timer(&dev->catas_err.timer); |
139 | } | 181 | } |
140 | 182 | ||
@@ -153,4 +195,24 @@ void mthca_stop_catas_poll(struct mthca_dev *dev) | |||
153 | dev->catas_err.addr), | 195 | dev->catas_err.addr), |
154 | dev->catas_err.size * 4); | 196 | dev->catas_err.size * 4); |
155 | } | 197 | } |
198 | |||
199 | spin_lock_irq(&catas_lock); | ||
200 | list_del(&dev->catas_err.list); | ||
201 | spin_unlock_irq(&catas_lock); | ||
202 | } | ||
203 | |||
204 | int __init mthca_catas_init(void) | ||
205 | { | ||
206 | INIT_WORK(&catas_work, catas_reset, NULL); | ||
207 | |||
208 | catas_wq = create_singlethread_workqueue("mthca_catas"); | ||
209 | if (!catas_wq) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | void mthca_catas_cleanup(void) | ||
216 | { | ||
217 | destroy_workqueue(catas_wq); | ||
156 | } | 218 | } |
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index deabc14b4ea4..99a94d710935 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c | |||
@@ -34,7 +34,7 @@ | |||
34 | * $Id: mthca_cmd.c 1349 2004-12-16 21:09:43Z roland $ | 34 | * $Id: mthca_cmd.c 1349 2004-12-16 21:09:43Z roland $ |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/sched.h> | 37 | #include <linux/completion.h> |
38 | #include <linux/pci.h> | 38 | #include <linux/pci.h> |
39 | #include <linux/errno.h> | 39 | #include <linux/errno.h> |
40 | #include <asm/io.h> | 40 | #include <asm/io.h> |
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 3e27a084257e..e393681ba7d4 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c | |||
@@ -544,11 +544,11 @@ static inline int mthca_poll_one(struct mthca_dev *dev, | |||
544 | wq = &(*cur_qp)->rq; | 544 | wq = &(*cur_qp)->rq; |
545 | wqe = be32_to_cpu(cqe->wqe); | 545 | wqe = be32_to_cpu(cqe->wqe); |
546 | wqe_index = wqe >> wq->wqe_shift; | 546 | wqe_index = wqe >> wq->wqe_shift; |
547 | /* | 547 | /* |
548 | * WQE addr == base - 1 might be reported in receive completion | 548 | * WQE addr == base - 1 might be reported in receive completion |
549 | * with error instead of (rq size - 1) by Sinai FW 1.0.800 and | 549 | * with error instead of (rq size - 1) by Sinai FW 1.0.800 and |
550 | * Arbel FW 5.1.400. This bug should be fixed in later FW revs. | 550 | * Arbel FW 5.1.400. This bug should be fixed in later FW revs. |
551 | */ | 551 | */ |
552 | if (unlikely(wqe_index < 0)) | 552 | if (unlikely(wqe_index < 0)) |
553 | wqe_index = wq->max - 1; | 553 | wqe_index = wq->max - 1; |
554 | entry->wr_id = (*cur_qp)->wrid[wqe_index]; | 554 | entry->wr_id = (*cur_qp)->wrid[wqe_index]; |
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index f8160b8de090..fe5cecf70fed 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/dma-mapping.h> | 45 | #include <linux/dma-mapping.h> |
46 | #include <linux/timer.h> | 46 | #include <linux/timer.h> |
47 | #include <linux/mutex.h> | 47 | #include <linux/mutex.h> |
48 | #include <linux/list.h> | ||
48 | 49 | ||
49 | #include <asm/semaphore.h> | 50 | #include <asm/semaphore.h> |
50 | 51 | ||
@@ -283,8 +284,11 @@ struct mthca_catas_err { | |||
283 | unsigned long stop; | 284 | unsigned long stop; |
284 | u32 size; | 285 | u32 size; |
285 | struct timer_list timer; | 286 | struct timer_list timer; |
287 | struct list_head list; | ||
286 | }; | 288 | }; |
287 | 289 | ||
290 | extern struct mutex mthca_device_mutex; | ||
291 | |||
288 | struct mthca_dev { | 292 | struct mthca_dev { |
289 | struct ib_device ib_dev; | 293 | struct ib_device ib_dev; |
290 | struct pci_dev *pdev; | 294 | struct pci_dev *pdev; |
@@ -450,6 +454,9 @@ void mthca_unregister_device(struct mthca_dev *dev); | |||
450 | 454 | ||
451 | void mthca_start_catas_poll(struct mthca_dev *dev); | 455 | void mthca_start_catas_poll(struct mthca_dev *dev); |
452 | void mthca_stop_catas_poll(struct mthca_dev *dev); | 456 | void mthca_stop_catas_poll(struct mthca_dev *dev); |
457 | int __mthca_restart_one(struct pci_dev *pdev); | ||
458 | int mthca_catas_init(void); | ||
459 | void mthca_catas_cleanup(void); | ||
453 | 460 | ||
454 | int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar); | 461 | int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar); |
455 | void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar); | 462 | void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar); |
@@ -506,7 +513,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, | |||
506 | struct ib_srq_attr *attr, struct mthca_srq *srq); | 513 | struct ib_srq_attr *attr, struct mthca_srq *srq); |
507 | void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq); | 514 | void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq); |
508 | int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, | 515 | int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, |
509 | enum ib_srq_attr_mask attr_mask); | 516 | enum ib_srq_attr_mask attr_mask, struct ib_udata *udata); |
510 | int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr); | 517 | int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr); |
511 | int mthca_max_srq_sge(struct mthca_dev *dev); | 518 | int mthca_max_srq_sge(struct mthca_dev *dev); |
512 | void mthca_srq_event(struct mthca_dev *dev, u32 srqn, | 519 | void mthca_srq_event(struct mthca_dev *dev, u32 srqn, |
@@ -521,7 +528,8 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn, | |||
521 | enum ib_event_type event_type); | 528 | enum ib_event_type event_type); |
522 | int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, | 529 | int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, |
523 | struct ib_qp_init_attr *qp_init_attr); | 530 | struct ib_qp_init_attr *qp_init_attr); |
524 | int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask); | 531 | int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, |
532 | struct ib_udata *udata); | ||
525 | int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | 533 | int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, |
526 | struct ib_send_wr **bad_wr); | 534 | struct ib_send_wr **bad_wr); |
527 | int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | 535 | int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, |
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c index d9bc030bcccc..45e106f14807 100644 --- a/drivers/infiniband/hw/mthca/mthca_mad.c +++ b/drivers/infiniband/hw/mthca/mthca_mad.c | |||
@@ -119,7 +119,7 @@ static void smp_snoop(struct ib_device *ibdev, | |||
119 | 119 | ||
120 | mthca_update_rate(to_mdev(ibdev), port_num); | 120 | mthca_update_rate(to_mdev(ibdev), port_num); |
121 | update_sm_ah(to_mdev(ibdev), port_num, | 121 | update_sm_ah(to_mdev(ibdev), port_num, |
122 | be16_to_cpu(pinfo->lid), | 122 | be16_to_cpu(pinfo->sm_lid), |
123 | pinfo->neighbormtu_mastersmsl & 0xf); | 123 | pinfo->neighbormtu_mastersmsl & 0xf); |
124 | 124 | ||
125 | event.device = ibdev; | 125 | event.device = ibdev; |
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 7b82c1907f04..47ea02148368 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c | |||
@@ -80,6 +80,8 @@ static int tune_pci = 0; | |||
80 | module_param(tune_pci, int, 0444); | 80 | module_param(tune_pci, int, 0444); |
81 | MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero"); | 81 | MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero"); |
82 | 82 | ||
83 | struct mutex mthca_device_mutex; | ||
84 | |||
83 | static const char mthca_version[] __devinitdata = | 85 | static const char mthca_version[] __devinitdata = |
84 | DRV_NAME ": Mellanox InfiniBand HCA driver v" | 86 | DRV_NAME ": Mellanox InfiniBand HCA driver v" |
85 | DRV_VERSION " (" DRV_RELDATE ")\n"; | 87 | DRV_VERSION " (" DRV_RELDATE ")\n"; |
@@ -978,28 +980,15 @@ static struct { | |||
978 | MTHCA_FLAG_SINAI_OPT } | 980 | MTHCA_FLAG_SINAI_OPT } |
979 | }; | 981 | }; |
980 | 982 | ||
981 | static int __devinit mthca_init_one(struct pci_dev *pdev, | 983 | static int __mthca_init_one(struct pci_dev *pdev, int hca_type) |
982 | const struct pci_device_id *id) | ||
983 | { | 984 | { |
984 | static int mthca_version_printed = 0; | ||
985 | int ddr_hidden = 0; | 985 | int ddr_hidden = 0; |
986 | int err; | 986 | int err; |
987 | struct mthca_dev *mdev; | 987 | struct mthca_dev *mdev; |
988 | 988 | ||
989 | if (!mthca_version_printed) { | ||
990 | printk(KERN_INFO "%s", mthca_version); | ||
991 | ++mthca_version_printed; | ||
992 | } | ||
993 | |||
994 | printk(KERN_INFO PFX "Initializing %s\n", | 989 | printk(KERN_INFO PFX "Initializing %s\n", |
995 | pci_name(pdev)); | 990 | pci_name(pdev)); |
996 | 991 | ||
997 | if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { | ||
998 | printk(KERN_ERR PFX "%s has invalid driver data %lx\n", | ||
999 | pci_name(pdev), id->driver_data); | ||
1000 | return -ENODEV; | ||
1001 | } | ||
1002 | |||
1003 | err = pci_enable_device(pdev); | 992 | err = pci_enable_device(pdev); |
1004 | if (err) { | 993 | if (err) { |
1005 | dev_err(&pdev->dev, "Cannot enable PCI device, " | 994 | dev_err(&pdev->dev, "Cannot enable PCI device, " |
@@ -1065,7 +1054,7 @@ static int __devinit mthca_init_one(struct pci_dev *pdev, | |||
1065 | 1054 | ||
1066 | mdev->pdev = pdev; | 1055 | mdev->pdev = pdev; |
1067 | 1056 | ||
1068 | mdev->mthca_flags = mthca_hca_table[id->driver_data].flags; | 1057 | mdev->mthca_flags = mthca_hca_table[hca_type].flags; |
1069 | if (ddr_hidden) | 1058 | if (ddr_hidden) |
1070 | mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; | 1059 | mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; |
1071 | 1060 | ||
@@ -1099,13 +1088,13 @@ static int __devinit mthca_init_one(struct pci_dev *pdev, | |||
1099 | if (err) | 1088 | if (err) |
1100 | goto err_cmd; | 1089 | goto err_cmd; |
1101 | 1090 | ||
1102 | if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) { | 1091 | if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { |
1103 | mthca_warn(mdev, "HCA FW version %d.%d.%d is old (%d.%d.%d is current).\n", | 1092 | mthca_warn(mdev, "HCA FW version %d.%d.%d is old (%d.%d.%d is current).\n", |
1104 | (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, | 1093 | (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, |
1105 | (int) (mdev->fw_ver & 0xffff), | 1094 | (int) (mdev->fw_ver & 0xffff), |
1106 | (int) (mthca_hca_table[id->driver_data].latest_fw >> 32), | 1095 | (int) (mthca_hca_table[hca_type].latest_fw >> 32), |
1107 | (int) (mthca_hca_table[id->driver_data].latest_fw >> 16) & 0xffff, | 1096 | (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff, |
1108 | (int) (mthca_hca_table[id->driver_data].latest_fw & 0xffff)); | 1097 | (int) (mthca_hca_table[hca_type].latest_fw & 0xffff)); |
1109 | mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); | 1098 | mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); |
1110 | } | 1099 | } |
1111 | 1100 | ||
@@ -1122,6 +1111,7 @@ static int __devinit mthca_init_one(struct pci_dev *pdev, | |||
1122 | goto err_unregister; | 1111 | goto err_unregister; |
1123 | 1112 | ||
1124 | pci_set_drvdata(pdev, mdev); | 1113 | pci_set_drvdata(pdev, mdev); |
1114 | mdev->hca_type = hca_type; | ||
1125 | 1115 | ||
1126 | return 0; | 1116 | return 0; |
1127 | 1117 | ||
@@ -1166,7 +1156,7 @@ err_disable_pdev: | |||
1166 | return err; | 1156 | return err; |
1167 | } | 1157 | } |
1168 | 1158 | ||
1169 | static void __devexit mthca_remove_one(struct pci_dev *pdev) | 1159 | static void __mthca_remove_one(struct pci_dev *pdev) |
1170 | { | 1160 | { |
1171 | struct mthca_dev *mdev = pci_get_drvdata(pdev); | 1161 | struct mthca_dev *mdev = pci_get_drvdata(pdev); |
1172 | u8 status; | 1162 | u8 status; |
@@ -1211,6 +1201,51 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev) | |||
1211 | } | 1201 | } |
1212 | } | 1202 | } |
1213 | 1203 | ||
1204 | int __mthca_restart_one(struct pci_dev *pdev) | ||
1205 | { | ||
1206 | struct mthca_dev *mdev; | ||
1207 | |||
1208 | mdev = pci_get_drvdata(pdev); | ||
1209 | if (!mdev) | ||
1210 | return -ENODEV; | ||
1211 | __mthca_remove_one(pdev); | ||
1212 | return __mthca_init_one(pdev, mdev->hca_type); | ||
1213 | } | ||
1214 | |||
1215 | static int __devinit mthca_init_one(struct pci_dev *pdev, | ||
1216 | const struct pci_device_id *id) | ||
1217 | { | ||
1218 | static int mthca_version_printed = 0; | ||
1219 | int ret; | ||
1220 | |||
1221 | mutex_lock(&mthca_device_mutex); | ||
1222 | |||
1223 | if (!mthca_version_printed) { | ||
1224 | printk(KERN_INFO "%s", mthca_version); | ||
1225 | ++mthca_version_printed; | ||
1226 | } | ||
1227 | |||
1228 | if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { | ||
1229 | printk(KERN_ERR PFX "%s has invalid driver data %lx\n", | ||
1230 | pci_name(pdev), id->driver_data); | ||
1231 | mutex_unlock(&mthca_device_mutex); | ||
1232 | return -ENODEV; | ||
1233 | } | ||
1234 | |||
1235 | ret = __mthca_init_one(pdev, id->driver_data); | ||
1236 | |||
1237 | mutex_unlock(&mthca_device_mutex); | ||
1238 | |||
1239 | return ret; | ||
1240 | } | ||
1241 | |||
1242 | static void __devexit mthca_remove_one(struct pci_dev *pdev) | ||
1243 | { | ||
1244 | mutex_lock(&mthca_device_mutex); | ||
1245 | __mthca_remove_one(pdev); | ||
1246 | mutex_unlock(&mthca_device_mutex); | ||
1247 | } | ||
1248 | |||
1214 | static struct pci_device_id mthca_pci_table[] = { | 1249 | static struct pci_device_id mthca_pci_table[] = { |
1215 | { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), | 1250 | { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), |
1216 | .driver_data = TAVOR }, | 1251 | .driver_data = TAVOR }, |
@@ -1248,13 +1283,24 @@ static int __init mthca_init(void) | |||
1248 | { | 1283 | { |
1249 | int ret; | 1284 | int ret; |
1250 | 1285 | ||
1286 | mutex_init(&mthca_device_mutex); | ||
1287 | ret = mthca_catas_init(); | ||
1288 | if (ret) | ||
1289 | return ret; | ||
1290 | |||
1251 | ret = pci_register_driver(&mthca_driver); | 1291 | ret = pci_register_driver(&mthca_driver); |
1252 | return ret < 0 ? ret : 0; | 1292 | if (ret < 0) { |
1293 | mthca_catas_cleanup(); | ||
1294 | return ret; | ||
1295 | } | ||
1296 | |||
1297 | return 0; | ||
1253 | } | 1298 | } |
1254 | 1299 | ||
1255 | static void __exit mthca_cleanup(void) | 1300 | static void __exit mthca_cleanup(void) |
1256 | { | 1301 | { |
1257 | pci_unregister_driver(&mthca_driver); | 1302 | pci_unregister_driver(&mthca_driver); |
1303 | mthca_catas_cleanup(); | ||
1258 | } | 1304 | } |
1259 | 1305 | ||
1260 | module_init(mthca_init); | 1306 | module_init(mthca_init); |
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 265b1d1c4a62..981fe2eebdfa 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c | |||
@@ -1288,7 +1288,7 @@ int mthca_register_device(struct mthca_dev *dev) | |||
1288 | (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | | 1288 | (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | |
1289 | (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | | 1289 | (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | |
1290 | (1ull << IB_USER_VERBS_CMD_DETACH_MCAST); | 1290 | (1ull << IB_USER_VERBS_CMD_DETACH_MCAST); |
1291 | dev->ib_dev.node_type = IB_NODE_CA; | 1291 | dev->ib_dev.node_type = RDMA_NODE_IB_CA; |
1292 | dev->ib_dev.phys_port_cnt = dev->limits.num_ports; | 1292 | dev->ib_dev.phys_port_cnt = dev->limits.num_ports; |
1293 | dev->ib_dev.dma_device = &dev->pdev->dev; | 1293 | dev->ib_dev.dma_device = &dev->pdev->dev; |
1294 | dev->ib_dev.class_dev.dev = &dev->pdev->dev; | 1294 | dev->ib_dev.class_dev.dev = &dev->pdev->dev; |
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 2e8f6f36e0a5..5e5c58b9920b 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c | |||
@@ -408,7 +408,7 @@ static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr, | |||
408 | ib_ah_attr->sl = be32_to_cpu(path->sl_tclass_flowlabel) >> 28; | 408 | ib_ah_attr->sl = be32_to_cpu(path->sl_tclass_flowlabel) >> 28; |
409 | ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f; | 409 | ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f; |
410 | ib_ah_attr->static_rate = mthca_rate_to_ib(dev, | 410 | ib_ah_attr->static_rate = mthca_rate_to_ib(dev, |
411 | path->static_rate & 0x7, | 411 | path->static_rate & 0xf, |
412 | ib_ah_attr->port_num); | 412 | ib_ah_attr->port_num); |
413 | ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0; | 413 | ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0; |
414 | if (ib_ah_attr->ah_flags) { | 414 | if (ib_ah_attr->ah_flags) { |
@@ -472,10 +472,14 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m | |||
472 | if (qp->transport == RC || qp->transport == UC) { | 472 | if (qp->transport == RC || qp->transport == UC) { |
473 | to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); | 473 | to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); |
474 | to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path); | 474 | to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path); |
475 | qp_attr->alt_pkey_index = | ||
476 | be32_to_cpu(context->alt_path.port_pkey) & 0x7f; | ||
477 | qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; | ||
475 | } | 478 | } |
476 | 479 | ||
477 | qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f; | 480 | qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f; |
478 | qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f; | 481 | qp_attr->port_num = |
482 | (be32_to_cpu(context->pri_path.port_pkey) >> 24) & 0x3; | ||
479 | 483 | ||
480 | /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ | 484 | /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ |
481 | qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING; | 485 | qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING; |
@@ -486,11 +490,9 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m | |||
486 | 1 << ((be32_to_cpu(context->params2) >> 21) & 0x7); | 490 | 1 << ((be32_to_cpu(context->params2) >> 21) & 0x7); |
487 | qp_attr->min_rnr_timer = | 491 | qp_attr->min_rnr_timer = |
488 | (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f; | 492 | (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f; |
489 | qp_attr->port_num = qp_attr->ah_attr.port_num; | ||
490 | qp_attr->timeout = context->pri_path.ackto >> 3; | 493 | qp_attr->timeout = context->pri_path.ackto >> 3; |
491 | qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7; | 494 | qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7; |
492 | qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5; | 495 | qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5; |
493 | qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; | ||
494 | qp_attr->alt_timeout = context->alt_path.ackto >> 3; | 496 | qp_attr->alt_timeout = context->alt_path.ackto >> 3; |
495 | qp_init_attr->cap = qp_attr->cap; | 497 | qp_init_attr->cap = qp_attr->cap; |
496 | 498 | ||
@@ -527,7 +529,8 @@ static int mthca_path_set(struct mthca_dev *dev, struct ib_ah_attr *ah, | |||
527 | return 0; | 529 | return 0; |
528 | } | 530 | } |
529 | 531 | ||
530 | int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | 532 | int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, |
533 | struct ib_udata *udata) | ||
531 | { | 534 | { |
532 | struct mthca_dev *dev = to_mdev(ibqp->device); | 535 | struct mthca_dev *dev = to_mdev(ibqp->device); |
533 | struct mthca_qp *qp = to_mqp(ibqp); | 536 | struct mthca_qp *qp = to_mqp(ibqp); |
@@ -842,11 +845,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
842 | * entries and reinitialize the QP. | 845 | * entries and reinitialize the QP. |
843 | */ | 846 | */ |
844 | if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) { | 847 | if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) { |
845 | mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, | 848 | mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, |
846 | qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); | 849 | qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); |
847 | if (qp->ibqp.send_cq != qp->ibqp.recv_cq) | 850 | if (qp->ibqp.send_cq != qp->ibqp.recv_cq) |
848 | mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, | 851 | mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, NULL); |
849 | qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); | ||
850 | 852 | ||
851 | mthca_wq_reset(&qp->sq); | 853 | mthca_wq_reset(&qp->sq); |
852 | qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); | 854 | qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); |
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index b60a9d79ae54..0f316c87bf64 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c | |||
@@ -358,7 +358,7 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) | |||
358 | } | 358 | } |
359 | 359 | ||
360 | int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, | 360 | int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, |
361 | enum ib_srq_attr_mask attr_mask) | 361 | enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) |
362 | { | 362 | { |
363 | struct mthca_dev *dev = to_mdev(ibsrq->device); | 363 | struct mthca_dev *dev = to_mdev(ibsrq->device); |
364 | struct mthca_srq *srq = to_msrq(ibsrq); | 364 | struct mthca_srq *srq = to_msrq(ibsrq); |
diff --git a/drivers/infiniband/hw/mthca/mthca_uar.c b/drivers/infiniband/hw/mthca/mthca_uar.c index 8e9219842be4..8b728486410d 100644 --- a/drivers/infiniband/hw/mthca/mthca_uar.c +++ b/drivers/infiniband/hw/mthca/mthca_uar.c | |||
@@ -60,7 +60,7 @@ int mthca_init_uar_table(struct mthca_dev *dev) | |||
60 | ret = mthca_alloc_init(&dev->uar_table.alloc, | 60 | ret = mthca_alloc_init(&dev->uar_table.alloc, |
61 | dev->limits.num_uars, | 61 | dev->limits.num_uars, |
62 | dev->limits.num_uars - 1, | 62 | dev->limits.num_uars - 1, |
63 | dev->limits.reserved_uars); | 63 | dev->limits.reserved_uars + 1); |
64 | if (ret) | 64 | if (ret) |
65 | return ret; | 65 | return ret; |
66 | 66 | ||