~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to arch/powerpc/platforms/pseries/msi.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

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