linux/arch/powerpc/platforms/pseries/msi.c
<<
>>
Prefs
   1/*
   2 * Copyright 2006 Jake Moilanen <moilanen@austin.ibm.com>, IBM Corp.
   3 * Copyright 2006-2007 Michael Ellerman, IBM Corp.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License
   7 * as published by the Free Software Foundation; version 2 of the
   8 * License.
   9 *
  10 */
  11
  12#include <linux/device.h>
  13#include <linux/irq.h>
  14#include <linux/msi.h>
  15
  16#include <asm/rtas.h>
  17#include <asm/hw_irq.h>
  18#include <asm/ppc-pci.h>
  19
  20static int query_token, change_token;
  21
  22#define RTAS_QUERY_FN           0
  23#define RTAS_CHANGE_FN          1
  24#define RTAS_RESET_FN           2
  25#define RTAS_CHANGE_MSI_FN      3
  26#define RTAS_CHANGE_MSIX_FN     4
  27
  28static struct pci_dn *get_pdn(struct pci_dev *pdev)
  29{
  30        struct device_node *dn;
  31        struct pci_dn *pdn;
  32
  33        dn = pci_device_to_OF_node(pdev);
  34        if (!dn) {
  35                dev_dbg(&pdev->dev, "rtas_msi: No OF device node\n");
  36                return NULL;
  37        }
  38
  39        pdn = PCI_DN(dn);
  40        if (!pdn) {
  41                dev_dbg(&pdev->dev, "rtas_msi: No PCI DN\n");
  42                return NULL;
  43        }
  44
  45        return pdn;
  46}
  47
  48/* RTAS Helpers */
  49
  50static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs)
  51{
  52        u32 addr, seq_num, rtas_ret[3];
  53        unsigned long buid;
  54        int rc;
  55
  56        addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
  57        buid = pdn->phb->buid;
  58
  59        seq_num = 1;
  60        do {
  61                if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN)
  62                        rc = rtas_call(change_token, 6, 4, rtas_ret, addr,
  63                                        BUID_HI(buid), BUID_LO(buid),
  64                                        func, num_irqs, seq_num);
  65                else
  66                        rc = rtas_call(change_token, 6, 3, rtas_ret, addr,
  67                                        BUID_HI(buid), BUID_LO(buid),
  68                                        func, num_irqs, seq_num);
  69
  70                seq_num = rtas_ret[1];
  71        } while (rtas_busy_delay(rc));
  72
  73        /*
  74         * If the RTAS call succeeded, return the number of irqs allocated.
  75         * If not, make sure we return a negative error code.
  76         */
  77        if (rc == 0)
  78                rc = rtas_ret[0];
  79        else if (rc > 0)
  80                rc = -rc;
  81
  82        pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d), got %d rc = %d\n",
  83                 func, num_irqs, rtas_ret[0], rc);
  84
  85        return rc;
  86}
  87
  88static void rtas_disable_msi(struct pci_dev *pdev)
  89{
  90        struct pci_dn *pdn;
  91
  92        pdn = get_pdn(pdev);
  93        if (!pdn)
  94                return;
  95
  96        /*
  97         * disabling MSI with the explicit interface also disables MSI-X
  98         */
  99        if (rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, 0) != 0) {
 100                /* 
 101                 * may have failed because explicit interface is not
 102                 * present
 103                 */
 104                if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0) {
 105                        pr_debug("rtas_msi: Setting MSIs to 0 failed!\n");
 106                }
 107        }
 108}
 109
 110static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
 111{
 112        u32 addr, rtas_ret[2];
 113        unsigned long buid;
 114        int rc;
 115
 116        addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
 117        buid = pdn->phb->buid;
 118
 119        do {
 120                rc = rtas_call(query_token, 4, 3, rtas_ret, addr,
 121                               BUID_HI(buid), BUID_LO(buid), offset);
 122        } while (rtas_busy_delay(rc));
 123
 124        if (rc) {
 125                pr_debug("rtas_msi: error (%d) querying source number\n", rc);
 126                return rc;
 127        }
 128
 129        return rtas_ret[0];
 130}
 131
 132static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
 133{
 134        struct msi_desc *entry;
 135
 136        list_for_each_entry(entry, &pdev->msi_list, list) {
 137                if (entry->irq == NO_IRQ)
 138                        continue;
 139
 140                irq_set_msi_desc(entry->irq, NULL);
 141                irq_dispose_mapping(entry->irq);
 142        }
 143
 144        rtas_disable_msi(pdev);
 145}
 146
 147static int check_req(struct pci_dev *pdev, int nvec, char *prop_name)
 148{
 149        struct device_node *dn;
 150        struct pci_dn *pdn;
 151        const u32 *req_msi;
 152
 153        pdn = get_pdn(pdev);
 154        if (!pdn)
 155                return -ENODEV;
 156
 157        dn = pdn->node;
 158
 159        req_msi = of_get_property(dn, prop_name, NULL);
 160        if (!req_msi) {
 161                pr_debug("rtas_msi: No %s on %s\n", prop_name, dn->full_name);
 162                return -ENOENT;
 163        }
 164
 165        if (*req_msi < nvec) {
 166                pr_debug("rtas_msi: %s requests < %d MSIs\n", prop_name, nvec);
 167
 168                if (*req_msi == 0) /* Be paranoid */
 169                        return -ENOSPC;
 170
 171                return *req_msi;
 172        }
 173
 174        return 0;
 175}
 176
 177static int check_req_msi(struct pci_dev *pdev, int nvec)
 178{
 179        return check_req(pdev, nvec, "ibm,req#msi");
 180}
 181
 182static int check_req_msix(struct pci_dev *pdev, int nvec)
 183{
 184        return check_req(pdev, nvec, "ibm,req#msi-x");
 185}
 186
 187/* Quota calculation */
 188
 189static struct device_node *find_pe_total_msi(struct pci_dev *dev, int *total)
 190{
 191        struct device_node *dn;
 192        const u32 *p;
 193
 194        dn = of_node_get(pci_device_to_OF_node(dev));
 195        while (dn) {
 196                p = of_get_property(dn, "ibm,pe-total-#msi", NULL);
 197                if (p) {
 198                        pr_debug("rtas_msi: found prop on dn %s\n",
 199                                dn->full_name);
 200                        *total = *p;
 201                        return dn;
 202                }
 203
 204                dn = of_get_next_parent(dn);
 205        }
 206
 207        return NULL;
 208}
 209
 210static struct device_node *find_pe_dn(struct pci_dev *dev, int *total)
 211{
 212        struct device_node *dn;
 213
 214        /* Found our PE and assume 8 at that point. */
 215
 216        dn = pci_device_to_OF_node(dev);
 217        if (!dn)
 218                return NULL;
 219
 220        dn = find_device_pe(dn);
 221        if (!dn)
 222                return NULL;
 223
 224        /* We actually want the parent */
 225        dn = of_get_parent(dn);
 226        if (!dn)
 227                return NULL;
 228
 229        /* Hardcode of 8 for old firmwares */
 230        *total = 8;
 231        pr_debug("rtas_msi: using PE dn %s\n", dn->full_name);
 232
 233        return dn;
 234}
 235
 236struct msi_counts {
 237        struct device_node *requestor;
 238        int num_devices;
 239        int request;
 240        int quota;
 241        int spare;
 242        int over_quota;
 243};
 244
 245static void *count_non_bridge_devices(struct device_node *dn, void *data)
 246{
 247        struct msi_counts *counts = data;
 248        const u32 *p;
 249        u32 class;
 250
 251        pr_debug("rtas_msi: counting %s\n", dn->full_name);
 252
 253        p = of_get_property(dn, "class-code", NULL);
 254        class = p ? *p : 0;
 255
 256        if ((class >> 8) != PCI_CLASS_BRIDGE_PCI)
 257                counts->num_devices++;
 258
 259        return NULL;
 260}
 261
 262static void *count_spare_msis(struct device_node *dn, void *data)
 263{
 264        struct msi_counts *counts = data;
 265        const u32 *p;
 266        int req;
 267
 268        if (dn == counts->requestor)
 269                req = counts->request;
 270        else {
 271                /* We don't know if a driver will try to use MSI or MSI-X,
 272                 * so we just have to punt and use the larger of the two. */
 273                req = 0;
 274                p = of_get_property(dn, "ibm,req#msi", NULL);
 275                if (p)
 276                        req = *p;
 277
 278                p = of_get_property(dn, "ibm,req#msi-x", NULL);
 279                if (p)
 280                        req = max(req, (int)*p);
 281        }
 282
 283        if (req < counts->quota)
 284                counts->spare += counts->quota - req;
 285        else if (req > counts->quota)
 286                counts->over_quota++;
 287
 288        return NULL;
 289}
 290
 291static int msi_quota_for_device(struct pci_dev *dev, int request)
 292{
 293        struct device_node *pe_dn;
 294        struct msi_counts counts;
 295        int total;
 296
 297        pr_debug("rtas_msi: calc quota for %s, request %d\n", pci_name(dev),
 298                  request);
 299
 300        pe_dn = find_pe_total_msi(dev, &total);
 301        if (!pe_dn)
 302                pe_dn = find_pe_dn(dev, &total);
 303
 304        if (!pe_dn) {
 305                pr_err("rtas_msi: couldn't find PE for %s\n", pci_name(dev));
 306                goto out;
 307        }
 308
 309        pr_debug("rtas_msi: found PE %s\n", pe_dn->full_name);
 310
 311        memset(&counts, 0, sizeof(struct msi_counts));
 312
 313        /* Work out how many devices we have below this PE */
 314        traverse_pci_devices(pe_dn, count_non_bridge_devices, &counts);
 315
 316        if (counts.num_devices == 0) {
 317                pr_err("rtas_msi: found 0 devices under PE for %s\n",
 318                        pci_name(dev));
 319                goto out;
 320        }
 321
 322        counts.quota = total / counts.num_devices;
 323        if (request <= counts.quota)
 324                goto out;
 325
 326        /* else, we have some more calculating to do */
 327        counts.requestor = pci_device_to_OF_node(dev);
 328        counts.request = request;
 329        traverse_pci_devices(pe_dn, count_spare_msis, &counts);
 330
 331        /* If the quota isn't an integer multiple of the total, we can
 332         * use the remainder as spare MSIs for anyone that wants them. */
 333        counts.spare += total % counts.num_devices;
 334
 335        /* Divide any spare by the number of over-quota requestors */
 336        if (counts.over_quota)
 337                counts.quota += counts.spare / counts.over_quota;
 338
 339        /* And finally clamp the request to the possibly adjusted quota */
 340        request = min(counts.quota, request);
 341
 342        pr_debug("rtas_msi: request clamped to quota %d\n", request);
 343out:
 344        of_node_put(pe_dn);
 345
 346        return request;
 347}
 348
 349static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
 350{
 351        int quota, rc;
 352
 353        if (type == PCI_CAP_ID_MSIX)
 354                rc = check_req_msix(pdev, nvec);
 355        else
 356                rc = check_req_msi(pdev, nvec);
 357
 358        if (rc)
 359                return rc;
 360
 361        quota = msi_quota_for_device(pdev, nvec);
 362
 363        if (quota && quota < nvec)
 364                return quota;
 365
 366        return 0;
 367}
 368
 369static int check_msix_entries(struct pci_dev *pdev)
 370{
 371        struct msi_desc *entry;
 372        int expected;
 373
 374        /* There's no way for us to express to firmware that we want
 375         * a discontiguous, or non-zero based, range of MSI-X entries.
 376         * So we must reject such requests. */
 377
 378        expected = 0;
 379        list_for_each_entry(entry, &pdev->msi_list, list) {
 380                if (entry->msi_attrib.entry_nr != expected) {
 381                        pr_debug("rtas_msi: bad MSI-X entries.\n");
 382                        return -EINVAL;
 383                }
 384                expected++;
 385        }
 386
 387        return 0;
 388}
 389
 390static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 391{
 392        struct pci_dn *pdn;
 393        int hwirq, virq, i, rc;
 394        struct msi_desc *entry;
 395        struct msi_msg msg;
 396
 397        pdn = get_pdn(pdev);
 398        if (!pdn)
 399                return -ENODEV;
 400
 401        if (type == PCI_CAP_ID_MSIX && check_msix_entries(pdev))
 402                return -EINVAL;
 403
 404        /*
 405         * Try the new more explicit firmware interface, if that fails fall
 406         * back to the old interface. The old interface is known to never
 407         * return MSI-Xs.
 408         */
 409        if (type == PCI_CAP_ID_MSI) {
 410                rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
 411
 412                if (rc < 0) {
 413                        pr_debug("rtas_msi: trying the old firmware call.\n");
 414                        rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec);
 415                }
 416        } else
 417                rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec);
 418
 419        if (rc != nvec) {
 420                pr_debug("rtas_msi: rtas_change_msi() failed\n");
 421                return rc;
 422        }
 423
 424        i = 0;
 425        list_for_each_entry(entry, &pdev->msi_list, list) {
 426                hwirq = rtas_query_irq_number(pdn, i++);
 427                if (hwirq < 0) {
 428                        pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);
 429                        return hwirq;
 430                }
 431
 432                virq = irq_create_mapping(NULL, hwirq);
 433
 434                if (virq == NO_IRQ) {
 435                        pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
 436                        return -ENOSPC;
 437                }
 438
 439                dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq);
 440                irq_set_msi_desc(virq, entry);
 441
 442                /* Read config space back so we can restore after reset */
 443                read_msi_msg(virq, &msg);
 444                entry->msg = msg;
 445        }
 446
 447        return 0;
 448}
 449
 450static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
 451{
 452        /* No LSI -> leave MSIs (if any) configured */
 453        if (pdev->irq == NO_IRQ) {
 454                dev_dbg(&pdev->dev, "rtas_msi: no LSI, nothing to do.\n");
 455                return;
 456        }
 457
 458        /* No MSI -> MSIs can't have been assigned by fw, leave LSI */
 459        if (check_req_msi(pdev, 1) && check_req_msix(pdev, 1)) {
 460                dev_dbg(&pdev->dev, "rtas_msi: no req#msi/x, nothing to do.\n");
 461                return;
 462        }
 463
 464        dev_dbg(&pdev->dev, "rtas_msi: disabling existing MSI.\n");
 465        rtas_disable_msi(pdev);
 466}
 467
 468static int rtas_msi_init(void)
 469{
 470        query_token  = rtas_token("ibm,query-interrupt-source-number");
 471        change_token = rtas_token("ibm,change-msi");
 472
 473        if ((query_token == RTAS_UNKNOWN_SERVICE) ||
 474                        (change_token == RTAS_UNKNOWN_SERVICE)) {
 475                pr_debug("rtas_msi: no RTAS tokens, no MSI support.\n");
 476                return -1;
 477        }
 478
 479        pr_debug("rtas_msi: Registering RTAS MSI callbacks.\n");
 480
 481        WARN_ON(ppc_md.setup_msi_irqs);
 482        ppc_md.setup_msi_irqs = rtas_setup_msi_irqs;
 483        ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs;
 484        ppc_md.msi_check_device = rtas_msi_check_device;
 485
 486        WARN_ON(ppc_md.pci_irq_fixup);
 487        ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup;
 488
 489        return 0;
 490}
 491arch_initcall(rtas_msi_init);
 492