Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
powerpc
platforms
wsp
msi.c
Go to the documentation of this file.
1
/*
2
* Copyright 2011 Michael Ellerman, IBM Corp.
3
*
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version
7
* 2 of the License, or (at your option) any later version.
8
*/
9
10
#include <linux/kernel.h>
11
#include <linux/pci.h>
12
#include <
linux/msi.h
>
13
#include <
linux/irq.h
>
14
#include <
linux/interrupt.h
>
15
16
#include "
msi.h
"
17
#include "
ics.h
"
18
#include "
wsp_pci.h
"
19
20
/* Magic addresses for 32 & 64-bit MSIs with hardcoded MVE 0 */
21
#define MSI_ADDR_32 0xFFFF0000ul
22
#define MSI_ADDR_64 0x1000000000000000ul
23
24
int
wsp_setup_msi_irqs
(
struct
pci_dev
*
dev
,
int
nvec,
int
type
)
25
{
26
struct
pci_controller
*phb;
27
struct
msi_desc
*
entry
;
28
struct
msi_msg
msg;
29
unsigned
int
virq;
30
int
hwirq;
31
32
phb = pci_bus_to_host(dev->
bus
);
33
if
(!phb)
34
return
-
ENOENT
;
35
36
entry =
list_first_entry
(&dev->msi_list,
struct
msi_desc
,
list
);
37
if
(entry->
msi_attrib
.is_64) {
38
msg.
address_lo
= 0;
39
msg.
address_hi
=
MSI_ADDR_64
>> 32;
40
}
else
{
41
msg.
address_lo
=
MSI_ADDR_32
;
42
msg.
address_hi
= 0;
43
}
44
45
list_for_each_entry
(entry, &dev->msi_list,
list
) {
46
hwirq =
wsp_ics_alloc_irq
(phb->dn, 1);
47
if
(hwirq < 0) {
48
dev_warn
(&dev->
dev
,
"wsp_msi: hwirq alloc failed!\n"
);
49
return
hwirq;
50
}
51
52
virq =
irq_create_mapping
(
NULL
, hwirq);
53
if
(virq ==
NO_IRQ
) {
54
dev_warn
(&dev->
dev
,
"wsp_msi: virq alloc failed!\n"
);
55
return
-1;
56
}
57
58
dev_dbg
(&dev->
dev
,
"wsp_msi: allocated irq %#x/%#x\n"
,
59
hwirq, virq);
60
61
wsp_ics_set_msi_chip(virq);
62
irq_set_msi_desc
(virq, entry);
63
msg.
data
= hwirq &
XIVE_ADDR_MASK
;
64
write_msi_msg
(virq, &msg);
65
}
66
67
return
0;
68
}
69
70
void
wsp_teardown_msi_irqs
(
struct
pci_dev
*
dev
)
71
{
72
struct
pci_controller
*phb;
73
struct
msi_desc
*
entry
;
74
int
hwirq;
75
76
phb = pci_bus_to_host(dev->
bus
);
77
78
dev_dbg
(&dev->
dev
,
"wsp_msi: tearing down msi irqs\n"
);
79
80
list_for_each_entry
(entry, &dev->msi_list,
list
) {
81
if
(entry->
irq
==
NO_IRQ
)
82
continue
;
83
84
irq_set_msi_desc
(entry->
irq
,
NULL
);
85
wsp_ics_set_std_chip(entry->
irq
);
86
87
hwirq =
virq_to_hw
(entry->
irq
);
88
/* In this order to avoid racing with irq_create_mapping() */
89
irq_dispose_mapping
(entry->
irq
);
90
wsp_ics_free_irq
(phb->dn, hwirq);
91
}
92
}
93
94
void
wsp_setup_phb_msi
(
struct
pci_controller
*phb)
95
{
96
/* Create a single MVE at offset 0 that matches everything */
97
out_be64(phb->cfg_data +
PCIE_REG_IODA_ADDR
,
PCIE_REG_IODA_AD_TBL_MVT
);
98
out_be64(phb->cfg_data +
PCIE_REG_IODA_DATA0
, 1ull << 63);
99
100
ppc_md
.setup_msi_irqs =
wsp_setup_msi_irqs
;
101
ppc_md
.teardown_msi_irqs =
wsp_teardown_msi_irqs
;
102
}
Generated on Thu Jan 10 2013 12:59:29 for Linux Kernel by
1.8.2