]>
Commit | Line | Data |
---|---|---|
f46753c5 AC |
1 | /* |
2 | * drivers/pci/slot.c | |
3 | * Copyright (C) 2006 Matthew Wilcox <matthew@wil.cx> | |
4 | * Copyright (C) 2006-2008 Hewlett-Packard Development Company, L.P. | |
5 | * Alex Chiang <achiang@hp.com> | |
6 | */ | |
7 | ||
8 | #include <linux/kobject.h> | |
9 | #include <linux/pci.h> | |
10 | #include <linux/err.h> | |
11 | #include "pci.h" | |
12 | ||
13 | struct kset *pci_slots_kset; | |
14 | EXPORT_SYMBOL_GPL(pci_slots_kset); | |
15 | ||
16 | static ssize_t pci_slot_attr_show(struct kobject *kobj, | |
17 | struct attribute *attr, char *buf) | |
18 | { | |
19 | struct pci_slot *slot = to_pci_slot(kobj); | |
20 | struct pci_slot_attribute *attribute = to_pci_slot_attr(attr); | |
21 | return attribute->show ? attribute->show(slot, buf) : -EIO; | |
22 | } | |
23 | ||
24 | static ssize_t pci_slot_attr_store(struct kobject *kobj, | |
25 | struct attribute *attr, const char *buf, size_t len) | |
26 | { | |
27 | struct pci_slot *slot = to_pci_slot(kobj); | |
28 | struct pci_slot_attribute *attribute = to_pci_slot_attr(attr); | |
29 | return attribute->store ? attribute->store(slot, buf, len) : -EIO; | |
30 | } | |
31 | ||
32 | static struct sysfs_ops pci_slot_sysfs_ops = { | |
33 | .show = pci_slot_attr_show, | |
34 | .store = pci_slot_attr_store, | |
35 | }; | |
36 | ||
37 | static ssize_t address_read_file(struct pci_slot *slot, char *buf) | |
38 | { | |
39 | if (slot->number == 0xff) | |
40 | return sprintf(buf, "%04x:%02x\n", | |
41 | pci_domain_nr(slot->bus), | |
42 | slot->bus->number); | |
43 | else | |
44 | return sprintf(buf, "%04x:%02x:%02x\n", | |
45 | pci_domain_nr(slot->bus), | |
46 | slot->bus->number, | |
47 | slot->number); | |
48 | } | |
49 | ||
50 | static void pci_slot_release(struct kobject *kobj) | |
51 | { | |
cef354db | 52 | struct pci_dev *dev; |
f46753c5 AC |
53 | struct pci_slot *slot = to_pci_slot(kobj); |
54 | ||
55 | pr_debug("%s: releasing pci_slot on %x:%d\n", __func__, | |
56 | slot->bus->number, slot->number); | |
57 | ||
cef354db AC |
58 | list_for_each_entry(dev, &slot->bus->devices, bus_list) |
59 | if (PCI_SLOT(dev->devfn) == slot->number) | |
60 | dev->slot = NULL; | |
61 | ||
f46753c5 AC |
62 | list_del(&slot->list); |
63 | ||
64 | kfree(slot); | |
65 | } | |
66 | ||
67 | static struct pci_slot_attribute pci_slot_attr_address = | |
68 | __ATTR(address, (S_IFREG | S_IRUGO), address_read_file, NULL); | |
69 | ||
70 | static struct attribute *pci_slot_default_attrs[] = { | |
71 | &pci_slot_attr_address.attr, | |
72 | NULL, | |
73 | }; | |
74 | ||
75 | static struct kobj_type pci_slot_ktype = { | |
76 | .sysfs_ops = &pci_slot_sysfs_ops, | |
77 | .release = &pci_slot_release, | |
78 | .default_attrs = pci_slot_default_attrs, | |
79 | }; | |
80 | ||
81 | /** | |
82 | * pci_create_slot - create or increment refcount for physical PCI slot | |
83 | * @parent: struct pci_bus of parent bridge | |
84 | * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder | |
85 | * @name: user visible string presented in /sys/bus/pci/slots/<name> | |
86 | * | |
87 | * PCI slots have first class attributes such as address, speed, width, | |
88 | * and a &struct pci_slot is used to manage them. This interface will | |
89 | * either return a new &struct pci_slot to the caller, or if the pci_slot | |
90 | * already exists, its refcount will be incremented. | |
91 | * | |
92 | * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple. | |
93 | * | |
94 | * Placeholder slots: | |
95 | * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify | |
96 | * a slot. There is one notable exception - pSeries (rpaphp), where the | |
97 | * @slot_nr cannot be determined until a device is actually inserted into | |
98 | * the slot. In this scenario, the caller may pass -1 for @slot_nr. | |
99 | * | |
100 | * The following semantics are imposed when the caller passes @slot_nr == | |
101 | * -1. First, the check for existing %struct pci_slot is skipped, as the | |
102 | * caller may know about several unpopulated slots on a given %struct | |
103 | * pci_bus, and each slot would have a @slot_nr of -1. Uniqueness for | |
104 | * these slots is then determined by the @name parameter. We expect | |
105 | * kobject_init_and_add() to warn us if the caller attempts to create | |
106 | * multiple slots with the same name. The other change in semantics is | |
107 | * user-visible, which is the 'address' parameter presented in sysfs will | |
108 | * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the | |
109 | * %struct pci_bus and bb is the bus number. In other words, the devfn of | |
110 | * the 'placeholder' slot will not be displayed. | |
111 | */ | |
112 | ||
113 | struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, | |
114 | const char *name) | |
115 | { | |
cef354db | 116 | struct pci_dev *dev; |
f46753c5 AC |
117 | struct pci_slot *slot; |
118 | int err; | |
119 | ||
120 | down_write(&pci_bus_sem); | |
121 | ||
122 | if (slot_nr == -1) | |
123 | goto placeholder; | |
124 | ||
125 | /* If we've already created this slot, bump refcount and return. */ | |
126 | list_for_each_entry(slot, &parent->slots, list) { | |
127 | if (slot->number == slot_nr) { | |
128 | kobject_get(&slot->kobj); | |
129 | pr_debug("%s: inc refcount to %d on %04x:%02x:%02x\n", | |
130 | __func__, | |
131 | atomic_read(&slot->kobj.kref.refcount), | |
132 | pci_domain_nr(parent), parent->number, | |
133 | slot_nr); | |
134 | goto out; | |
135 | } | |
136 | } | |
137 | ||
138 | placeholder: | |
139 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | |
140 | if (!slot) { | |
141 | slot = ERR_PTR(-ENOMEM); | |
142 | goto out; | |
143 | } | |
144 | ||
145 | slot->bus = parent; | |
146 | slot->number = slot_nr; | |
147 | ||
148 | slot->kobj.kset = pci_slots_kset; | |
149 | err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, | |
150 | "%s", name); | |
151 | if (err) { | |
152 | printk(KERN_ERR "Unable to register kobject %s\n", name); | |
153 | goto err; | |
154 | } | |
155 | ||
156 | INIT_LIST_HEAD(&slot->list); | |
157 | list_add(&slot->list, &parent->slots); | |
158 | ||
cef354db AC |
159 | list_for_each_entry(dev, &parent->devices, bus_list) |
160 | if (PCI_SLOT(dev->devfn) == slot_nr) | |
161 | dev->slot = slot; | |
162 | ||
f46753c5 AC |
163 | /* Don't care if debug printk has a -1 for slot_nr */ |
164 | pr_debug("%s: created pci_slot on %04x:%02x:%02x\n", | |
165 | __func__, pci_domain_nr(parent), parent->number, slot_nr); | |
166 | ||
167 | out: | |
168 | up_write(&pci_bus_sem); | |
169 | return slot; | |
170 | err: | |
171 | kfree(slot); | |
172 | slot = ERR_PTR(err); | |
173 | goto out; | |
174 | } | |
175 | EXPORT_SYMBOL_GPL(pci_create_slot); | |
176 | ||
177 | /** | |
178 | * pci_update_slot_number - update %struct pci_slot -> number | |
179 | * @slot - %struct pci_slot to update | |
180 | * @slot_nr - new number for slot | |
181 | * | |
182 | * The primary purpose of this interface is to allow callers who earlier | |
183 | * created a placeholder slot in pci_create_slot() by passing a -1 as | |
184 | * slot_nr, to update their %struct pci_slot with the correct @slot_nr. | |
185 | */ | |
186 | ||
187 | void pci_update_slot_number(struct pci_slot *slot, int slot_nr) | |
188 | { | |
189 | int name_count = 0; | |
190 | struct pci_slot *tmp; | |
191 | ||
192 | down_write(&pci_bus_sem); | |
193 | ||
194 | list_for_each_entry(tmp, &slot->bus->slots, list) { | |
195 | WARN_ON(tmp->number == slot_nr); | |
196 | if (!strcmp(kobject_name(&tmp->kobj), kobject_name(&slot->kobj))) | |
197 | name_count++; | |
198 | } | |
199 | ||
200 | if (name_count > 1) | |
201 | printk(KERN_WARNING "pci_update_slot_number found %d slots with the same name: %s\n", name_count, kobject_name(&slot->kobj)); | |
202 | ||
203 | slot->number = slot_nr; | |
204 | up_write(&pci_bus_sem); | |
205 | } | |
206 | EXPORT_SYMBOL_GPL(pci_update_slot_number); | |
207 | ||
208 | /** | |
209 | * pci_destroy_slot - decrement refcount for physical PCI slot | |
210 | * @slot: struct pci_slot to decrement | |
211 | * | |
212 | * %struct pci_slot is refcounted, so destroying them is really easy; we | |
213 | * just call kobject_put on its kobj and let our release methods do the | |
214 | * rest. | |
215 | */ | |
216 | ||
217 | void pci_destroy_slot(struct pci_slot *slot) | |
218 | { | |
219 | pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__, | |
220 | atomic_read(&slot->kobj.kref.refcount) - 1, | |
221 | pci_domain_nr(slot->bus), slot->bus->number, slot->number); | |
222 | ||
223 | down_write(&pci_bus_sem); | |
224 | kobject_put(&slot->kobj); | |
225 | up_write(&pci_bus_sem); | |
226 | } | |
227 | EXPORT_SYMBOL_GPL(pci_destroy_slot); | |
228 | ||
229 | static int pci_slot_init(void) | |
230 | { | |
231 | struct kset *pci_bus_kset; | |
232 | ||
233 | pci_bus_kset = bus_get_kset(&pci_bus_type); | |
234 | pci_slots_kset = kset_create_and_add("slots", NULL, | |
235 | &pci_bus_kset->kobj); | |
236 | if (!pci_slots_kset) { | |
237 | printk(KERN_ERR "PCI: Slot initialization failure\n"); | |
238 | return -ENOMEM; | |
239 | } | |
240 | return 0; | |
241 | } | |
242 | ||
243 | subsys_initcall(pci_slot_init); |