1 /* 2 * Compaq Hot Plug Controller Driver 3 * 4 * Copyright (C) 1995,2001 Compaq Computer Corporation 5 * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) 6 * Copyright (C) 2001 IBM Corp. 7 * 8 * All rights reserved. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or (at 13 * your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 18 * NON INFRINGEMENT. See the GNU General Public License for more 19 * details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 * 25 * Send feedback to <greg@kroah.com> 26 * 27 */ 28 29 #include <linux/module.h> 30 #include <linux/kernel.h> 31 #include <linux/types.h> 32 #include <linux/proc_fs.h> 33 #include <linux/workqueue.h> 34 #include <linux/pci.h> 35 #include <linux/debugfs.h> 36 #include "cpqphp.h" 37 38 static int show_ctrl (struct controller *ctrl, char *buf) 39 { 40 char *out = buf; 41 int index; 42 struct pci_resource *res; 43 44 out += sprintf(buf, "Free resources: memory\n"); 45 index = 11; 46 res = ctrl->mem_head; 47 while (res && index--) { 48 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 49 res = res->next; 50 } 51 out += sprintf(out, "Free resources: prefetchable memory\n"); 52 index = 11; 53 res = ctrl->p_mem_head; 54 while (res && index--) { 55 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 56 res = res->next; 57 } 58 out += sprintf(out, "Free resources: IO\n"); 59 index = 11; 60 res = ctrl->io_head; 61 while (res && index--) { 62 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 63 res = res->next; 64 } 65 out += sprintf(out, "Free resources: bus numbers\n"); 66 index = 11; 67 res = ctrl->bus_head; 68 while (res && index--) { 69 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 70 res = res->next; 71 } 72 73 return out - buf; 74 } 75 76 static int show_dev (struct controller *ctrl, char *buf) 77 { 78 char * out = buf; 79 int index; 80 struct pci_resource *res; 81 struct pci_func *new_slot; 82 struct slot *slot; 83 84 slot = ctrl->slot; 85 86 while (slot) { 87 new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); 88 if (!new_slot) 89 break; 90 out += sprintf(out, "assigned resources: memory\n"); 91 index = 11; 92 res = new_slot->mem_head; 93 while (res && index--) { 94 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 95 res = res->next; 96 } 97 out += sprintf(out, "assigned resources: prefetchable memory\n"); 98 index = 11; 99 res = new_slot->p_mem_head; 100 while (res && index--) { 101 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 102 res = res->next; 103 } 104 out += sprintf(out, "assigned resources: IO\n"); 105 index = 11; 106 res = new_slot->io_head; 107 while (res && index--) { 108 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 109 res = res->next; 110 } 111 out += sprintf(out, "assigned resources: bus numbers\n"); 112 index = 11; 113 res = new_slot->bus_head; 114 while (res && index--) { 115 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); 116 res = res->next; 117 } 118 slot=slot->next; 119 } 120 121 return out - buf; 122 } 123 124 static int spew_debug_info(struct controller *ctrl, char *data, int size) 125 { 126 int used; 127 128 used = size - show_ctrl(ctrl, data); 129 used = (size - used) - show_dev(ctrl, &data[used]); 130 return used; 131 } 132 133 struct ctrl_dbg { 134 int size; 135 char *data; 136 struct controller *ctrl; 137 }; 138 139 #define MAX_OUTPUT (4*PAGE_SIZE) 140 141 static int open(struct inode *inode, struct file *file) 142 { 143 struct controller *ctrl = inode->u.generic_ip; 144 struct ctrl_dbg *dbg; 145 int retval = -ENOMEM; 146 147 lock_kernel(); 148 dbg = kmalloc(sizeof(*dbg), GFP_KERNEL); 149 if (!dbg) 150 goto exit; 151 dbg->data = kmalloc(MAX_OUTPUT, GFP_KERNEL); 152 if (!dbg->data) { 153 kfree(dbg); 154 goto exit; 155 } 156 dbg->size = spew_debug_info(ctrl, dbg->data, MAX_OUTPUT); 157 file->private_data = dbg; 158 retval = 0; 159 exit: 160 unlock_kernel(); 161 return retval; 162 } 163 164 static loff_t lseek(struct file *file, loff_t off, int whence) 165 { 166 struct ctrl_dbg *dbg; 167 loff_t new = -1; 168 169 lock_kernel(); 170 dbg = file->private_data; 171 172 switch (whence) { 173 case 0: 174 new = off; 175 break; 176 case 1: 177 new = file->f_pos + off; 178 break; 179 } 180 if (new < 0 || new > dbg->size) { 181 unlock_kernel(); 182 return -EINVAL; 183 } 184 unlock_kernel(); 185 return (file->f_pos = new); 186 } 187 188 static ssize_t read(struct file *file, char __user *buf, 189 size_t nbytes, loff_t *ppos) 190 { 191 struct ctrl_dbg *dbg = file->private_data; 192 return simple_read_from_buffer(buf, nbytes, ppos, dbg->data, dbg->size); 193 } 194 195 static int release(struct inode *inode, struct file *file) 196 { 197 struct ctrl_dbg *dbg = file->private_data; 198 199 kfree(dbg->data); 200 kfree(dbg); 201 return 0; 202 } 203 204 static struct file_operations debug_ops = { 205 .owner = THIS_MODULE, 206 .open = open, 207 .llseek = lseek, 208 .read = read, 209 .release = release, 210 }; 211 212 static struct dentry *root; 213 214 void cpqhp_initialize_debugfs(void) 215 { 216 if (!root) 217 root = debugfs_create_dir("cpqhp", NULL); 218 } 219 220 void cpqhp_shutdown_debugfs(void) 221 { 222 debugfs_remove(root); 223 } 224 225 void cpqhp_create_debugfs_files(struct controller *ctrl) 226 { 227 ctrl->dentry = debugfs_create_file(ctrl->pci_dev->dev.bus_id, S_IRUGO, root, ctrl, &debug_ops); 228 } 229 230 void cpqhp_remove_debugfs_files(struct controller *ctrl) 231 { 232 if (ctrl->dentry) 233 debugfs_remove(ctrl->dentry); 234 ctrl->dentry = NULL; 235 } 236 237