1f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 2f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Copyright (c) 2010 QLogic Corporation. All rights reserved. 3f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. 4f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. 5f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 6f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * This software is available to you under a choice of one of two 7f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * licenses. You may choose to be licensed under the terms of the GNU 8f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * General Public License (GPL) Version 2, available from the file 9f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * COPYING in the main directory of this source tree, or the 10f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * OpenIB.org BSD license below: 11f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 12f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Redistribution and use in source and binary forms, with or 13f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * without modification, are permitted provided that the following 14f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * conditions are met: 15f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 16f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * - Redistributions of source code must retain the above 17f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * copyright notice, this list of conditions and the following 18f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * disclaimer. 19f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 20f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * - Redistributions in binary form must reproduce the above 21f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * copyright notice, this list of conditions and the following 22f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * disclaimer in the documentation and/or other materials 23f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * provided with the distribution. 24f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 25f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * SOFTWARE. 33f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 34f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 35f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 36f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * This file contains support for diagnostic functions. It is accessed by 37f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * opening the qib_diag device, normally minor number 129. Diagnostic use 38f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * of the QLogic_IB chip may render the chip or board unusable until the 39f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * driver is unloaded, or in some cases, until the system is rebooted. 40f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 41f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Accesses to the chip through this interface are not similar to going 42f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * through the /sys/bus/pci resource mmap interface. 43f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 44f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 45f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/io.h> 46f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/pci.h> 47f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/poll.h> 48f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/vmalloc.h> 49b108d9764cff25262bf764542ed1998d3e568962Paul Gortmaker#include <linux/export.h> 50f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/fs.h> 51f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include <linux/uaccess.h> 52f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 53f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include "qib.h" 54f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell#include "qib_common.h" 55f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 56f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 57f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Each client that opens the diag device must read then write 58f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * offset 0, to prevent lossage from random cat or od. diag_state 59f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * sequences this "handshake". 60f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 61f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellenum diag_state { UNUSED = 0, OPENED, INIT, READY }; 62f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 63f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* State for an individual client. PID so children cannot abuse handshake */ 64f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic struct qib_diag_client { 65f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_client *next; 66f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_devdata *dd; 67f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell pid_t pid; 68f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell enum diag_state state; 69f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} *client_pool; 70f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 71f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 72f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Get a client struct. Recycled if possible, else kmalloc. 73f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Must be called with qib_mutex held 74f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 75f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic struct qib_diag_client *get_client(struct qib_devdata *dd) 76f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 77f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_client *dc; 78f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 79f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc = client_pool; 80f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc) 81f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* got from pool remove it and use */ 82f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell client_pool = dc->next; 83f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else 84f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* None in pool, alloc and init */ 85f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc = kmalloc(sizeof *dc, GFP_KERNEL); 86f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 87f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc) { 88f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc->next = NULL; 89f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc->dd = dd; 90f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc->pid = current->pid; 91f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc->state = OPENED; 92f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 93f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return dc; 94f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 95f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 96f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 97f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Return to pool. Must be called with qib_mutex held 98f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 99f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void return_client(struct qib_diag_client *dc) 100f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 101f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_devdata *dd = dc->dd; 102f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_client *tdc, *rdc; 103f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 104f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell rdc = NULL; 105f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc == dd->diag_client) { 106f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd->diag_client = dc->next; 107f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell rdc = dc; 108f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } else { 109f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell tdc = dc->dd->diag_client; 110f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (tdc) { 111f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc == tdc->next) { 112f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell tdc->next = dc->next; 113f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell rdc = dc; 114f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell break; 115f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 116f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell tdc = tdc->next; 117f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 118f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 119f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (rdc) { 120f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell rdc->state = UNUSED; 121f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell rdc->dd = NULL; 122f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell rdc->pid = 0; 123f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell rdc->next = client_pool; 124f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell client_pool = rdc; 125f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 126f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 127f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 128f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_diag_open(struct inode *in, struct file *fp); 129f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_diag_release(struct inode *in, struct file *fp); 130f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic ssize_t qib_diag_read(struct file *fp, char __user *data, 131f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell size_t count, loff_t *off); 132f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic ssize_t qib_diag_write(struct file *fp, const char __user *data, 133f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell size_t count, loff_t *off); 134f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 135f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic const struct file_operations diag_file_ops = { 136f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell .owner = THIS_MODULE, 137f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell .write = qib_diag_write, 138f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell .read = qib_diag_read, 139f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell .open = qib_diag_open, 1406038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .release = qib_diag_release, 1416038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = default_llseek, 142f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}; 143f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 144f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic atomic_t diagpkt_count = ATOMIC_INIT(0); 145f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic struct cdev *diagpkt_cdev; 146f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic struct device *diagpkt_device; 147f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 148f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic ssize_t qib_diagpkt_write(struct file *fp, const char __user *data, 149f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell size_t count, loff_t *off); 150f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 151f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic const struct file_operations diagpkt_file_ops = { 152f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell .owner = THIS_MODULE, 153f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell .write = qib_diagpkt_write, 1546038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = noop_llseek, 155f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}; 156f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 157f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellint qib_diag_add(struct qib_devdata *dd) 158f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 159f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell char name[16]; 160f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int ret = 0; 161f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 162f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (atomic_inc_return(&diagpkt_count) == 1) { 163f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = qib_cdev_init(QIB_DIAGPKT_MINOR, "ipath_diagpkt", 164f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell &diagpkt_file_ops, &diagpkt_cdev, 165f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell &diagpkt_device); 166f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (ret) 167f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto done; 168f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 169f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 170f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell snprintf(name, sizeof(name), "ipath_diag%d", dd->unit); 171f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = qib_cdev_init(QIB_DIAG_MINOR_BASE + dd->unit, name, 172f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell &diag_file_ops, &dd->diag_cdev, 173f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell &dd->diag_device); 174f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbelldone: 175f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 176f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 177f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 178f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_unregister_observers(struct qib_devdata *dd); 179f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 180f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellvoid qib_diag_remove(struct qib_devdata *dd) 181f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 182f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_client *dc; 183f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 184f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (atomic_dec_and_test(&diagpkt_count)) 185f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_cdev_cleanup(&diagpkt_cdev, &diagpkt_device); 186f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 187f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_cdev_cleanup(&dd->diag_cdev, &dd->diag_device); 188f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 189f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 190f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Return all diag_clients of this device. There should be none, 191f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * as we are "guaranteed" that no clients are still open 192f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 193f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (dd->diag_client) 194f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return_client(dd->diag_client); 195f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 196f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* Now clean up all unused client structs */ 197f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (client_pool) { 198f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc = client_pool; 199f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell client_pool = dc->next; 200f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell kfree(dc); 201f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 202f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* Clean up observer list */ 203f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_unregister_observers(dd); 204f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 205f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 206f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* qib_remap_ioaddr32 - remap an offset into chip address space to __iomem * 207f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 208f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @dd: the qlogic_ib device 209f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @offs: the offset in chip-space 210f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @cntp: Pointer to max (byte) count for transfer starting at offset 211f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * This returns a u32 __iomem * so it can be used for both 64 and 32-bit 212f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * mapping. It is needed because with the use of PAT for control of 213f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * write-combining, the logically contiguous address-space of the chip 214f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * may be split into virtually non-contiguous spaces, with different 215f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * attributes, which are them mapped to contiguous physical space 216f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * based from the first BAR. 217f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 218f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * The code below makes the same assumptions as were made in 219f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * init_chip_wc_pat() (qib_init.c), copied here: 220f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Assumes chip address space looks like: 221f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * - kregs + sregs + cregs + uregs (in any order) 222f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * - piobufs (2K and 4K bufs in either order) 223f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * or: 224f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * - kregs + sregs + cregs (in any order) 225f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * - piobufs (2K and 4K bufs in either order) 226f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * - uregs 227f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 228f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * If cntp is non-NULL, returns how many bytes from offset can be accessed 229f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Returns 0 if the offset is not mapped. 230f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 231f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, 232f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 *cntp) 233f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 234f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 kreglen; 235f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 snd_bottom, snd_lim = 0; 236f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 __iomem *krb32 = (u32 __iomem *)dd->kregbase; 237f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 __iomem *map = NULL; 238f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 cnt = 0; 239fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson u32 tot4k, offs4k; 240f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 241f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* First, simplest case, offset is within the first map. */ 242f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell kreglen = (dd->kregend - dd->kregbase) * sizeof(u64); 243f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (offset < kreglen) { 244f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell map = krb32 + (offset / sizeof(u32)); 245f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell cnt = kreglen - offset; 246f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto mapped; 247f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 248f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 249f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 250f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Next check for user regs, the next most common case, 251f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * and a cheap check because if they are not in the first map 252f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * they are last in chip. 253f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 254f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dd->userbase) { 255f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* If user regs mapped, they are after send, so set limit. */ 256f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase; 257fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson if (!dd->piovl15base) 258fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson snd_lim = dd->uregbase; 259f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell krb32 = (u32 __iomem *)dd->userbase; 260f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (offset >= dd->uregbase && offset < ulim) { 261f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell map = krb32 + (offset - dd->uregbase) / sizeof(u32); 262f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell cnt = ulim - offset; 263f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto mapped; 264f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 265f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 266f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 267f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 268f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Lastly, check for offset within Send Buffers. 269f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * This is gnarly because struct devdata is deliberately vague 270f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * about things like 7322 VL15 buffers, and we are not in 271f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * chip-specific code here, so should not make many assumptions. 272f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * The one we _do_ make is that the only chip that has more sndbufs 273f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * than we admit is the 7322, and it has userregs above that, so 274f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * we know the snd_lim. 275f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 276f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* Assume 2K buffers are first. */ 277f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell snd_bottom = dd->pio2k_bufbase; 278f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (snd_lim == 0) { 279f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 tot2k = dd->piobcnt2k * ALIGN(dd->piosize2k, dd->palign); 280f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell snd_lim = snd_bottom + tot2k; 281f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 282f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* If 4k buffers exist, account for them by bumping 283f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * appropriate limit. 284f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 285fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson tot4k = dd->piobcnt4k * dd->align4k; 286fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson offs4k = dd->piobufbase >> 32; 287f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dd->piobcnt4k) { 288f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (snd_bottom > offs4k) 289f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell snd_bottom = offs4k; 290f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else { 291f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 4k above 2k. Bump snd_lim, if needed*/ 292fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson if (!dd->userbase || dd->piovl15base) 293f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell snd_lim = offs4k + tot4k; 294f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 295f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 296f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 297f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Judgement call: can we ignore the space between SendBuffs and 298f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * UserRegs, where we would like to see vl15 buffs, but not more? 299f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 300f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (offset >= snd_bottom && offset < snd_lim) { 301f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell offset -= snd_bottom; 302f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell map = (u32 __iomem *)dd->piobase + (offset / sizeof(u32)); 303f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell cnt = snd_lim - offset; 304f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 305f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 306fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson if (!map && offs4k && dd->piovl15base) { 307fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson snd_lim = offs4k + tot4k + 2 * dd->align4k; 308fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson if (offset >= (offs4k + tot4k) && offset < snd_lim) { 309fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson map = (u32 __iomem *)dd->piovl15base + 310fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson ((offset - (offs4k + tot4k)) / sizeof(u32)); 311fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson cnt = snd_lim - offset; 312fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson } 313fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson } 314fce24a9d28f8b99fd0eacc14e252ab4fca9527a7Dave Olson 315f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellmapped: 316f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (cntp) 317f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *cntp = cnt; 318f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return map; 319f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 320f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 321f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 322f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * qib_read_umem64 - read a 64-bit quantity from the chip into user space 323f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @dd: the qlogic_ib device 324f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @uaddr: the location to store the data in user memory 325f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore) 326f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @count: number of bytes to copy (multiple of 32 bits) 327f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 328f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * This function also localizes all chip memory accesses. 329f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * The copy should be written such that we read full cacheline packets 330f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * from the chip. This is usually used for a single qword 331f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 332f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * NOTE: This assumes the chip address is 64-bit aligned. 333f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 334f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_read_umem64(struct qib_devdata *dd, void __user *uaddr, 335f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 regoffs, size_t count) 336f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 337f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const u64 __iomem *reg_addr; 338f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const u64 __iomem *reg_end; 339f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 limit; 340f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int ret; 341f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 342f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr = (const u64 __iomem *)qib_remap_ioaddr32(dd, regoffs, &limit); 343f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) { 344f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 345f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 346f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 347f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count >= limit) 348f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count = limit; 349f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_end = reg_addr + (count / sizeof(u64)); 350f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 351f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* not very efficient, but it works for now */ 352f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (reg_addr < reg_end) { 353f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u64 data = readq(reg_addr); 354f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 355f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (copy_to_user(uaddr, &data, sizeof(u64))) { 356f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 357f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 358f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 359f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr++; 360f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell uaddr += sizeof(u64); 361f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 362f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 363f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 364f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 365f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 366f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 367f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 368f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * qib_write_umem64 - write a 64-bit quantity to the chip from user space 369f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @dd: the qlogic_ib device 370f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore) 371f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @uaddr: the source of the data in user memory 372f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @count: the number of bytes to copy (multiple of 32 bits) 373f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 374f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * This is usually used for a single qword 375f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * NOTE: This assumes the chip address is 64-bit aligned. 376f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 377f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 378f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_write_umem64(struct qib_devdata *dd, u32 regoffs, 379f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const void __user *uaddr, size_t count) 380f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 381f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u64 __iomem *reg_addr; 382f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const u64 __iomem *reg_end; 383f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 limit; 384f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int ret; 385f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 386f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr = (u64 __iomem *)qib_remap_ioaddr32(dd, regoffs, &limit); 387f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) { 388f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 389f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 390f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 391f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count >= limit) 392f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count = limit; 393f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_end = reg_addr + (count / sizeof(u64)); 394f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 395f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* not very efficient, but it works for now */ 396f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (reg_addr < reg_end) { 397f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u64 data; 398f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (copy_from_user(&data, uaddr, sizeof(data))) { 399f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 400f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 401f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 402f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell writeq(data, reg_addr); 403f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 404f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr++; 405f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell uaddr += sizeof(u64); 406f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 407f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 408f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 409f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 410f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 411f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 412f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 413f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * qib_read_umem32 - read a 32-bit quantity from the chip into user space 414f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @dd: the qlogic_ib device 415f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @uaddr: the location to store the data in user memory 416f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore) 417f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @count: number of bytes to copy 418f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 419f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * read 32 bit values, not 64 bit; for memories that only 420f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * support 32 bit reads; usually a single dword. 421f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 422f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_read_umem32(struct qib_devdata *dd, void __user *uaddr, 423f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 regoffs, size_t count) 424f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 425f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const u32 __iomem *reg_addr; 426f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const u32 __iomem *reg_end; 427f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 limit; 428f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int ret; 429f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 430f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr = qib_remap_ioaddr32(dd, regoffs, &limit); 431f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) { 432f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 433f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 434f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 435f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count >= limit) 436f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count = limit; 437f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_end = reg_addr + (count / sizeof(u32)); 438f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 439f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* not very efficient, but it works for now */ 440f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (reg_addr < reg_end) { 441f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 data = readl(reg_addr); 442f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 443f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (copy_to_user(uaddr, &data, sizeof(data))) { 444f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 445f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 446f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 447f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 448f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr++; 449f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell uaddr += sizeof(u32); 450f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 451f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 452f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 453f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 454f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 455f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 456f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 457f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 458f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * qib_write_umem32 - write a 32-bit quantity to the chip from user space 459f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @dd: the qlogic_ib device 460f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @regoffs: the offset from BAR0 (_NOT_ full pointer, anymore) 461f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @uaddr: the source of the data in user memory 462f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @count: number of bytes to copy 463f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * 464f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * write 32 bit values, not 64 bit; for memories that only 465f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * support 32 bit write; usually a single dword. 466f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 467f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 468f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_write_umem32(struct qib_devdata *dd, u32 regoffs, 469f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const void __user *uaddr, size_t count) 470f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 471f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 __iomem *reg_addr; 472f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const u32 __iomem *reg_end; 473f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 limit; 474f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int ret; 475f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 476f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr = qib_remap_ioaddr32(dd, regoffs, &limit); 477f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (reg_addr == NULL || limit == 0 || !(dd->flags & QIB_PRESENT)) { 478f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 479f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 480f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 481f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count >= limit) 482f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count = limit; 483f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_end = reg_addr + (count / sizeof(u32)); 484f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 485f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (reg_addr < reg_end) { 486f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 data; 487f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 488f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (copy_from_user(&data, uaddr, sizeof(data))) { 489f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 490f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 491f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 492f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell writel(data, reg_addr); 493f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 494f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell reg_addr++; 495f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell uaddr += sizeof(u32); 496f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 497f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 498f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 499f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 500f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 501f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 502f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_diag_open(struct inode *in, struct file *fp) 503f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 504f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int unit = iminor(in) - QIB_DIAG_MINOR_BASE; 505f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_devdata *dd; 506f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_client *dc; 507f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int ret; 508f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 509f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell mutex_lock(&qib_mutex); 510f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 511f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd = qib_lookup(unit); 512f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 513f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dd == NULL || !(dd->flags & QIB_PRESENT) || 514f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell !dd->kregbase) { 515f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -ENODEV; 516f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 517f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 518f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 519f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc = get_client(dd); 520f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!dc) { 521f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -ENOMEM; 522f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 523f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 524f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc->next = dd->diag_client; 525f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd->diag_client = dc; 526f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell fp->private_data = dc; 527f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 528f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 529f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell mutex_unlock(&qib_mutex); 530f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 531f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 532f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 533f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 534f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/** 535f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * qib_diagpkt_write - write an IB packet 536f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @fp: the diag data device file pointer 537f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @data: qib_diag_pkt structure saying where to get the packet 538f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @count: size of data to write 539f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * @off: unused by this code 540f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 541f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic ssize_t qib_diagpkt_write(struct file *fp, 542f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const char __user *data, 543f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell size_t count, loff_t *off) 544f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 545f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 __iomem *piobuf; 546f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 plen, clen, pbufn; 547f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_xpkt dp; 548f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 *tmpbuf = NULL; 549f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_devdata *dd; 550f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_pportdata *ppd; 551f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ssize_t ret = 0; 552f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 553f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count != sizeof(dp)) { 554f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 555f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 556f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 557f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (copy_from_user(&dp, data, sizeof(dp))) { 558f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 559f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 560f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 561f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 562f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd = qib_lookup(dp.unit); 563f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!dd || !(dd->flags & QIB_PRESENT) || !dd->kregbase) { 564f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -ENODEV; 565f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 566f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 567f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!(dd->flags & QIB_INITTED)) { 568f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* no hardware, freeze, etc. */ 569f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -ENODEV; 570f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 571f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 572f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 573f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dp.version != _DIAG_XPKT_VERS) { 574f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_dev_err(dd, "Invalid version %u for diagpkt_write\n", 575f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dp.version); 576f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 577f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 578f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 579f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* send count must be an exact number of dwords */ 580f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dp.len & 3) { 581f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 582f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 583f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 584f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!dp.port || dp.port > dd->num_pports) { 585f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 586f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 587f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 588f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ppd = &dd->pport[dp.port - 1]; 589f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 590f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* need total length before first word written */ 591f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* +1 word is for the qword padding */ 592f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell plen = sizeof(u32) + dp.len; 593f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell clen = dp.len >> 2; 594f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 595f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if ((plen + 4) > ppd->ibmaxlen) { 596f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 597f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; /* before writing pbc */ 598f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 599f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell tmpbuf = vmalloc(plen); 600f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!tmpbuf) { 601f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_devinfo(dd->pcidev, "Unable to allocate tmp buffer, " 602f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell "failing\n"); 603f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -ENOMEM; 604f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 605f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 606f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 607f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (copy_from_user(tmpbuf, 608f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell (const void __user *) (unsigned long) dp.data, 609f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dp.len)) { 610f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 611f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 612f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 613f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 614f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell plen >>= 2; /* in dwords */ 615f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 616f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dp.pbc_wd == 0) 617f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dp.pbc_wd = plen; 618f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 619f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell piobuf = dd->f_getsendbuf(ppd, dp.pbc_wd, &pbufn); 620f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!piobuf) { 621f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EBUSY; 622f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 623f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 624f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* disarm it just to be extra sure */ 625f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(pbufn)); 626f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 627f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* disable header check on pbufn for this packet */ 628f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_DIS1, NULL); 629f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 630f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell writeq(dp.pbc_wd, piobuf); 631f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 632f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Copy all but the trigger word, then flush, so it's written 633f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * to chip before trigger word, then write trigger word, then 634f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * flush again, so packet is sent. 635f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 636f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dd->flags & QIB_PIO_FLUSH_WC) { 637f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_flush_wc(); 638f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_pio_copy(piobuf + 2, tmpbuf, clen - 1); 639f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_flush_wc(); 640f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); 641f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } else 642f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_pio_copy(piobuf + 2, tmpbuf, clen); 643f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 644f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dd->flags & QIB_USE_SPCL_TRIG) { 645f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023; 646f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 647f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_flush_wc(); 648f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell __raw_writel(0xaebecede, piobuf + spcl_off); 649f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 650f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 651f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 652f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Ensure buffer is written to the chip, then re-enable 653f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * header checks (if supported by chip). The txchk 654f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * code will ensure seen by chip before returning. 655f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 656f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_flush_wc(); 657f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell qib_sendbuf_done(dd, pbufn); 658f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_ENAB1, NULL); 659f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 660f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = sizeof(dp); 661f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 662f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 663f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell vfree(tmpbuf); 664f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 665f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 666f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 667f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic int qib_diag_release(struct inode *in, struct file *fp) 668f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 669f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell mutex_lock(&qib_mutex); 670f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return_client(fp->private_data); 671f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell fp->private_data = NULL; 672f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell mutex_unlock(&qib_mutex); 673f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return 0; 674f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 675f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 676f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 677f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Chip-specific code calls to register its interest in 678f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * a specific range. 679f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 680f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstruct diag_observer_list_elt { 681f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct diag_observer_list_elt *next; 682f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const struct diag_observer *op; 683f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell}; 684f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 685f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellint qib_register_observer(struct qib_devdata *dd, 686f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const struct diag_observer *op) 687f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 688f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct diag_observer_list_elt *olp; 689f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int ret = -EINVAL; 690f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 691f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!dd || !op) 692f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 693f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -ENOMEM; 694f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell olp = vmalloc(sizeof *olp); 695f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!olp) { 696f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell printk(KERN_ERR QIB_DRV_NAME ": vmalloc for observer failed\n"); 697f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 698f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 699f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (olp) { 700f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell unsigned long flags; 701f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 702f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_lock_irqsave(&dd->qib_diag_trans_lock, flags); 703f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell olp->op = op; 704f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell olp->next = dd->diag_observer_list; 705f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd->diag_observer_list = olp; 706f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags); 707f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 708f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 709f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 710f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 711f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 712f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 713f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* Remove all registered observers when device is closed */ 714f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic void qib_unregister_observers(struct qib_devdata *dd) 715f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 716f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct diag_observer_list_elt *olp; 717f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell unsigned long flags; 718f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 719f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_lock_irqsave(&dd->qib_diag_trans_lock, flags); 720f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell olp = dd->diag_observer_list; 721f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (olp) { 722f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* Pop one observer, let go of lock */ 723f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dd->diag_observer_list = olp->next; 724f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags); 725f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell vfree(olp); 726f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* try again. */ 727f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_lock_irqsave(&dd->qib_diag_trans_lock, flags); 728f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell olp = dd->diag_observer_list; 729f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 730f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags); 731f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 732f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 733f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell/* 734f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Find the observer, if any, for the specified address. Initial implementation 735f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * is simple stack of observers. This must be called with diag transaction 736f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * lock held. 737f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 738f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic const struct diag_observer *diag_get_observer(struct qib_devdata *dd, 739f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 addr) 740f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 741f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct diag_observer_list_elt *olp; 742f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const struct diag_observer *op = NULL; 743f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 744f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell olp = dd->diag_observer_list; 745f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell while (olp) { 746f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell op = olp->op; 747f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (addr >= op->bottom && addr <= op->top) 748f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell break; 749f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell olp = olp->next; 750f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 751f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!olp) 752f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell op = NULL; 753f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 754f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return op; 755f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 756f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 757f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic ssize_t qib_diag_read(struct file *fp, char __user *data, 758f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell size_t count, loff_t *off) 759f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 760f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_client *dc = fp->private_data; 761f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_devdata *dd = dc->dd; 762f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell void __iomem *kreg_base; 763f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ssize_t ret; 764f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 765f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc->pid != current->pid) { 766f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EPERM; 767f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 768f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 769f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 770f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell kreg_base = dd->kregbase; 771f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 772f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count == 0) 773f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 774f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else if ((count % 4) || (*off % 4)) 775f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* address or length is not 32-bit aligned, hence invalid */ 776f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 777f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else if (dc->state < READY && (*off || count != 8)) 778f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; /* prevent cat /dev/qib_diag* */ 779f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else { 780f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell unsigned long flags; 781f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u64 data64 = 0; 782f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int use_32; 783f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const struct diag_observer *op; 784f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 785f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell use_32 = (count % 8) || (*off % 8); 786f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -1; 787f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_lock_irqsave(&dd->qib_diag_trans_lock, flags); 788f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 789f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Check for observer on this address range. 790f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * we only support a single 32 or 64-bit read 791f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * via observer, currently. 792f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 793f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell op = diag_get_observer(dd, *off); 794f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (op) { 795f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 offset = *off; 796f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = op->hook(dd, op, offset, &data64, 0, use_32); 797f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 798f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 799f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * We need to release lock before any copy_to_user(), 800f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * whether implicit in qib_read_umem* or explicit below. 801f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 802f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags); 803f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!op) { 804f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (use_32) 805f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 806f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Address or length is not 64-bit aligned; 807f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * do 32-bit rd 808f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 809f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = qib_read_umem32(dd, data, (u32) *off, 810f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count); 811f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else 812f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = qib_read_umem64(dd, data, (u32) *off, 813f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count); 814f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } else if (ret == count) { 815f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* Below finishes case where observer existed */ 816f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = copy_to_user(data, &data64, use_32 ? 817f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell sizeof(u32) : sizeof(u64)); 818f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (ret) 819f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 820f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 821f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 822f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 823f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (ret >= 0) { 824f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *off += count; 825f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = count; 826f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc->state == OPENED) 827f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc->state = INIT; 828f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 829f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 830f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 831f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 832f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 833f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellstatic ssize_t qib_diag_write(struct file *fp, const char __user *data, 834f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell size_t count, loff_t *off) 835f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell{ 836f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_diag_client *dc = fp->private_data; 837f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell struct qib_devdata *dd = dc->dd; 838f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell void __iomem *kreg_base; 839f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ssize_t ret; 840f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 841f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc->pid != current->pid) { 842f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EPERM; 843f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 844f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 845f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 846f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell kreg_base = dd->kregbase; 847f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 848f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count == 0) 849f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = 0; 850f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else if ((count % 4) || (*off % 4)) 851f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* address or length is not 32-bit aligned, hence invalid */ 852f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; 853f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else if (dc->state < READY && 854f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ((*off || count != 8) || dc->state != INIT)) 855f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* No writes except second-step of init seq */ 856f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EINVAL; /* before any other write allowed */ 857f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else { 858f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell unsigned long flags; 859f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell const struct diag_observer *op = NULL; 860f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell int use_32 = (count % 8) || (*off % 8); 861f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 862f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 863f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Check for observer on this address range. 864f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * We only support a single 32 or 64-bit write 865f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * via observer, currently. This helps, because 866f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * we would otherwise have to jump through hoops 867f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * to make "diag transaction" meaningful when we 868f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * cannot do a copy_from_user while holding the lock. 869f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 870f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (count == 4 || count == 8) { 871f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u64 data64; 872f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell u32 offset = *off; 873f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = copy_from_user(&data64, data, count); 874f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (ret) { 875f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = -EFAULT; 876f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell goto bail; 877f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 878f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_lock_irqsave(&dd->qib_diag_trans_lock, flags); 879f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell op = diag_get_observer(dd, *off); 880f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (op) 881f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = op->hook(dd, op, offset, &data64, ~0Ull, 882f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell use_32); 883f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell spin_unlock_irqrestore(&dd->qib_diag_trans_lock, flags); 884f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 885f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 886f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (!op) { 887f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (use_32) 888f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell /* 889f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * Address or length is not 64-bit aligned; 890f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell * do 32-bit write 891f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell */ 892f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = qib_write_umem32(dd, (u32) *off, data, 893f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count); 894f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell else 895f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = qib_write_umem64(dd, (u32) *off, data, 896f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell count); 897f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 898f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 899f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell 900f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (ret >= 0) { 901f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell *off += count; 902f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell ret = count; 903f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell if (dc->state == INIT) 904f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell dc->state = READY; /* all read/write OK now */ 905f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell } 906f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbellbail: 907f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell return ret; 908f931551bafe1f10ded7f5282e2aa162c267a2e5dRalph Campbell} 909