209 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Compaq Hot Plug Controller Driver4 *5 * Copyright (C) 1995,2001 Compaq Computer Corporation6 * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)7 * Copyright (C) 2001 IBM Corp.8 *9 * All rights reserved.10 *11 * Send feedback to <greg@kroah.com>12 *13 */14 15#include <linux/module.h>16#include <linux/kernel.h>17#include <linux/slab.h>18#include <linux/types.h>19#include <linux/proc_fs.h>20#include <linux/workqueue.h>21#include <linux/pci.h>22#include <linux/pci_hotplug.h>23#include <linux/mutex.h>24#include <linux/debugfs.h>25#include "cpqphp.h"26 27static DEFINE_MUTEX(cpqphp_mutex);28static int show_ctrl(struct controller *ctrl, char *buf)29{30 char *out = buf;31 int index;32 struct pci_resource *res;33 34 out += sprintf(buf, "Free resources: memory\n");35 index = 11;36 res = ctrl->mem_head;37 while (res && index--) {38 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);39 res = res->next;40 }41 out += sprintf(out, "Free resources: prefetchable memory\n");42 index = 11;43 res = ctrl->p_mem_head;44 while (res && index--) {45 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);46 res = res->next;47 }48 out += sprintf(out, "Free resources: IO\n");49 index = 11;50 res = ctrl->io_head;51 while (res && index--) {52 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);53 res = res->next;54 }55 out += sprintf(out, "Free resources: bus numbers\n");56 index = 11;57 res = ctrl->bus_head;58 while (res && index--) {59 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);60 res = res->next;61 }62 63 return out - buf;64}65 66static int show_dev(struct controller *ctrl, char *buf)67{68 char *out = buf;69 int index;70 struct pci_resource *res;71 struct pci_func *new_slot;72 struct slot *slot;73 74 slot = ctrl->slot;75 76 while (slot) {77 new_slot = cpqhp_slot_find(slot->bus, slot->device, 0);78 if (!new_slot)79 break;80 out += sprintf(out, "assigned resources: memory\n");81 index = 11;82 res = new_slot->mem_head;83 while (res && index--) {84 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);85 res = res->next;86 }87 out += sprintf(out, "assigned resources: prefetchable memory\n");88 index = 11;89 res = new_slot->p_mem_head;90 while (res && index--) {91 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);92 res = res->next;93 }94 out += sprintf(out, "assigned resources: IO\n");95 index = 11;96 res = new_slot->io_head;97 while (res && index--) {98 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);99 res = res->next;100 }101 out += sprintf(out, "assigned resources: bus numbers\n");102 index = 11;103 res = new_slot->bus_head;104 while (res && index--) {105 out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);106 res = res->next;107 }108 slot = slot->next;109 }110 111 return out - buf;112}113 114static int spew_debug_info(struct controller *ctrl, char *data, int size)115{116 int used;117 118 used = size - show_ctrl(ctrl, data);119 used = (size - used) - show_dev(ctrl, &data[used]);120 return used;121}122 123struct ctrl_dbg {124 int size;125 char *data;126 struct controller *ctrl;127};128 129#define MAX_OUTPUT (4*PAGE_SIZE)130 131static int open(struct inode *inode, struct file *file)132{133 struct controller *ctrl = inode->i_private;134 struct ctrl_dbg *dbg;135 int retval = -ENOMEM;136 137 mutex_lock(&cpqphp_mutex);138 dbg = kmalloc(sizeof(*dbg), GFP_KERNEL);139 if (!dbg)140 goto exit;141 dbg->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);142 if (!dbg->data) {143 kfree(dbg);144 goto exit;145 }146 dbg->size = spew_debug_info(ctrl, dbg->data, MAX_OUTPUT);147 file->private_data = dbg;148 retval = 0;149exit:150 mutex_unlock(&cpqphp_mutex);151 return retval;152}153 154static loff_t lseek(struct file *file, loff_t off, int whence)155{156 struct ctrl_dbg *dbg = file->private_data;157 return fixed_size_llseek(file, off, whence, dbg->size);158}159 160static ssize_t read(struct file *file, char __user *buf,161 size_t nbytes, loff_t *ppos)162{163 struct ctrl_dbg *dbg = file->private_data;164 return simple_read_from_buffer(buf, nbytes, ppos, dbg->data, dbg->size);165}166 167static int release(struct inode *inode, struct file *file)168{169 struct ctrl_dbg *dbg = file->private_data;170 171 kfree(dbg->data);172 kfree(dbg);173 return 0;174}175 176static const struct file_operations debug_ops = {177 .owner = THIS_MODULE,178 .open = open,179 .llseek = lseek,180 .read = read,181 .release = release,182};183 184static struct dentry *root;185 186void cpqhp_initialize_debugfs(void)187{188 if (!root)189 root = debugfs_create_dir("cpqhp", NULL);190}191 192void cpqhp_shutdown_debugfs(void)193{194 debugfs_remove(root);195}196 197void cpqhp_create_debugfs_files(struct controller *ctrl)198{199 ctrl->dentry = debugfs_create_file(dev_name(&ctrl->pci_dev->dev),200 S_IRUGO, root, ctrl, &debug_ops);201}202 203void cpqhp_remove_debugfs_files(struct controller *ctrl)204{205 debugfs_remove(ctrl->dentry);206 ctrl->dentry = NULL;207}208 209