View | Details | Raw Unified | Return to bug 146438
Collapse All | Expand All

(-)drivers/pci/fixup-parent-busses.c (+134 lines)
Line 0 Link Here
1
#include <linux/module.h>
2
#include <linux/pci.h>
3
4
MODULE_DESCRIPTION("test module for fixing up parent subordinate numbers after PCI scan");
5
MODULE_LICENSE("GPL");
6
static char config[33] = "";
7
static struct kparam_string kps = {
8
	.string = config,
9
	.maxlen = 33,
10
};
11
12
static int init_fixup_parent_subord(void)
13
{
14
	return 0;
15
}
16
17
static void cleanup_fixup_parent_subord(void)
18
{
19
}
20
21
static int pci_bus_is_parent_of(struct pci_bus *bus, struct pci_bus *hidden) {
22
	printk(KERN_WARNING "Bus #%02x-#%02x primary: #%02x is parent of\n",
23
	       bus->secondary, bus->subordinate, bus->primary);
24
	printk(KERN_WARNING "Bus #%02x-#%02x primary: #%02x ?\n",
25
	       hidden->secondary, hidden->subordinate, hidden->primary);
26
	for (hidden = hidden->parent; hidden; hidden=hidden->parent) {
27
           if (bus == hidden) {
28
		printk(KERN_WARNING "yes, it is.\n");
29
		return 1;
30
		}
31
	}
32
	printk(KERN_WARNING "no, it's not\n");
33
	return 0;
34
}
35
36
static unsigned char pci_find_free_subordinate(struct pci_bus *bus, struct pci_bus *hidden)
37
{
38
	struct list_head *tmp;
39
        unsigned char subordinate, highest_free_subordinate = 0xff;
40
	printk(KERN_WARNING "find free subordinates - checking Bus #%02x-#%02x primary: #%02x\n",
41
	       bus->secondary, bus->subordinate, bus->primary);
42
43
	list_for_each(tmp, &bus->children) {
44
		subordinate = pci_find_free_subordinate(pci_bus_b(tmp), hidden);
45
			printk(KERN_WARNING "find max subordinate is #%02x (#%02x)!\n",subordinate,highest_free_subordinate);
46
		if (subordinate < highest_free_subordinate)
47
			highest_free_subordinate = subordinate;
48
	}
49
50
	if (!pci_bus_is_parent_of(bus, hidden)) {
51
		printk(KERN_WARNING "Secondary is #%02x, hidden's secondary: #%02x (max: #%02x)\n",
52
			bus->secondary, hidden->secondary, highest_free_subordinate);
53
		if (bus->secondary > hidden->secondary && // It's above
54
		    bus->secondary <= highest_free_subordinate) { // but overlaps
55
			printk(KERN_WARNING "Secondary is #%02x, don't overlap it!\n",bus->secondary);
56
			return bus->secondary-1;
57
		}
58
	}
59
	return highest_free_subordinate;
60
}
61
                
62
static unsigned char pci_get_free_subordinate(struct pci_bus *hidden)
63
{
64
	struct pci_bus *bus = NULL;
65
        unsigned char subordinate, highest_free_subordinate = 0xff;
66
67
	while ((bus = pci_find_next_bus(bus)) != NULL) {
68
                subordinate = pci_find_free_subordinate(bus, hidden);
69
			printk(KERN_WARNING "max subordinate is #%02x (#%02x)!\n",subordinate,highest_free_subordinate);
70
                if (subordinate < highest_free_subordinate)
71
                        highest_free_subordinate = subordinate;
72
	}
73
        return highest_free_subordinate;
74
}
75
76
static void fixup_parent_subord_subordinate(struct pci_bus *hidden, struct pci_bus *parent)
77
{
78
	unsigned char free_subordinate;
79
        printk(KERN_WARNING "PCI: Bus #%02x (-#%02x) is "
80
                            "hidden behind bridge #%02x (-#%02x)\n",
81
                               hidden->number, hidden->subordinate,
82
                               parent->number, parent->subordinate);
83
84
	free_subordinate = pci_get_free_subordinate(hidden);
85
86
	printk("Result: free subordinate: #%02x parent's subordinate: #%02x\n",
87
		free_subordinate, parent->subordinate);
88
89
	if (free_subordinate > parent->subordinate) {
90
		free_subordinate = min(free_subordinate, hidden->subordinate);
91
		printk("Fixing up subordinate of #%02x from #%02x to #%02x\n",
92
			parent->number, parent->subordinate, free_subordinate);
93
		parent->subordinate = free_subordinate;
94
		pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, parent->subordinate);
95
	}
96
}
97
98
static void fix_walk_bus(struct pci_bus *bus)
99
{
100
	struct list_head *tmp;
101
	printk(KERN_WARNING "checking Bus #%02x-#%02x primary: #%02x\n",
102
	       bus->secondary, bus->subordinate, bus->primary);
103
/* For testing only: sets the pci bus list entries to their initial values on Samsung X20:
104
	if (bus->number == 6) bus->subordinate = 6;
105
	if (bus->number == 0) bus->subordinate = 0x0a;
106
	// This changes the X20's unused PCI-X bus to become a overlapping bus for testing:
107
	if (bus->number == 2) bus->secondary = 0x0a;
108
	if (bus->number == 2) bus->subordinate = 0x0b;
109
*/
110
111
	list_for_each(tmp, &bus->children)
112
		fix_walk_bus(pci_bus_b(tmp));
113
114
	if (bus->parent) {
115
		struct pci_bus *parent;
116
		for (parent = bus->parent; parent && parent->parent; parent=parent->parent)
117
            	    if (bus->subordinate > parent->subordinate)
118
			fixup_parent_subord_subordinate(bus, parent);
119
                
120
	}
121
}
122
123
static int param_set_fixup_parent_subord_var(const char *kmessage, struct kernel_param *kp)
124
{
125
	struct pci_bus * bus = NULL;
126
	while ((bus = pci_find_next_bus(bus)) != NULL)
127
		fix_walk_bus(bus);
128
	return 0;
129
}
130
131
module_init(init_fixup_parent_subord);
132
module_exit(cleanup_fixup_parent_subord);
133
module_param_call(fixup_parent_subord, param_set_fixup_parent_subord_var, param_get_string, &kps, 0644);
134
MODULE_PARM_DESC(fixup_parent_subord, "");
(-)drivers/pci/Makefile (+2 lines)
Lines 40-45 Link Here
40
obj-y += syscall.o
40
obj-y += syscall.o
41
endif
41
endif
42
42
43
obj-m += fixup-parent-busses.o
44
43
ifeq ($(CONFIG_PCI_DEBUG),y)
45
ifeq ($(CONFIG_PCI_DEBUG),y)
44
EXTRA_CFLAGS += -DDEBUG
46
EXTRA_CFLAGS += -DDEBUG
45
endif
47
endif

Return to bug 146438