1 /* 2 * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the Free 6 * Software Foundation; either version 2 of the License, or (at your option) 7 * any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 59 16 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * The full GNU General Public License is included in this distribution in the 19 * file called COPYING. 20 */ 21 22 /* 23 * This driver supports an interface for DCA clients and providers to meet. 24 */ 25 26 #include <linux/kernel.h> 27 #include <linux/notifier.h> 28 #include <linux/device.h> 29 #include <linux/dca.h> 30 #include <linux/slab.h> 31 32 #define DCA_VERSION "1.12.1" 33 34 MODULE_VERSION(DCA_VERSION); 35 MODULE_LICENSE("GPL"); 36 MODULE_AUTHOR("Intel Corporation"); 37 38 static DEFINE_SPINLOCK(dca_lock); 39 40 static LIST_HEAD(dca_domains); 41 42 static struct pci_bus *dca_pci_rc_from_dev(struct device *dev) 43 { 44 struct pci_dev *pdev = to_pci_dev(dev); 45 struct pci_bus *bus = pdev->bus; 46 47 while (bus->parent) 48 bus = bus->parent; 49 50 return bus; 51 } 52 53 static struct dca_domain *dca_allocate_domain(struct pci_bus *rc) 54 { 55 struct dca_domain *domain; 56 57 domain = kzalloc(sizeof(*domain), GFP_NOWAIT); 58 if (!domain) 59 return NULL; 60 61 INIT_LIST_HEAD(&domain->dca_providers); 62 domain->pci_rc = rc; 63 64 return domain; 65 } 66 67 static void dca_free_domain(struct dca_domain *domain) 68 { 69 list_del(&domain->node); 70 kfree(domain); 71 } 72 73 static struct dca_domain *dca_find_domain(struct pci_bus *rc) 74 { 75 struct dca_domain *domain; 76 77 list_for_each_entry(domain, &dca_domains, node) 78 if (domain->pci_rc == rc) 79 return domain; 80 81 return NULL; 82 } 83 84 static struct dca_domain *dca_get_domain(struct device *dev) 85 { 86 struct pci_bus *rc; 87 struct dca_domain *domain; 88 89 rc = dca_pci_rc_from_dev(dev); 90 domain = dca_find_domain(rc); 91 92 if (!domain) { 93 domain = dca_allocate_domain(rc); 94 if (domain) 95 list_add(&domain->node, &dca_domains); 96 } 97 98 return domain; 99 } 100 101 static struct dca_provider *dca_find_provider_by_dev(struct device *dev) 102 { 103 struct dca_provider *dca; 104 struct pci_bus *rc; 105 struct dca_domain *domain; 106 107 if (dev) { 108 rc = dca_pci_rc_from_dev(dev); 109 domain = dca_find_domain(rc); 110 if (!domain) 111 return NULL; 112 } else { 113 if (!list_empty(&dca_domains)) 114 domain = list_first_entry(&dca_domains, 115 struct dca_domain, 116 node); 117 else 118 return NULL; 119 } 120 121 list_for_each_entry(dca, &domain->dca_providers, node) 122 if ((!dev) || (dca->ops->dev_managed(dca, dev))) 123 return dca; 124 125 return NULL; 126 } 127 128 /** 129 * dca_add_requester - add a dca client to the list 130 * @dev - the device that wants dca service 131 */ 132 int dca_add_requester(struct device *dev) 133 { 134 struct dca_provider *dca; 135 int err, slot = -ENODEV; 136 unsigned long flags; 137 struct pci_bus *pci_rc; 138 struct dca_domain *domain; 139 140 if (!dev) 141 return -EFAULT; 142 143 spin_lock_irqsave(&dca_lock, flags); 144 145 /* check if the requester has not been added already */ 146 dca = dca_find_provider_by_dev(dev); 147 if (dca) { 148 spin_unlock_irqrestore(&dca_lock, flags); 149 return -EEXIST; 150 } 151 152 pci_rc = dca_pci_rc_from_dev(dev); 153 domain = dca_find_domain(pci_rc); 154 if (!domain) { 155 spin_unlock_irqrestore(&dca_lock, flags); 156 return -ENODEV; 157 } 158 159 list_for_each_entry(dca, &domain->dca_providers, node) { 160 slot = dca->ops->add_requester(dca, dev); 161 if (slot >= 0) 162 break; 163 } 164 165 spin_unlock_irqrestore(&dca_lock, flags); 166 167 if (slot < 0) 168 return slot; 169 170 err = dca_sysfs_add_req(dca, dev, slot); 171 if (err) { 172 spin_lock_irqsave(&dca_lock, flags); 173 if (dca == dca_find_provider_by_dev(dev)) 174 dca->ops->remove_requester(dca, dev); 175 spin_unlock_irqrestore(&dca_lock, flags); 176 return err; 177 } 178 179 return 0; 180 } 181 EXPORT_SYMBOL_GPL(dca_add_requester); 182 183 /** 184 * dca_remove_requester - remove a dca client from the list 185 * @dev - the device that wants dca service 186 */ 187 int dca_remove_requester(struct device *dev) 188 { 189 struct dca_provider *dca; 190 int slot; 191 unsigned long flags; 192 193 if (!dev) 194 return -EFAULT; 195 196 spin_lock_irqsave(&dca_lock, flags); 197 dca = dca_find_provider_by_dev(dev); 198 if (!dca) { 199 spin_unlock_irqrestore(&dca_lock, flags); 200 return -ENODEV; 201 } 202 slot = dca->ops->remove_requester(dca, dev); 203 spin_unlock_irqrestore(&dca_lock, flags); 204 205 if (slot < 0) 206 return slot; 207 208 dca_sysfs_remove_req(dca, slot); 209 210 return 0; 211 } 212 EXPORT_SYMBOL_GPL(dca_remove_requester); 213 214 /** 215 * dca_common_get_tag - return the dca tag (serves both new and old api) 216 * @dev - the device that wants dca service 217 * @cpu - the cpuid as returned by get_cpu() 218 */ 219 u8 dca_common_get_tag(struct device *dev, int cpu) 220 { 221 struct dca_provider *dca; 222 u8 tag; 223 unsigned long flags; 224 225 spin_lock_irqsave(&dca_lock, flags); 226 227 dca = dca_find_provider_by_dev(dev); 228 if (!dca) { 229 spin_unlock_irqrestore(&dca_lock, flags); 230 return -ENODEV; 231 } 232 tag = dca->ops->get_tag(dca, dev, cpu); 233 234 spin_unlock_irqrestore(&dca_lock, flags); 235 return tag; 236 } 237 238 /** 239 * dca3_get_tag - return the dca tag to the requester device 240 * for the given cpu (new api) 241 * @dev - the device that wants dca service 242 * @cpu - the cpuid as returned by get_cpu() 243 */ 244 u8 dca3_get_tag(struct device *dev, int cpu) 245 { 246 if (!dev) 247 return -EFAULT; 248 249 return dca_common_get_tag(dev, cpu); 250 } 251 EXPORT_SYMBOL_GPL(dca3_get_tag); 252 253 /** 254 * dca_get_tag - return the dca tag for the given cpu (old api) 255 * @cpu - the cpuid as returned by get_cpu() 256 */ 257 u8 dca_get_tag(int cpu) 258 { 259 struct device *dev = NULL; 260 261 return dca_common_get_tag(dev, cpu); 262 } 263 EXPORT_SYMBOL_GPL(dca_get_tag); 264 265 /** 266 * alloc_dca_provider - get data struct for describing a dca provider 267 * @ops - pointer to struct of dca operation function pointers 268 * @priv_size - size of extra mem to be added for provider's needs 269 */ 270 struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size) 271 { 272 struct dca_provider *dca; 273 int alloc_size; 274 275 alloc_size = (sizeof(*dca) + priv_size); 276 dca = kzalloc(alloc_size, GFP_KERNEL); 277 if (!dca) 278 return NULL; 279 dca->ops = ops; 280 281 return dca; 282 } 283 EXPORT_SYMBOL_GPL(alloc_dca_provider); 284 285 /** 286 * free_dca_provider - release the dca provider data struct 287 * @ops - pointer to struct of dca operation function pointers 288 * @priv_size - size of extra mem to be added for provider's needs 289 */ 290 void free_dca_provider(struct dca_provider *dca) 291 { 292 kfree(dca); 293 } 294 EXPORT_SYMBOL_GPL(free_dca_provider); 295 296 static BLOCKING_NOTIFIER_HEAD(dca_provider_chain); 297 298 /** 299 * register_dca_provider - register a dca provider 300 * @dca - struct created by alloc_dca_provider() 301 * @dev - device providing dca services 302 */ 303 int register_dca_provider(struct dca_provider *dca, struct device *dev) 304 { 305 int err; 306 unsigned long flags; 307 struct dca_domain *domain; 308 309 err = dca_sysfs_add_provider(dca, dev); 310 if (err) 311 return err; 312 313 spin_lock_irqsave(&dca_lock, flags); 314 domain = dca_get_domain(dev); 315 if (!domain) { 316 spin_unlock_irqrestore(&dca_lock, flags); 317 return -ENODEV; 318 } 319 list_add(&dca->node, &domain->dca_providers); 320 spin_unlock_irqrestore(&dca_lock, flags); 321 322 blocking_notifier_call_chain(&dca_provider_chain, 323 DCA_PROVIDER_ADD, NULL); 324 return 0; 325 } 326 EXPORT_SYMBOL_GPL(register_dca_provider); 327 328 /** 329 * unregister_dca_provider - remove a dca provider 330 * @dca - struct created by alloc_dca_provider() 331 */ 332 void unregister_dca_provider(struct dca_provider *dca, struct device *dev) 333 { 334 unsigned long flags; 335 struct pci_bus *pci_rc; 336 struct dca_domain *domain; 337 338 blocking_notifier_call_chain(&dca_provider_chain, 339 DCA_PROVIDER_REMOVE, NULL); 340 341 spin_lock_irqsave(&dca_lock, flags); 342 343 list_del(&dca->node); 344 345 pci_rc = dca_pci_rc_from_dev(dev); 346 domain = dca_find_domain(pci_rc); 347 if (list_empty(&domain->dca_providers)) 348 dca_free_domain(domain); 349 350 spin_unlock_irqrestore(&dca_lock, flags); 351 352 dca_sysfs_remove_provider(dca); 353 } 354 EXPORT_SYMBOL_GPL(unregister_dca_provider); 355 356 /** 357 * dca_register_notify - register a client's notifier callback 358 */ 359 void dca_register_notify(struct notifier_block *nb) 360 { 361 blocking_notifier_chain_register(&dca_provider_chain, nb); 362 } 363 EXPORT_SYMBOL_GPL(dca_register_notify); 364 365 /** 366 * dca_unregister_notify - remove a client's notifier callback 367 */ 368 void dca_unregister_notify(struct notifier_block *nb) 369 { 370 blocking_notifier_chain_unregister(&dca_provider_chain, nb); 371 } 372 EXPORT_SYMBOL_GPL(dca_unregister_notify); 373 374 static int __init dca_init(void) 375 { 376 pr_info("dca service started, version %s\n", DCA_VERSION); 377 return dca_sysfs_init(); 378 } 379 380 static void __exit dca_exit(void) 381 { 382 dca_sysfs_exit(); 383 } 384 385 arch_initcall(dca_init); 386 module_exit(dca_exit); 387 388