Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
0004  *
0005  * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
0006  * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
0007  * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
0008  *  Bjorn Helgaas <bjorn.helgaas@hp.com>
0009  */
0010 
0011 #include <linux/errno.h>
0012 #include <linux/module.h>
0013 #include <linux/init.h>
0014 #include <linux/kernel.h>
0015 #include <linux/pnp.h>
0016 #include <linux/bitmap.h>
0017 #include <linux/mutex.h>
0018 #include "base.h"
0019 
0020 DEFINE_MUTEX(pnp_res_mutex);
0021 
0022 static struct resource *pnp_find_resource(struct pnp_dev *dev,
0023                       unsigned char rule,
0024                       unsigned long type,
0025                       unsigned int bar)
0026 {
0027     struct resource *res = pnp_get_resource(dev, type, bar);
0028 
0029     /* when the resource already exists, set its resource bits from rule */
0030     if (res) {
0031         res->flags &= ~IORESOURCE_BITS;
0032         res->flags |= rule & IORESOURCE_BITS;
0033     }
0034 
0035     return res;
0036 }
0037 
0038 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
0039 {
0040     struct resource *res, local_res;
0041 
0042     res = pnp_find_resource(dev, rule->flags, IORESOURCE_IO, idx);
0043     if (res) {
0044         pnp_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
0045             "flags %#lx\n", idx, (unsigned long long) res->start,
0046             (unsigned long long) res->end, res->flags);
0047         return 0;
0048     }
0049 
0050     res = &local_res;
0051     res->flags = rule->flags | IORESOURCE_AUTO;
0052     res->start = 0;
0053     res->end = 0;
0054 
0055     if (!rule->size) {
0056         res->flags |= IORESOURCE_DISABLED;
0057         pnp_dbg(&dev->dev, "  io %d disabled\n", idx);
0058         goto __add;
0059     }
0060 
0061     res->start = rule->min;
0062     res->end = res->start + rule->size - 1;
0063 
0064     while (!pnp_check_port(dev, res)) {
0065         res->start += rule->align;
0066         res->end = res->start + rule->size - 1;
0067         if (res->start > rule->max || !rule->align) {
0068             pnp_dbg(&dev->dev, "  couldn't assign io %d "
0069                 "(min %#llx max %#llx)\n", idx,
0070                 (unsigned long long) rule->min,
0071                 (unsigned long long) rule->max);
0072             return -EBUSY;
0073         }
0074     }
0075 
0076 __add:
0077     pnp_add_io_resource(dev, res->start, res->end, res->flags);
0078     return 0;
0079 }
0080 
0081 static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
0082 {
0083     struct resource *res, local_res;
0084 
0085     res = pnp_find_resource(dev, rule->flags, IORESOURCE_MEM, idx);
0086     if (res) {
0087         pnp_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
0088             "flags %#lx\n", idx, (unsigned long long) res->start,
0089             (unsigned long long) res->end, res->flags);
0090         return 0;
0091     }
0092 
0093     res = &local_res;
0094     res->flags = rule->flags | IORESOURCE_AUTO;
0095     res->start = 0;
0096     res->end = 0;
0097 
0098     /* ??? rule->flags restricted to 8 bits, all tests bogus ??? */
0099     if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
0100         res->flags |= IORESOURCE_READONLY;
0101     if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
0102         res->flags |= IORESOURCE_RANGELENGTH;
0103     if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
0104         res->flags |= IORESOURCE_SHADOWABLE;
0105 
0106     if (!rule->size) {
0107         res->flags |= IORESOURCE_DISABLED;
0108         pnp_dbg(&dev->dev, "  mem %d disabled\n", idx);
0109         goto __add;
0110     }
0111 
0112     res->start = rule->min;
0113     res->end = res->start + rule->size - 1;
0114 
0115     while (!pnp_check_mem(dev, res)) {
0116         res->start += rule->align;
0117         res->end = res->start + rule->size - 1;
0118         if (res->start > rule->max || !rule->align) {
0119             pnp_dbg(&dev->dev, "  couldn't assign mem %d "
0120                 "(min %#llx max %#llx)\n", idx,
0121                 (unsigned long long) rule->min,
0122                 (unsigned long long) rule->max);
0123             return -EBUSY;
0124         }
0125     }
0126 
0127 __add:
0128     pnp_add_mem_resource(dev, res->start, res->end, res->flags);
0129     return 0;
0130 }
0131 
0132 static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
0133 {
0134     struct resource *res, local_res;
0135     int i;
0136 
0137     /* IRQ priority: this table is good for i386 */
0138     static unsigned short xtab[16] = {
0139         5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
0140     };
0141 
0142     res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx);
0143     if (res) {
0144         pnp_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
0145             idx, (int) res->start, res->flags);
0146         return 0;
0147     }
0148 
0149     res = &local_res;
0150     res->flags = rule->flags | IORESOURCE_AUTO;
0151     res->start = -1;
0152     res->end = -1;
0153 
0154     if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
0155         res->flags |= IORESOURCE_DISABLED;
0156         pnp_dbg(&dev->dev, "  irq %d disabled\n", idx);
0157         goto __add;
0158     }
0159 
0160     /* TBD: need check for >16 IRQ */
0161     res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
0162     if (res->start < PNP_IRQ_NR) {
0163         res->end = res->start;
0164         goto __add;
0165     }
0166     for (i = 0; i < 16; i++) {
0167         if (test_bit(xtab[i], rule->map.bits)) {
0168             res->start = res->end = xtab[i];
0169             if (pnp_check_irq(dev, res))
0170                 goto __add;
0171         }
0172     }
0173 
0174     if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
0175         res->start = -1;
0176         res->end = -1;
0177         res->flags |= IORESOURCE_DISABLED;
0178         pnp_dbg(&dev->dev, "  irq %d disabled (optional)\n", idx);
0179         goto __add;
0180     }
0181 
0182     pnp_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
0183     return -EBUSY;
0184 
0185 __add:
0186     pnp_add_irq_resource(dev, res->start, res->flags);
0187     return 0;
0188 }
0189 
0190 #ifdef CONFIG_ISA_DMA_API
0191 static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
0192 {
0193     struct resource *res, local_res;
0194     int i;
0195 
0196     /* DMA priority: this table is good for i386 */
0197     static unsigned short xtab[8] = {
0198         1, 3, 5, 6, 7, 0, 2, 4
0199     };
0200 
0201     res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx);
0202     if (res) {
0203         pnp_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
0204             idx, (int) res->start, res->flags);
0205         return 0;
0206     }
0207 
0208     res = &local_res;
0209     res->flags = rule->flags | IORESOURCE_AUTO;
0210     res->start = -1;
0211     res->end = -1;
0212 
0213     if (!rule->map) {
0214         res->flags |= IORESOURCE_DISABLED;
0215         pnp_dbg(&dev->dev, "  dma %d disabled\n", idx);
0216         goto __add;
0217     }
0218 
0219     for (i = 0; i < 8; i++) {
0220         if (rule->map & (1 << xtab[i])) {
0221             res->start = res->end = xtab[i];
0222             if (pnp_check_dma(dev, res))
0223                 goto __add;
0224         }
0225     }
0226 
0227     pnp_dbg(&dev->dev, "  couldn't assign dma %d\n", idx);
0228     return -EBUSY;
0229 
0230 __add:
0231     pnp_add_dma_resource(dev, res->start, res->flags);
0232     return 0;
0233 }
0234 #endif /* CONFIG_ISA_DMA_API */
0235 
0236 void pnp_init_resources(struct pnp_dev *dev)
0237 {
0238     pnp_free_resources(dev);
0239 }
0240 
0241 static void pnp_clean_resource_table(struct pnp_dev *dev)
0242 {
0243     struct pnp_resource *pnp_res, *tmp;
0244 
0245     list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
0246         if (pnp_res->res.flags & IORESOURCE_AUTO)
0247             pnp_free_resource(pnp_res);
0248     }
0249 }
0250 
0251 /**
0252  * pnp_assign_resources - assigns resources to the device based on the specified dependent number
0253  * @dev: pointer to the desired device
0254  * @set: the dependent function number
0255  */
0256 static int pnp_assign_resources(struct pnp_dev *dev, int set)
0257 {
0258     struct pnp_option *option;
0259     int nport = 0, nmem = 0, nirq = 0;
0260     int ndma __maybe_unused = 0;
0261     int ret = 0;
0262 
0263     pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
0264     mutex_lock(&pnp_res_mutex);
0265     pnp_clean_resource_table(dev);
0266 
0267     list_for_each_entry(option, &dev->options, list) {
0268         if (pnp_option_is_dependent(option) &&
0269             pnp_option_set(option) != set)
0270                 continue;
0271 
0272         switch (option->type) {
0273         case IORESOURCE_IO:
0274             ret = pnp_assign_port(dev, &option->u.port, nport++);
0275             break;
0276         case IORESOURCE_MEM:
0277             ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
0278             break;
0279         case IORESOURCE_IRQ:
0280             ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
0281             break;
0282 #ifdef CONFIG_ISA_DMA_API
0283         case IORESOURCE_DMA:
0284             ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
0285             break;
0286 #endif
0287         default:
0288             ret = -EINVAL;
0289             break;
0290         }
0291         if (ret < 0)
0292             break;
0293     }
0294 
0295     mutex_unlock(&pnp_res_mutex);
0296     if (ret < 0) {
0297         pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
0298         pnp_clean_resource_table(dev);
0299     } else
0300         dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
0301     return ret;
0302 }
0303 
0304 /**
0305  * pnp_auto_config_dev - automatically assigns resources to a device
0306  * @dev: pointer to the desired device
0307  */
0308 int pnp_auto_config_dev(struct pnp_dev *dev)
0309 {
0310     int i, ret;
0311 
0312     if (!pnp_can_configure(dev)) {
0313         pnp_dbg(&dev->dev, "configuration not supported\n");
0314         return -ENODEV;
0315     }
0316 
0317     ret = pnp_assign_resources(dev, 0);
0318     if (ret == 0)
0319         return 0;
0320 
0321     for (i = 1; i < dev->num_dependent_sets; i++) {
0322         ret = pnp_assign_resources(dev, i);
0323         if (ret == 0)
0324             return 0;
0325     }
0326 
0327     dev_err(&dev->dev, "unable to assign resources\n");
0328     return ret;
0329 }
0330 
0331 /**
0332  * pnp_start_dev - low-level start of the PnP device
0333  * @dev: pointer to the desired device
0334  *
0335  * assumes that resources have already been allocated
0336  */
0337 int pnp_start_dev(struct pnp_dev *dev)
0338 {
0339     if (!pnp_can_write(dev)) {
0340         pnp_dbg(&dev->dev, "activation not supported\n");
0341         return -EINVAL;
0342     }
0343 
0344     dbg_pnp_show_resources(dev, "pnp_start_dev");
0345     if (dev->protocol->set(dev) < 0) {
0346         dev_err(&dev->dev, "activation failed\n");
0347         return -EIO;
0348     }
0349 
0350     dev_info(&dev->dev, "activated\n");
0351     return 0;
0352 }
0353 EXPORT_SYMBOL(pnp_start_dev);
0354 
0355 /**
0356  * pnp_stop_dev - low-level disable of the PnP device
0357  * @dev: pointer to the desired device
0358  *
0359  * does not free resources
0360  */
0361 int pnp_stop_dev(struct pnp_dev *dev)
0362 {
0363     if (!pnp_can_disable(dev)) {
0364         pnp_dbg(&dev->dev, "disabling not supported\n");
0365         return -EINVAL;
0366     }
0367     if (dev->protocol->disable(dev) < 0) {
0368         dev_err(&dev->dev, "disable failed\n");
0369         return -EIO;
0370     }
0371 
0372     dev_info(&dev->dev, "disabled\n");
0373     return 0;
0374 }
0375 EXPORT_SYMBOL(pnp_stop_dev);
0376 
0377 /**
0378  * pnp_activate_dev - activates a PnP device for use
0379  * @dev: pointer to the desired device
0380  *
0381  * does not validate or set resources so be careful.
0382  */
0383 int pnp_activate_dev(struct pnp_dev *dev)
0384 {
0385     int error;
0386 
0387     if (dev->active)
0388         return 0;
0389 
0390     /* ensure resources are allocated */
0391     if (pnp_auto_config_dev(dev))
0392         return -EBUSY;
0393 
0394     error = pnp_start_dev(dev);
0395     if (error)
0396         return error;
0397 
0398     dev->active = 1;
0399     return 0;
0400 }
0401 EXPORT_SYMBOL(pnp_activate_dev);
0402 
0403 /**
0404  * pnp_disable_dev - disables device
0405  * @dev: pointer to the desired device
0406  *
0407  * inform the correct pnp protocol so that resources can be used by other devices
0408  */
0409 int pnp_disable_dev(struct pnp_dev *dev)
0410 {
0411     int error;
0412 
0413     if (!dev->active)
0414         return 0;
0415 
0416     error = pnp_stop_dev(dev);
0417     if (error)
0418         return error;
0419 
0420     dev->active = 0;
0421 
0422     /* release the resources so that other devices can use them */
0423     mutex_lock(&pnp_res_mutex);
0424     pnp_clean_resource_table(dev);
0425     mutex_unlock(&pnp_res_mutex);
0426 
0427     return 0;
0428 }
0429 EXPORT_SYMBOL(pnp_disable_dev);