]>
Commit | Line | Data |
---|---|---|
0a34fb31 BS |
1 | /* |
2 | * Copyright 2015 Red Hat Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | * Authors: Ben Skeggs <bskeggs@redhat.com> | |
23 | */ | |
24 | #include "priv.h" | |
340b0e7c | 25 | #include "agp.h" |
0a34fb31 | 26 | |
2b700825 BS |
27 | #include <core/option.h> |
28 | #include <core/pci.h> | |
29 | #include <subdev/mc.h> | |
30 | ||
0a34fb31 BS |
31 | u32 |
32 | nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr) | |
33 | { | |
34 | return pci->func->rd32(pci, addr); | |
35 | } | |
36 | ||
37 | void | |
38 | nvkm_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data) | |
39 | { | |
40 | pci->func->wr08(pci, addr, data); | |
41 | } | |
42 | ||
43 | void | |
44 | nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) | |
45 | { | |
46 | pci->func->wr32(pci, addr, data); | |
47 | } | |
48 | ||
5d5b43f5 PM |
49 | u32 |
50 | nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 value) | |
51 | { | |
52 | u32 data = pci->func->rd32(pci, addr); | |
53 | pci->func->wr32(pci, addr, (data & ~mask) | value); | |
54 | return data; | |
55 | } | |
56 | ||
0a34fb31 BS |
57 | void |
58 | nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) | |
59 | { | |
60 | u32 data = nvkm_pci_rd32(pci, 0x0050); | |
61 | if (shadow) | |
62 | data |= 0x00000001; | |
63 | else | |
64 | data &= ~0x00000001; | |
65 | nvkm_pci_wr32(pci, 0x0050, data); | |
66 | } | |
67 | ||
2b700825 BS |
68 | static irqreturn_t |
69 | nvkm_pci_intr(int irq, void *arg) | |
70 | { | |
71 | struct nvkm_pci *pci = arg; | |
d3981190 | 72 | struct nvkm_device *device = pci->subdev.device; |
2b700825 | 73 | bool handled = false; |
d3981190 BS |
74 | nvkm_mc_intr_unarm(device); |
75 | if (pci->msi) | |
76 | pci->func->msi_rearm(pci); | |
77 | nvkm_mc_intr(device, &handled); | |
78 | nvkm_mc_intr_rearm(device); | |
2b700825 BS |
79 | return handled ? IRQ_HANDLED : IRQ_NONE; |
80 | } | |
81 | ||
82 | static int | |
83 | nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) | |
0a34fb31 | 84 | { |
2b700825 | 85 | struct nvkm_pci *pci = nvkm_pci(subdev); |
340b0e7c | 86 | |
2b700825 BS |
87 | if (pci->irq >= 0) { |
88 | free_irq(pci->irq, pci); | |
89 | pci->irq = -1; | |
90 | }; | |
340b0e7c BS |
91 | |
92 | if (pci->agp.bridge) | |
93 | nvkm_agp_fini(pci); | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | static int | |
99 | nvkm_pci_preinit(struct nvkm_subdev *subdev) | |
100 | { | |
101 | struct nvkm_pci *pci = nvkm_pci(subdev); | |
102 | if (pci->agp.bridge) | |
103 | nvkm_agp_preinit(pci); | |
2b700825 BS |
104 | return 0; |
105 | } | |
106 | ||
bcc19d9b KH |
107 | static int |
108 | nvkm_pci_oneinit(struct nvkm_subdev *subdev) | |
109 | { | |
110 | struct nvkm_pci *pci = nvkm_pci(subdev); | |
111 | if (pci_is_pcie(pci->pdev)) | |
112 | return nvkm_pcie_oneinit(pci); | |
113 | return 0; | |
114 | } | |
115 | ||
2b700825 BS |
116 | static int |
117 | nvkm_pci_init(struct nvkm_subdev *subdev) | |
118 | { | |
119 | struct nvkm_pci *pci = nvkm_pci(subdev); | |
120 | struct pci_dev *pdev = pci->pdev; | |
121 | int ret; | |
122 | ||
340b0e7c BS |
123 | if (pci->agp.bridge) { |
124 | ret = nvkm_agp_init(pci); | |
125 | if (ret) | |
126 | return ret; | |
bcc19d9b KH |
127 | } else if (pci_is_pcie(pci->pdev)) { |
128 | nvkm_pcie_init(pci); | |
340b0e7c BS |
129 | } |
130 | ||
779d16aa BS |
131 | if (pci->func->init) |
132 | pci->func->init(pci); | |
133 | ||
2b700825 BS |
134 | ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci); |
135 | if (ret) | |
136 | return ret; | |
137 | ||
138 | pci->irq = pdev->irq; | |
139 | return ret; | |
0a34fb31 BS |
140 | } |
141 | ||
142 | static void * | |
143 | nvkm_pci_dtor(struct nvkm_subdev *subdev) | |
144 | { | |
2b700825 | 145 | struct nvkm_pci *pci = nvkm_pci(subdev); |
340b0e7c | 146 | nvkm_agp_dtor(pci); |
2b700825 BS |
147 | if (pci->msi) |
148 | pci_disable_msi(pci->pdev); | |
0a34fb31 BS |
149 | return nvkm_pci(subdev); |
150 | } | |
151 | ||
152 | static const struct nvkm_subdev_func | |
153 | nvkm_pci_func = { | |
154 | .dtor = nvkm_pci_dtor, | |
bcc19d9b | 155 | .oneinit = nvkm_pci_oneinit, |
340b0e7c | 156 | .preinit = nvkm_pci_preinit, |
2b700825 BS |
157 | .init = nvkm_pci_init, |
158 | .fini = nvkm_pci_fini, | |
0a34fb31 BS |
159 | }; |
160 | ||
161 | int | |
162 | nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, | |
163 | int index, struct nvkm_pci **ppci) | |
164 | { | |
165 | struct nvkm_pci *pci; | |
2b700825 | 166 | |
0a34fb31 BS |
167 | if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL))) |
168 | return -ENOMEM; | |
56d06fa2 | 169 | nvkm_subdev_ctor(&nvkm_pci_func, device, index, &pci->subdev); |
0a34fb31 | 170 | pci->func = func; |
2b700825 BS |
171 | pci->pdev = device->func->pci(device)->pdev; |
172 | pci->irq = -1; | |
bcc19d9b KH |
173 | pci->pcie.speed = -1; |
174 | pci->pcie.width = -1; | |
2b700825 | 175 | |
340b0e7c BS |
176 | if (device->type == NVKM_DEVICE_AGP) |
177 | nvkm_agp_ctor(pci); | |
178 | ||
2b700825 BS |
179 | switch (pci->pdev->device & 0x0ff0) { |
180 | case 0x00f0: | |
181 | case 0x02e0: | |
182 | /* BR02? NFI how these would be handled yet exactly */ | |
183 | break; | |
184 | default: | |
185 | switch (device->chipset) { | |
186 | case 0xaa: | |
187 | /* reported broken, nv also disable it */ | |
188 | break; | |
189 | default: | |
190 | pci->msi = true; | |
191 | break; | |
192 | } | |
193 | } | |
194 | ||
917d6389 IM |
195 | #ifdef __BIG_ENDIAN |
196 | pci->msi = false; | |
197 | #endif | |
198 | ||
2b700825 BS |
199 | pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi); |
200 | if (pci->msi && func->msi_rearm) { | |
201 | pci->msi = pci_enable_msi(pci->pdev) == 0; | |
202 | if (pci->msi) | |
203 | nvkm_debug(&pci->subdev, "MSI enabled\n"); | |
204 | } else { | |
205 | pci->msi = false; | |
206 | } | |
207 | ||
0a34fb31 BS |
208 | return 0; |
209 | } |