linux/drivers/pnp/resource.c
<<
>>
Prefs
   1/*
   2 * resource.c - Contains functions for registering and analyzing resource information
   3 *
   4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
   5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
   6 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
   7 *      Bjorn Helgaas <bjorn.helgaas@hp.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/errno.h>
  12#include <linux/interrupt.h>
  13#include <linux/kernel.h>
  14#include <asm/io.h>
  15#include <asm/dma.h>
  16#include <asm/irq.h>
  17#include <linux/pci.h>
  18#include <linux/ioport.h>
  19#include <linux/init.h>
  20
  21#include <linux/pnp.h>
  22#include "base.h"
  23
  24static int pnp_reserve_irq[16] = {[0 ... 15] = -1 };    /* reserve (don't use) some IRQ */
  25static int pnp_reserve_dma[8] = {[0 ... 7] = -1 };      /* reserve (don't use) some DMA */
  26static int pnp_reserve_io[16] = {[0 ... 15] = -1 };     /* reserve (don't use) some I/O region */
  27static int pnp_reserve_mem[16] = {[0 ... 15] = -1 };    /* reserve (don't use) some memory region */
  28
  29/*
  30 * option registration
  31 */
  32
  33struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type,
  34                                    unsigned int option_flags)
  35{
  36        struct pnp_option *option;
  37
  38        option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL);
  39        if (!option)
  40                return NULL;
  41
  42        option->flags = option_flags;
  43        option->type = type;
  44
  45        list_add_tail(&option->list, &dev->options);
  46        return option;
  47}
  48
  49int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
  50                              pnp_irq_mask_t *map, unsigned char flags)
  51{
  52        struct pnp_option *option;
  53        struct pnp_irq *irq;
  54
  55        option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags);
  56        if (!option)
  57                return -ENOMEM;
  58
  59        irq = &option->u.irq;
  60        irq->map = *map;
  61        irq->flags = flags;
  62
  63#ifdef CONFIG_PCI
  64        {
  65                int i;
  66
  67                for (i = 0; i < 16; i++)
  68                        if (test_bit(i, irq->map.bits))
  69                                pcibios_penalize_isa_irq(i, 0);
  70        }
  71#endif
  72
  73        dbg_pnp_show_option(dev, option);
  74        return 0;
  75}
  76
  77int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
  78                              unsigned char map, unsigned char flags)
  79{
  80        struct pnp_option *option;
  81        struct pnp_dma *dma;
  82
  83        option = pnp_build_option(dev, IORESOURCE_DMA, option_flags);
  84        if (!option)
  85                return -ENOMEM;
  86
  87        dma = &option->u.dma;
  88        dma->map = map;
  89        dma->flags = flags;
  90
  91        dbg_pnp_show_option(dev, option);
  92        return 0;
  93}
  94
  95int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
  96                               resource_size_t min, resource_size_t max,
  97                               resource_size_t align, resource_size_t size,
  98                               unsigned char flags)
  99{
 100        struct pnp_option *option;
 101        struct pnp_port *port;
 102
 103        option = pnp_build_option(dev, IORESOURCE_IO, option_flags);
 104        if (!option)
 105                return -ENOMEM;
 106
 107        port = &option->u.port;
 108        port->min = min;
 109        port->max = max;
 110        port->align = align;
 111        port->size = size;
 112        port->flags = flags;
 113
 114        dbg_pnp_show_option(dev, option);
 115        return 0;
 116}
 117
 118int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
 119                              resource_size_t min, resource_size_t max,
 120                              resource_size_t align, resource_size_t size,
 121                              unsigned char flags)
 122{
 123        struct pnp_option *option;
 124        struct pnp_mem *mem;
 125
 126        option = pnp_build_option(dev, IORESOURCE_MEM, option_flags);
 127        if (!option)
 128                return -ENOMEM;
 129
 130        mem = &option->u.mem;
 131        mem->min = min;
 132        mem->max = max;
 133        mem->align = align;
 134        mem->size = size;
 135        mem->flags = flags;
 136
 137        dbg_pnp_show_option(dev, option);
 138        return 0;
 139}
 140
 141void pnp_free_options(struct pnp_dev *dev)
 142{
 143        struct pnp_option *option, *tmp;
 144
 145        list_for_each_entry_safe(option, tmp, &dev->options, list) {
 146                list_del(&option->list);
 147                kfree(option);
 148        }
 149}
 150
 151/*
 152 * resource validity checking
 153 */
 154
 155#define length(start, end) (*(end) - *(start) + 1)
 156
 157/* Two ranges conflict if one doesn't end before the other starts */
 158#define ranged_conflict(starta, enda, startb, endb) \
 159        !((*(enda) < *(startb)) || (*(endb) < *(starta)))
 160
 161#define cannot_compare(flags) \
 162((flags) & IORESOURCE_DISABLED)
 163
 164int pnp_check_port(struct pnp_dev *dev, struct resource *res)
 165{
 166        int i;
 167        struct pnp_dev *tdev;
 168        struct resource *tres;
 169        resource_size_t *port, *end, *tport, *tend;
 170
 171        port = &res->start;
 172        end = &res->end;
 173
 174        /* if the resource doesn't exist, don't complain about it */
 175        if (cannot_compare(res->flags))
 176                return 1;
 177
 178        /* check if the resource is already in use, skip if the
 179         * device is active because it itself may be in use */
 180        if (!dev->active) {
 181                if (__check_region(&ioport_resource, *port, length(port, end)))
 182                        return 0;
 183        }
 184
 185        /* check if the resource is reserved */
 186        for (i = 0; i < 8; i++) {
 187                int rport = pnp_reserve_io[i << 1];
 188                int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1;
 189                if (ranged_conflict(port, end, &rport, &rend))
 190                        return 0;
 191        }
 192
 193        /* check for internal conflicts */
 194        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
 195                if (tres != res && tres->flags & IORESOURCE_IO) {
 196                        tport = &tres->start;
 197                        tend = &tres->end;
 198                        if (ranged_conflict(port, end, tport, tend))
 199                                return 0;
 200                }
 201        }
 202
 203        /* check for conflicts with other pnp devices */
 204        pnp_for_each_dev(tdev) {
 205                if (tdev == dev)
 206                        continue;
 207                for (i = 0;
 208                     (tres = pnp_get_resource(tdev, IORESOURCE_IO, i));
 209                     i++) {
 210                        if (tres->flags & IORESOURCE_IO) {
 211                                if (cannot_compare(tres->flags))
 212                                        continue;
 213                                tport = &tres->start;
 214                                tend = &tres->end;
 215                                if (ranged_conflict(port, end, tport, tend))
 216                                        return 0;
 217                        }
 218                }
 219        }
 220
 221        return 1;
 222}
 223
 224int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
 225{
 226        int i;
 227        struct pnp_dev *tdev;
 228        struct resource *tres;
 229        resource_size_t *addr, *end, *taddr, *tend;
 230
 231        addr = &res->start;
 232        end = &res->end;
 233
 234        /* if the resource doesn't exist, don't complain about it */
 235        if (cannot_compare(res->flags))
 236                return 1;
 237
 238        /* check if the resource is already in use, skip if the
 239         * device is active because it itself may be in use */
 240        if (!dev->active) {
 241                if (check_mem_region(*addr, length(addr, end)))
 242                        return 0;
 243        }
 244
 245        /* check if the resource is reserved */
 246        for (i = 0; i < 8; i++) {
 247                int raddr = pnp_reserve_mem[i << 1];
 248                int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1;
 249                if (ranged_conflict(addr, end, &raddr, &rend))
 250                        return 0;
 251        }
 252
 253        /* check for internal conflicts */
 254        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
 255                if (tres != res && tres->flags & IORESOURCE_MEM) {
 256                        taddr = &tres->start;
 257                        tend = &tres->end;
 258                        if (ranged_conflict(addr, end, taddr, tend))
 259                                return 0;
 260                }
 261        }
 262
 263        /* check for conflicts with other pnp devices */
 264        pnp_for_each_dev(tdev) {
 265                if (tdev == dev)
 266                        continue;
 267                for (i = 0;
 268                     (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i));
 269                     i++) {
 270                        if (tres->flags & IORESOURCE_MEM) {
 271                                if (cannot_compare(tres->flags))
 272                                        continue;
 273                                taddr = &tres->start;
 274                                tend = &tres->end;
 275                                if (ranged_conflict(addr, end, taddr, tend))
 276                                        return 0;
 277                        }
 278                }
 279        }
 280
 281        return 1;
 282}
 283
 284static irqreturn_t pnp_test_handler(int irq, void *dev_id)
 285{
 286        return IRQ_HANDLED;
 287}
 288
 289#ifdef CONFIG_PCI
 290static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
 291                            unsigned int irq)
 292{
 293        u32 class;
 294        u8 progif;
 295
 296        if (pci->irq == irq) {
 297                pnp_dbg(&pnp->dev, "  device %s using irq %d\n",
 298                        pci_name(pci), irq);
 299                return 1;
 300        }
 301
 302        /*
 303         * See pci_setup_device() and ata_pci_sff_activate_host() for
 304         * similar IDE legacy detection.
 305         */
 306        pci_read_config_dword(pci, PCI_CLASS_REVISION, &class);
 307        class >>= 8;            /* discard revision ID */
 308        progif = class & 0xff;
 309        class >>= 8;
 310
 311        if (class == PCI_CLASS_STORAGE_IDE) {
 312                /*
 313                 * Unless both channels are native-PCI mode only,
 314                 * treat the compatibility IRQs as busy.
 315                 */
 316                if ((progif & 0x5) != 0x5)
 317                        if (pci_get_legacy_ide_irq(pci, 0) == irq ||
 318                            pci_get_legacy_ide_irq(pci, 1) == irq) {
 319                                pnp_dbg(&pnp->dev, "  legacy IDE device %s "
 320                                        "using irq %d\n", pci_name(pci), irq);
 321                                return 1;
 322                        }
 323        }
 324
 325        return 0;
 326}
 327#endif
 328
 329static int pci_uses_irq(struct pnp_dev *pnp, unsigned int irq)
 330{
 331#ifdef CONFIG_PCI
 332        struct pci_dev *pci = NULL;
 333
 334        for_each_pci_dev(pci) {
 335                if (pci_dev_uses_irq(pnp, pci, irq)) {
 336                        pci_dev_put(pci);
 337                        return 1;
 338                }
 339        }
 340#endif
 341        return 0;
 342}
 343
 344int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
 345{
 346        int i;
 347        struct pnp_dev *tdev;
 348        struct resource *tres;
 349        resource_size_t *irq;
 350
 351        irq = &res->start;
 352
 353        /* if the resource doesn't exist, don't complain about it */
 354        if (cannot_compare(res->flags))
 355                return 1;
 356
 357        /* check if the resource is valid */
 358        if (*irq < 0 || *irq > 15)
 359                return 0;
 360
 361        /* check if the resource is reserved */
 362        for (i = 0; i < 16; i++) {
 363                if (pnp_reserve_irq[i] == *irq)
 364                        return 0;
 365        }
 366
 367        /* check for internal conflicts */
 368        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
 369                if (tres != res && tres->flags & IORESOURCE_IRQ) {
 370                        if (tres->start == *irq)
 371                                return 0;
 372                }
 373        }
 374
 375        /* check if the resource is being used by a pci device */
 376        if (pci_uses_irq(dev, *irq))
 377                return 0;
 378
 379        /* check if the resource is already in use, skip if the
 380         * device is active because it itself may be in use */
 381        if (!dev->active) {
 382                if (request_irq(*irq, pnp_test_handler,
 383                                IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
 384                        return 0;
 385                free_irq(*irq, NULL);
 386        }
 387
 388        /* check for conflicts with other pnp devices */
 389        pnp_for_each_dev(tdev) {
 390                if (tdev == dev)
 391                        continue;
 392                for (i = 0;
 393                     (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i));
 394                     i++) {
 395                        if (tres->flags & IORESOURCE_IRQ) {
 396                                if (cannot_compare(tres->flags))
 397                                        continue;
 398                                if (tres->start == *irq)
 399                                        return 0;
 400                        }
 401                }
 402        }
 403
 404        return 1;
 405}
 406
 407int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
 408{
 409#ifndef CONFIG_IA64
 410        int i;
 411        struct pnp_dev *tdev;
 412        struct resource *tres;
 413        resource_size_t *dma;
 414
 415        dma = &res->start;
 416
 417        /* if the resource doesn't exist, don't complain about it */
 418        if (cannot_compare(res->flags))
 419                return 1;
 420
 421        /* check if the resource is valid */
 422        if (*dma < 0 || *dma == 4 || *dma > 7)
 423                return 0;
 424
 425        /* check if the resource is reserved */
 426        for (i = 0; i < 8; i++) {
 427                if (pnp_reserve_dma[i] == *dma)
 428                        return 0;
 429        }
 430
 431        /* check for internal conflicts */
 432        for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
 433                if (tres != res && tres->flags & IORESOURCE_DMA) {
 434                        if (tres->start == *dma)
 435                                return 0;
 436                }
 437        }
 438
 439        /* check if the resource is already in use, skip if the
 440         * device is active because it itself may be in use */
 441        if (!dev->active) {
 442                if (request_dma(*dma, "pnp"))
 443                        return 0;
 444                free_dma(*dma);
 445        }
 446
 447        /* check for conflicts with other pnp devices */
 448        pnp_for_each_dev(tdev) {
 449                if (tdev == dev)
 450                        continue;
 451                for (i = 0;
 452                     (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i));
 453                     i++) {
 454                        if (tres->flags & IORESOURCE_DMA) {
 455                                if (cannot_compare(tres->flags))
 456                                        continue;
 457                                if (tres->start == *dma)
 458                                        return 0;
 459                        }
 460                }
 461        }
 462
 463        return 1;
 464#else
 465        /* IA64 does not have legacy DMA */
 466        return 0;
 467#endif
 468}
 469
 470unsigned long pnp_resource_type(struct resource *res)
 471{
 472        return res->flags & (IORESOURCE_IO  | IORESOURCE_MEM |
 473                             IORESOURCE_IRQ | IORESOURCE_DMA);
 474}
 475
 476struct resource *pnp_get_resource(struct pnp_dev *dev,
 477                                  unsigned long type, unsigned int num)
 478{
 479        struct pnp_resource *pnp_res;
 480        struct resource *res;
 481
 482        list_for_each_entry(pnp_res, &dev->resources, list) {
 483                res = &pnp_res->res;
 484                if (pnp_resource_type(res) == type && num-- == 0)
 485                        return res;
 486        }
 487        return NULL;
 488}
 489EXPORT_SYMBOL(pnp_get_resource);
 490
 491static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
 492{
 493        struct pnp_resource *pnp_res;
 494
 495        pnp_res = kzalloc(sizeof(struct pnp_resource), GFP_KERNEL);
 496        if (!pnp_res)
 497                return NULL;
 498
 499        list_add_tail(&pnp_res->list, &dev->resources);
 500        return pnp_res;
 501}
 502
 503struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
 504                                          int flags)
 505{
 506        struct pnp_resource *pnp_res;
 507        struct resource *res;
 508
 509        pnp_res = pnp_new_resource(dev);
 510        if (!pnp_res) {
 511                dev_err(&dev->dev, "can't add resource for IRQ %d\n", irq);
 512                return NULL;
 513        }
 514
 515        res = &pnp_res->res;
 516        res->flags = IORESOURCE_IRQ | flags;
 517        res->start = irq;
 518        res->end = irq;
 519
 520        pnp_dbg(&dev->dev, "  add irq %d flags %#x\n", irq, flags);
 521        return pnp_res;
 522}
 523
 524struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
 525                                          int flags)
 526{
 527        struct pnp_resource *pnp_res;
 528        struct resource *res;
 529
 530        pnp_res = pnp_new_resource(dev);
 531        if (!pnp_res) {
 532                dev_err(&dev->dev, "can't add resource for DMA %d\n", dma);
 533                return NULL;
 534        }
 535
 536        res = &pnp_res->res;
 537        res->flags = IORESOURCE_DMA | flags;
 538        res->start = dma;
 539        res->end = dma;
 540
 541        pnp_dbg(&dev->dev, "  add dma %d flags %#x\n", dma, flags);
 542        return pnp_res;
 543}
 544
 545struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
 546                                         resource_size_t start,
 547                                         resource_size_t end, int flags)
 548{
 549        struct pnp_resource *pnp_res;
 550        struct resource *res;
 551
 552        pnp_res = pnp_new_resource(dev);
 553        if (!pnp_res) {
 554                dev_err(&dev->dev, "can't add resource for IO %#llx-%#llx\n",
 555                        (unsigned long long) start,
 556                        (unsigned long long) end);
 557                return NULL;
 558        }
 559
 560        res = &pnp_res->res;
 561        res->flags = IORESOURCE_IO | flags;
 562        res->start = start;
 563        res->end = end;
 564
 565        pnp_dbg(&dev->dev, "  add io  %#llx-%#llx flags %#x\n",
 566                (unsigned long long) start, (unsigned long long) end, flags);
 567        return pnp_res;
 568}
 569
 570struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
 571                                          resource_size_t start,
 572                                          resource_size_t end, int flags)
 573{
 574        struct pnp_resource *pnp_res;
 575        struct resource *res;
 576
 577        pnp_res = pnp_new_resource(dev);
 578        if (!pnp_res) {
 579                dev_err(&dev->dev, "can't add resource for MEM %#llx-%#llx\n",
 580                        (unsigned long long) start,
 581                        (unsigned long long) end);
 582                return NULL;
 583        }
 584
 585        res = &pnp_res->res;
 586        res->flags = IORESOURCE_MEM | flags;
 587        res->start = start;
 588        res->end = end;
 589
 590        pnp_dbg(&dev->dev, "  add mem %#llx-%#llx flags %#x\n",
 591                (unsigned long long) start, (unsigned long long) end, flags);
 592        return pnp_res;
 593}
 594
 595/*
 596 * Determine whether the specified resource is a possible configuration
 597 * for this device.
 598 */
 599int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
 600                        resource_size_t size)
 601{
 602        struct pnp_option *option;
 603        struct pnp_port *port;
 604        struct pnp_mem *mem;
 605        struct pnp_irq *irq;
 606        struct pnp_dma *dma;
 607
 608        list_for_each_entry(option, &dev->options, list) {
 609                if (option->type != type)
 610                        continue;
 611
 612                switch (option->type) {
 613                case IORESOURCE_IO:
 614                        port = &option->u.port;
 615                        if (port->min == start && port->size == size)
 616                                return 1;
 617                        break;
 618                case IORESOURCE_MEM:
 619                        mem = &option->u.mem;
 620                        if (mem->min == start && mem->size == size)
 621                                return 1;
 622                        break;
 623                case IORESOURCE_IRQ:
 624                        irq = &option->u.irq;
 625                        if (start < PNP_IRQ_NR &&
 626                            test_bit(start, irq->map.bits))
 627                                return 1;
 628                        break;
 629                case IORESOURCE_DMA:
 630                        dma = &option->u.dma;
 631                        if (dma->map & (1 << start))
 632                                return 1;
 633                        break;
 634                }
 635        }
 636
 637        return 0;
 638}
 639EXPORT_SYMBOL(pnp_possible_config);
 640
 641int pnp_range_reserved(resource_size_t start, resource_size_t end)
 642{
 643        struct pnp_dev *dev;
 644        struct pnp_resource *pnp_res;
 645        resource_size_t *dev_start, *dev_end;
 646
 647        pnp_for_each_dev(dev) {
 648                list_for_each_entry(pnp_res, &dev->resources, list) {
 649                        dev_start = &pnp_res->res.start;
 650                        dev_end   = &pnp_res->res.end;
 651                        if (ranged_conflict(&start, &end, dev_start, dev_end))
 652                                return 1;
 653                }
 654        }
 655        return 0;
 656}
 657EXPORT_SYMBOL(pnp_range_reserved);
 658
 659/* format is: pnp_reserve_irq=irq1[,irq2] .... */
 660static int __init pnp_setup_reserve_irq(char *str)
 661{
 662        int i;
 663
 664        for (i = 0; i < 16; i++)
 665                if (get_option(&str, &pnp_reserve_irq[i]) != 2)
 666                        break;
 667        return 1;
 668}
 669
 670__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
 671
 672/* format is: pnp_reserve_dma=dma1[,dma2] .... */
 673static int __init pnp_setup_reserve_dma(char *str)
 674{
 675        int i;
 676
 677        for (i = 0; i < 8; i++)
 678                if (get_option(&str, &pnp_reserve_dma[i]) != 2)
 679                        break;
 680        return 1;
 681}
 682
 683__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
 684
 685/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
 686static int __init pnp_setup_reserve_io(char *str)
 687{
 688        int i;
 689
 690        for (i = 0; i < 16; i++)
 691                if (get_option(&str, &pnp_reserve_io[i]) != 2)
 692                        break;
 693        return 1;
 694}
 695
 696__setup("pnp_reserve_io=", pnp_setup_reserve_io);
 697
 698/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
 699static int __init pnp_setup_reserve_mem(char *str)
 700{
 701        int i;
 702
 703        for (i = 0; i < 16; i++)
 704                if (get_option(&str, &pnp_reserve_mem[i]) != 2)
 705                        break;
 706        return 1;
 707}
 708
 709__setup("pnp_reserve_mem=", pnp_setup_reserve_mem);
 710