|
@@ -33,22 +33,15 @@
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/pci.h>
|
|
|
|
+#include <linux/debugfs.h>
|
|
#include "cpqphp.h"
|
|
#include "cpqphp.h"
|
|
|
|
|
|
-
|
|
|
|
-/* A few routines that create sysfs entries for the hot plug controller */
|
|
|
|
-
|
|
|
|
-static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
|
|
+static int show_ctrl (struct controller *ctrl, char *buf)
|
|
{
|
|
{
|
|
- struct pci_dev *pci_dev;
|
|
|
|
- struct controller *ctrl;
|
|
|
|
- char * out = buf;
|
|
|
|
|
|
+ char *out = buf;
|
|
int index;
|
|
int index;
|
|
struct pci_resource *res;
|
|
struct pci_resource *res;
|
|
|
|
|
|
- pci_dev = container_of (dev, struct pci_dev, dev);
|
|
|
|
- ctrl = pci_get_drvdata(pci_dev);
|
|
|
|
-
|
|
|
|
out += sprintf(buf, "Free resources: memory\n");
|
|
out += sprintf(buf, "Free resources: memory\n");
|
|
index = 11;
|
|
index = 11;
|
|
res = ctrl->mem_head;
|
|
res = ctrl->mem_head;
|
|
@@ -80,22 +73,16 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
|
|
|
|
|
|
return out - buf;
|
|
return out - buf;
|
|
}
|
|
}
|
|
-static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
|
|
|
|
|
|
|
|
-static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf)
|
|
|
|
|
|
+static int show_dev (struct controller *ctrl, char *buf)
|
|
{
|
|
{
|
|
- struct pci_dev *pci_dev;
|
|
|
|
- struct controller *ctrl;
|
|
|
|
char * out = buf;
|
|
char * out = buf;
|
|
int index;
|
|
int index;
|
|
struct pci_resource *res;
|
|
struct pci_resource *res;
|
|
struct pci_func *new_slot;
|
|
struct pci_func *new_slot;
|
|
struct slot *slot;
|
|
struct slot *slot;
|
|
|
|
|
|
- pci_dev = container_of (dev, struct pci_dev, dev);
|
|
|
|
- ctrl = pci_get_drvdata(pci_dev);
|
|
|
|
-
|
|
|
|
- slot=ctrl->slot;
|
|
|
|
|
|
+ slot = ctrl->slot;
|
|
|
|
|
|
while (slot) {
|
|
while (slot) {
|
|
new_slot = cpqhp_slot_find(slot->bus, slot->device, 0);
|
|
new_slot = cpqhp_slot_find(slot->bus, slot->device, 0);
|
|
@@ -134,10 +121,117 @@ static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char
|
|
|
|
|
|
return out - buf;
|
|
return out - buf;
|
|
}
|
|
}
|
|
-static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL);
|
|
|
|
|
|
|
|
-void cpqhp_create_ctrl_files (struct controller *ctrl)
|
|
|
|
|
|
+static int spew_debug_info(struct controller *ctrl, char *data, int size)
|
|
{
|
|
{
|
|
- device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
|
|
|
|
- device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev);
|
|
|
|
|
|
+ int used;
|
|
|
|
+
|
|
|
|
+ used = size - show_ctrl(ctrl, data);
|
|
|
|
+ used = (size - used) - show_dev(ctrl, &data[used]);
|
|
|
|
+ return used;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+struct ctrl_dbg {
|
|
|
|
+ int size;
|
|
|
|
+ char *data;
|
|
|
|
+ struct controller *ctrl;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define MAX_OUTPUT (4*PAGE_SIZE)
|
|
|
|
+
|
|
|
|
+static int open(struct inode *inode, struct file *file)
|
|
|
|
+{
|
|
|
|
+ struct controller *ctrl = inode->u.generic_ip;
|
|
|
|
+ struct ctrl_dbg *dbg;
|
|
|
|
+ int retval = -ENOMEM;
|
|
|
|
+
|
|
|
|
+ lock_kernel();
|
|
|
|
+ dbg = kmalloc(sizeof(*dbg), GFP_KERNEL);
|
|
|
|
+ if (!dbg)
|
|
|
|
+ goto exit;
|
|
|
|
+ dbg->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
|
|
|
|
+ if (!dbg->data) {
|
|
|
|
+ kfree(dbg);
|
|
|
|
+ goto exit;
|
|
|
|
+ }
|
|
|
|
+ dbg->size = spew_debug_info(ctrl, dbg->data, MAX_OUTPUT);
|
|
|
|
+ file->private_data = dbg;
|
|
|
|
+ retval = 0;
|
|
|
|
+exit:
|
|
|
|
+ unlock_kernel();
|
|
|
|
+ return retval;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static loff_t lseek(struct file *file, loff_t off, int whence)
|
|
|
|
+{
|
|
|
|
+ struct ctrl_dbg *dbg;
|
|
|
|
+ loff_t new = -1;
|
|
|
|
+
|
|
|
|
+ lock_kernel();
|
|
|
|
+ dbg = file->private_data;
|
|
|
|
+
|
|
|
|
+ switch (whence) {
|
|
|
|
+ case 0:
|
|
|
|
+ new = off;
|
|
|
|
+ break;
|
|
|
|
+ case 1:
|
|
|
|
+ new = file->f_pos + off;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (new < 0 || new > dbg->size) {
|
|
|
|
+ unlock_kernel();
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ unlock_kernel();
|
|
|
|
+ return (file->f_pos = new);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+static ssize_t read(struct file *file, char __user *buf,
|
|
|
|
+ size_t nbytes, loff_t *ppos)
|
|
|
|
+{
|
|
|
|
+ struct ctrl_dbg *dbg = file->private_data;
|
|
|
|
+ return simple_read_from_buffer(buf, nbytes, ppos, dbg->data, dbg->size);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int release(struct inode *inode, struct file *file)
|
|
|
|
+{
|
|
|
|
+ struct ctrl_dbg *dbg = file->private_data;
|
|
|
|
+
|
|
|
|
+ kfree(dbg->data);
|
|
|
|
+ kfree(dbg);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct file_operations debug_ops = {
|
|
|
|
+ .owner = THIS_MODULE,
|
|
|
|
+ .open = open,
|
|
|
|
+ .llseek = lseek,
|
|
|
|
+ .read = read,
|
|
|
|
+ .release = release,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct dentry *root;
|
|
|
|
+
|
|
|
|
+void cpqhp_initialize_debugfs(void)
|
|
|
|
+{
|
|
|
|
+ if (!root)
|
|
|
|
+ root = debugfs_create_dir("cpqhp", NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void cpqhp_shutdown_debugfs(void)
|
|
|
|
+{
|
|
|
|
+ debugfs_remove(root);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void cpqhp_create_debugfs_files(struct controller *ctrl)
|
|
|
|
+{
|
|
|
|
+ ctrl->dentry = debugfs_create_file(ctrl->pci_dev->dev.bus_id, S_IRUGO, root, ctrl, &debug_ops);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void cpqhp_remove_debugfs_files(struct controller *ctrl)
|
|
|
|
+{
|
|
|
|
+ if (ctrl->dentry)
|
|
|
|
+ debugfs_remove(ctrl->dentry);
|
|
|
|
+ ctrl->dentry = NULL;
|
|
|
|
+}
|
|
|
|
+
|