]>
Commit | Line | Data |
---|---|---|
08aa9d92 | 1 | --- linux-2.6.33/scripts/mod/modpost.c~ 2010-02-24 19:52:17.000000000 +0100 |
2 | +++ linux-2.6.33/scripts/mod/modpost.c 2010-03-07 14:26:47.242168558 +0100 | |
3 | @@ -15,7 +15,8 @@ | |
4 | #include <stdio.h> | |
5 | #include <ctype.h> | |
6 | #include "modpost.h" | |
7 | -#include "../../include/generated/autoconf.h" | |
8 | +// PLD architectures don't use CONFIG_SYMBOL_PREFIX | |
9 | +//#include "../../include/generated/autoconf.h" | |
10 | #include "../../include/linux/license.h" | |
11 | ||
12 | /* Some toolchains use a `_' prefix for all user symbols. */ | |
13 | ||
2136e199 AM |
14 | --- linux-3.0/scripts/kconfig/lxdialog/check-lxdialog.sh~ 2011-07-22 04:17:23.000000000 +0200 |
15 | +++ linux-3.0/scripts/kconfig/lxdialog/check-lxdialog.sh 2011-08-25 21:26:04.799150642 +0200 | |
16 | @@ -9,6 +9,12 @@ | |
17 | $cc -print-file-name=lib${lib}.${ext} | grep -q / | |
18 | if [ $? -eq 0 ]; then | |
19 | echo "-l${lib}" | |
20 | + for libt in tinfow tinfo ; do | |
21 | + $cc -print-file-name=lib${libt}.${ext} | grep -q / | |
22 | + if [ $? -eq 0 ]; then | |
23 | + echo "-l${libt}" | |
24 | + fi | |
25 | + done | |
26 | exit | |
27 | fi | |
28 | done | |
44c0f99c | 29 | |
59e60efc AM |
30 | diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c |
31 | index 7a0c800..ec5ebbb 100644 | |
32 | --- a/drivers/net/ethernet/realtek/r8169.c | |
33 | +++ b/drivers/net/ethernet/realtek/r8169.c | |
34 | @@ -4103,6 +4103,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |
35 | /* Get MAC address */ | |
36 | for (i = 0; i < ETH_ALEN; i++) | |
37 | dev->dev_addr[i] = RTL_R8(MAC0 + i); | |
38 | + | |
39 | + if (!is_valid_ether_addr(dev->dev_addr)) { | |
40 | + /* Report it and use a random ethernet address instead */ | |
41 | + netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr); | |
42 | + random_ether_addr(dev->dev_addr); | |
43 | + netdev_info(dev, "Using random MAC address: %pM\n", | |
44 | + dev->dev_addr); | |
45 | + } | |
46 | memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); | |
47 | ||
48 | SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops); | |
49 | -- | |
50 | 1.7.7.3 | |
51 | ||
7d841a4b | 52 | From 4acca62e1f1976015ebb718242523e1832716bc7 Mon Sep 17 00:00:00 2001 |
2dfbb274 | 53 | From: Takahisa Tanaka <mc74hc00@gmail.com> |
7d841a4b AM |
54 | Date: Wed, 14 Nov 2012 20:21:26 +0900 |
55 | Subject: [PATCH] sp5100_tco: Add SB8x0 chipset support | |
2dfbb274 AM |
56 | |
57 | The current sp5100_tco driver only supports SP5100/SB7x0 chipset, doesn't | |
58 | support SB8x0 chipset, because current sp5100_tco driver doesn't know that the | |
59 | offset address for watchdog timer was changed from SB8x0 chipset. | |
60 | ||
61 | The offset address of SP5100 and SB7x0 chipsets are as follows, quote from the | |
62 | AMD SB700/710/750 Register Reference Guide(Page 164) and the AMD SP5100 | |
63 | Register Reference Guide(Page 166). | |
64 | ||
65 | WatchDogTimerControl 69h | |
66 | WatchDogTimerBase0 6Ch | |
67 | WatchDogTimerBase1 6Dh | |
68 | WatchDogTimerBase2 6Eh | |
69 | WatchDogTimerBase3 6Fh | |
70 | ||
71 | In contrast, the offset address of SB8x0 chipset is as follows, quote from | |
72 | AMD SB800-Series Southbridges Register Reference Guide(Page 147). | |
73 | ||
74 | WatchDogTimerEn 48h | |
75 | WatchDogTimerConfig 4Ch | |
76 | ||
77 | So, In the case of SB8x0 chipset, sp5100_tco reads meaningless MMIO | |
78 | address(for example, 0xbafe00) from wrong offset address, and the following | |
79 | message is logged. | |
80 | ||
81 | SP5100 TCO timer: mmio address 0xbafe00 already in use | |
82 | ||
83 | With this patch, sp5100_tco driver supports SB8x0 chipset, and can avoid | |
7d841a4b | 84 | iomem resource conflict. |
2dfbb274 | 85 | |
7d841a4b AM |
86 | Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=43176 |
87 | To: linux-watchdog@vger.kernel.org | |
2dfbb274 AM |
88 | Signed-off-by: Takahisa Tanaka <mc74hc00@gmail.com> |
89 | ||
90 | --- | |
7d841a4b AM |
91 | v1 -> v2 |
92 | -Fix typo in module description and source code. | |
93 | -Fix a bug that can't correctly determine the watchdog fired. | |
94 | -Improve syslog messages. | |
95 | -Truncate the commit log, because previous commit log is too long. | |
96 | --- | |
97 | drivers/watchdog/sp5100_tco.c | 321 +++++++++++++++++++++++++++++++++++------- | |
98 | drivers/watchdog/sp5100_tco.h | 46 ++++-- | |
99 | 2 files changed, 306 insertions(+), 61 deletions(-) | |
2dfbb274 AM |
100 | |
101 | diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c | |
7d841a4b | 102 | index ae5e82c..183fcb2 100644 |
2dfbb274 AM |
103 | --- a/drivers/watchdog/sp5100_tco.c |
104 | +++ b/drivers/watchdog/sp5100_tco.c | |
105 | @@ -13,7 +13,9 @@ | |
106 | * as published by the Free Software Foundation; either version | |
107 | * 2 of the License, or (at your option) any later version. | |
108 | * | |
109 | - * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide" | |
110 | + * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide", | |
7d841a4b | 111 | + * AMD Publication 45482 "AMD SB800-Series Southbridges Register |
2dfbb274 AM |
112 | + * Reference Guide" |
113 | */ | |
114 | ||
115 | /* | |
7d841a4b | 116 | @@ -38,18 +40,24 @@ |
2dfbb274 AM |
117 | #include "sp5100_tco.h" |
118 | ||
119 | /* Module and version information */ | |
120 | -#define TCO_VERSION "0.01" | |
121 | +#define TCO_VERSION "0.03" | |
122 | #define TCO_MODULE_NAME "SP5100 TCO timer" | |
123 | #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION | |
124 | ||
125 | /* internal variables */ | |
126 | static u32 tcobase_phys; | |
127 | +static u32 resbase_phys; | |
7d841a4b | 128 | +static u32 tco_wdt_fired; |
2dfbb274 AM |
129 | static void __iomem *tcobase; |
130 | static unsigned int pm_iobase; | |
131 | static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ | |
132 | static unsigned long timer_alive; | |
133 | static char tco_expect_close; | |
134 | static struct pci_dev *sp5100_tco_pci; | |
135 | +static struct resource wdt_res = { | |
136 | + .name = "Watchdog Timer", | |
137 | + .flags = IORESOURCE_MEM, | |
138 | +}; | |
139 | ||
140 | /* the watchdog platform device */ | |
141 | static struct platform_device *sp5100_tco_platform_device; | |
7d841a4b AM |
142 | @@ -64,9 +72,15 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default=" |
143 | ||
144 | static bool nowayout = WATCHDOG_NOWAYOUT; | |
145 | module_param(nowayout, bool, 0); | |
146 | -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" | |
147 | +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started." | |
2dfbb274 AM |
148 | " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
149 | ||
150 | +static unsigned int force_addr; | |
151 | +module_param(force_addr, uint, 0); | |
7d841a4b AM |
152 | +MODULE_PARM_DESC(force_addr, "Force the use of specified MMIO address." |
153 | + " ONLY USE THIS PARAMETER IF YOU REALLY KNOW" | |
154 | + " WHAT YOU ARE DOING (default=none)"); | |
2dfbb274 AM |
155 | + |
156 | /* | |
157 | * Some TCO specific functions | |
158 | */ | |
7d841a4b | 159 | @@ -122,6 +136,79 @@ static int tco_timer_set_heartbeat(int t) |
2dfbb274 AM |
160 | return 0; |
161 | } | |
162 | ||
163 | +static void tco_timer_enable(void) | |
164 | +{ | |
165 | + int val; | |
166 | + | |
167 | + if (sp5100_tco_pci->revision >= 0x40) { | |
168 | + /* For SB800 or later */ | |
169 | + /* Set the Watchdog timer resolution to 1 sec */ | |
170 | + outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG); | |
171 | + val = inb(SB800_IO_PM_DATA_REG); | |
172 | + val |= SB800_PM_WATCHDOG_SECOND_RES; | |
173 | + outb(val, SB800_IO_PM_DATA_REG); | |
174 | + | |
175 | + /* Enable watchdog decode bit and watchdog timer */ | |
176 | + outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG); | |
177 | + val = inb(SB800_IO_PM_DATA_REG); | |
178 | + val |= SB800_PCI_WATCHDOG_DECODE_EN; | |
179 | + val &= ~SB800_PM_WATCHDOG_DISABLE; | |
180 | + outb(val, SB800_IO_PM_DATA_REG); | |
181 | + } else { | |
182 | + /* For SP5100 or SB7x0 */ | |
183 | + /* Enable watchdog decode bit */ | |
184 | + pci_read_config_dword(sp5100_tco_pci, | |
185 | + SP5100_PCI_WATCHDOG_MISC_REG, | |
186 | + &val); | |
187 | + | |
188 | + val |= SP5100_PCI_WATCHDOG_DECODE_EN; | |
189 | + | |
190 | + pci_write_config_dword(sp5100_tco_pci, | |
191 | + SP5100_PCI_WATCHDOG_MISC_REG, | |
192 | + val); | |
193 | + | |
194 | + /* Enable Watchdog timer and set the resolution to 1 sec */ | |
195 | + outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); | |
196 | + val = inb(SP5100_IO_PM_DATA_REG); | |
197 | + val |= SP5100_PM_WATCHDOG_SECOND_RES; | |
198 | + val &= ~SP5100_PM_WATCHDOG_DISABLE; | |
199 | + outb(val, SP5100_IO_PM_DATA_REG); | |
200 | + } | |
201 | +} | |
202 | + | |
203 | +static void tco_timer_disable(void) | |
204 | +{ | |
205 | + int val; | |
206 | + | |
207 | + if (sp5100_tco_pci->revision >= 0x40) { | |
208 | + /* For SB800 or later */ | |
209 | + /* Enable watchdog decode bit and Disable watchdog timer */ | |
210 | + outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG); | |
211 | + val = inb(SB800_IO_PM_DATA_REG); | |
212 | + val |= SB800_PCI_WATCHDOG_DECODE_EN; | |
213 | + val |= SB800_PM_WATCHDOG_DISABLE; | |
214 | + outb(val, SB800_IO_PM_DATA_REG); | |
215 | + } else { | |
216 | + /* For SP5100 or SB7x0 */ | |
217 | + /* Enable watchdog decode bit */ | |
218 | + pci_read_config_dword(sp5100_tco_pci, | |
219 | + SP5100_PCI_WATCHDOG_MISC_REG, | |
220 | + &val); | |
221 | + | |
222 | + val |= SP5100_PCI_WATCHDOG_DECODE_EN; | |
223 | + | |
224 | + pci_write_config_dword(sp5100_tco_pci, | |
225 | + SP5100_PCI_WATCHDOG_MISC_REG, | |
226 | + val); | |
227 | + | |
228 | + /* Disable Watchdog timer */ | |
229 | + outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); | |
230 | + val = inb(SP5100_IO_PM_DATA_REG); | |
231 | + val |= SP5100_PM_WATCHDOG_DISABLE; | |
232 | + outb(val, SP5100_IO_PM_DATA_REG); | |
233 | + } | |
234 | +} | |
235 | + | |
236 | /* | |
237 | * /dev/watchdog handling | |
238 | */ | |
7d841a4b | 239 | @@ -270,11 +357,12 @@ MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl); |
2dfbb274 AM |
240 | /* |
241 | * Init & exit routines | |
242 | */ | |
243 | - | |
244 | static unsigned char __devinit sp5100_tco_setupdevice(void) | |
245 | { | |
246 | struct pci_dev *dev = NULL; | |
247 | + const char *dev_name = NULL; | |
248 | u32 val; | |
249 | + u32 index_reg, data_reg, base_addr; | |
250 | ||
251 | /* Match the PCI device */ | |
252 | for_each_pci_dev(dev) { | |
7d841a4b | 253 | @@ -287,29 +375,160 @@ static unsigned char __devinit sp5100_tco_setupdevice(void) |
2dfbb274 AM |
254 | if (!sp5100_tco_pci) |
255 | return 0; | |
256 | ||
257 | + pr_info("PCI Revision ID: 0x%x\n", sp5100_tco_pci->revision); | |
258 | + | |
259 | + /* | |
260 | + * Determine type of southbridge chipset. | |
261 | + */ | |
262 | + if (sp5100_tco_pci->revision >= 0x40) { | |
263 | + dev_name = SB800_DEVNAME; | |
264 | + index_reg = SB800_IO_PM_INDEX_REG; | |
265 | + data_reg = SB800_IO_PM_DATA_REG; | |
266 | + base_addr = SB800_PM_WATCHDOG_BASE; | |
267 | + } else { | |
268 | + dev_name = SP5100_DEVNAME; | |
269 | + index_reg = SP5100_IO_PM_INDEX_REG; | |
270 | + data_reg = SP5100_IO_PM_DATA_REG; | |
271 | + base_addr = SP5100_PM_WATCHDOG_BASE; | |
272 | + } | |
273 | + | |
274 | /* Request the IO ports used by this driver */ | |
275 | pm_iobase = SP5100_IO_PM_INDEX_REG; | |
276 | - if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) { | |
2dfbb274 | 277 | + if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, dev_name)) { |
7d841a4b | 278 | pr_err("I/O address 0x%04x already in use\n", pm_iobase); |
2dfbb274 AM |
279 | goto exit; |
280 | } | |
281 | ||
282 | - /* Find the watchdog base address. */ | |
283 | - outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG); | |
284 | - val = inb(SP5100_IO_PM_DATA_REG); | |
285 | - outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG); | |
286 | - val = val << 8 | inb(SP5100_IO_PM_DATA_REG); | |
287 | - outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG); | |
288 | - val = val << 8 | inb(SP5100_IO_PM_DATA_REG); | |
289 | - outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG); | |
290 | - /* Low three bits of BASE0 are reserved. */ | |
291 | - val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); | |
292 | + /* | |
293 | + * First, Find the watchdog timer MMIO address from indirect I/O. | |
294 | + */ | |
295 | + outb(base_addr+3, index_reg); | |
296 | + val = inb(data_reg); | |
297 | + outb(base_addr+2, index_reg); | |
298 | + val = val << 8 | inb(data_reg); | |
299 | + outb(base_addr+1, index_reg); | |
300 | + val = val << 8 | inb(data_reg); | |
301 | + outb(base_addr+0, index_reg); | |
302 | + /* Low three bits of BASE are reserved */ | |
303 | + val = val << 8 | (inb(data_reg) & 0xf8); | |
304 | + | |
7d841a4b | 305 | + pr_debug("Got 0x%04x from indirect I/O\n", val); |
2dfbb274 AM |
306 | + |
307 | + /* Check MMIO address conflict */ | |
308 | + if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, | |
309 | + dev_name)) | |
310 | + goto setup_wdt; | |
311 | + else | |
7d841a4b | 312 | + pr_debug("MMIO address 0x%04x already in use\n", val); |
2dfbb274 AM |
313 | + |
314 | + /* | |
7d841a4b | 315 | + * Secondly, Find the watchdog timer MMIO address |
2dfbb274 AM |
316 | + * from SBResource_MMIO register. |
317 | + */ | |
318 | + if (sp5100_tco_pci->revision >= 0x40) { | |
319 | + /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */ | |
320 | + outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG); | |
321 | + val = inb(SB800_IO_PM_DATA_REG); | |
322 | + outb(SB800_PM_ACPI_MMIO_EN+2, SB800_IO_PM_INDEX_REG); | |
323 | + val = val << 8 | inb(SB800_IO_PM_DATA_REG); | |
324 | + outb(SB800_PM_ACPI_MMIO_EN+1, SB800_IO_PM_INDEX_REG); | |
325 | + val = val << 8 | inb(SB800_IO_PM_DATA_REG); | |
326 | + outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG); | |
327 | + val = val << 8 | inb(SB800_IO_PM_DATA_REG); | |
328 | + } else { | |
329 | + /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */ | |
330 | + pci_read_config_dword(sp5100_tco_pci, | |
331 | + SP5100_SB_RESOURCE_MMIO_BASE, &val); | |
332 | + } | |
333 | + | |
334 | + /* The SBResource_MMIO is enabled and mapped memory space? */ | |
335 | + if ((val & (SB800_ACPI_MMIO_DECODE_EN | SB800_ACPI_MMIO_SEL)) == | |
336 | + SB800_ACPI_MMIO_DECODE_EN) { | |
337 | + /* Clear unnecessary the low twelve bits */ | |
338 | + val &= ~0xFFF; | |
339 | + /* Add the Watchdog Timer offset to base address. */ | |
340 | + val += SB800_PM_WDT_MMIO_OFFSET; | |
7d841a4b | 341 | + /* Check MMIO address conflict */ |
2dfbb274 AM |
342 | + if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, |
343 | + dev_name)) { | |
7d841a4b | 344 | + pr_debug("Got 0x%04x from SBResource_MMIO register\n", |
2dfbb274 AM |
345 | + val); |
346 | + goto setup_wdt; | |
347 | + } else | |
7d841a4b | 348 | + pr_debug("MMIO address 0x%04x already in use\n", val); |
2dfbb274 | 349 | + } else |
7d841a4b | 350 | + pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val); |
2dfbb274 AM |
351 | + |
352 | + /* | |
7d841a4b | 353 | + * Lastly re-programming the watchdog timer MMIO address, |
2dfbb274 AM |
354 | + * This method is a last resort... |
355 | + * | |
356 | + * Before re-programming, to ensure that the watchdog timer | |
357 | + * is disabled, disable the watchdog timer. | |
358 | + */ | |
359 | + tco_timer_disable(); | |
360 | + | |
361 | + if (force_addr) { | |
7d841a4b AM |
362 | + /* |
363 | + * Force the use of watchdog timer MMIO address, and aligned to | |
364 | + * 8byte boundary. | |
365 | + */ | |
366 | + force_addr &= ~0x7; | |
2dfbb274 | 367 | + val = force_addr; |
2dfbb274 | 368 | + |
7d841a4b | 369 | + pr_info("Force the use of 0x%04x as MMIO address\n", val); |
2dfbb274 AM |
370 | + } else { |
371 | + /* | |
372 | + * Get empty slot into the resource tree for watchdog timer. | |
373 | + */ | |
374 | + if (allocate_resource(&iomem_resource, | |
375 | + &wdt_res, | |
376 | + SP5100_WDT_MEM_MAP_SIZE, | |
377 | + 0xf0000000, | |
378 | + 0xfffffff8, | |
379 | + 0x8, | |
380 | + NULL, | |
381 | + NULL)) { | |
382 | + pr_err("MMIO allocation failed\n"); | |
383 | + goto unreg_region; | |
384 | + } | |
385 | + | |
386 | + val = resbase_phys = wdt_res.start; | |
7d841a4b | 387 | + pr_debug("Got 0x%04x from resource tree\n", val); |
2dfbb274 AM |
388 | + } |
389 | + | |
390 | + /* Restore to the low three bits, if chipset is SB8x0(or later) */ | |
391 | + if (sp5100_tco_pci->revision >= 0x40) { | |
392 | + u8 reserved_bit; | |
393 | + reserved_bit = inb(base_addr) & 0x7; | |
394 | + val |= (u32)reserved_bit; | |
395 | + } | |
396 | + | |
397 | + /* Re-programming the watchdog timer base address */ | |
398 | + outb(base_addr+0, index_reg); | |
399 | + /* Low three bits of BASE are reserved */ | |
400 | + outb((val >> 0) & 0xf8, data_reg); | |
401 | + outb(base_addr+1, index_reg); | |
402 | + outb((val >> 8) & 0xff, data_reg); | |
403 | + outb(base_addr+2, index_reg); | |
404 | + outb((val >> 16) & 0xff, data_reg); | |
405 | + outb(base_addr+3, index_reg); | |
406 | + outb((val >> 24) & 0xff, data_reg); | |
407 | + | |
408 | + /* | |
409 | + * Clear unnecessary the low three bits, | |
410 | + * if chipset is SB8x0(or later) | |
411 | + */ | |
412 | + if (sp5100_tco_pci->revision >= 0x40) | |
413 | + val &= ~0x7; | |
414 | ||
415 | if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, | |
416 | - "SP5100 TCO")) { | |
417 | - pr_err("mmio address 0x%04x already in use\n", val); | |
418 | - goto unreg_region; | |
419 | + dev_name)) { | |
7d841a4b | 420 | + pr_err("MMIO address 0x%04x already in use\n", val); |
2dfbb274 AM |
421 | + goto unreg_resource; |
422 | } | |
423 | + | |
424 | +setup_wdt: | |
425 | tcobase_phys = val; | |
426 | ||
427 | tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); | |
7d841a4b | 428 | @@ -318,26 +537,18 @@ static unsigned char __devinit sp5100_tco_setupdevice(void) |
2dfbb274 AM |
429 | goto unreg_mem_region; |
430 | } | |
431 | ||
432 | - /* Enable watchdog decode bit */ | |
433 | - pci_read_config_dword(sp5100_tco_pci, | |
434 | - SP5100_PCI_WATCHDOG_MISC_REG, | |
435 | - &val); | |
436 | - | |
437 | - val |= SP5100_PCI_WATCHDOG_DECODE_EN; | |
7d841a4b AM |
438 | + pr_info("Using 0x%04x for watchdog MMIO address\n", val); |
439 | ||
2dfbb274 AM |
440 | - pci_write_config_dword(sp5100_tco_pci, |
441 | - SP5100_PCI_WATCHDOG_MISC_REG, | |
442 | - val); | |
7d841a4b AM |
443 | + /* Setup the watchdog timer */ |
444 | + tco_timer_enable(); | |
2dfbb274 AM |
445 | |
446 | - /* Enable Watchdog timer and set the resolution to 1 sec. */ | |
447 | - outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); | |
448 | - val = inb(SP5100_IO_PM_DATA_REG); | |
449 | - val |= SP5100_PM_WATCHDOG_SECOND_RES; | |
450 | - val &= ~SP5100_PM_WATCHDOG_DISABLE; | |
451 | - outb(val, SP5100_IO_PM_DATA_REG); | |
7d841a4b | 452 | - |
2dfbb274 AM |
453 | - /* Check that the watchdog action is set to reset the system. */ |
454 | + /* Check that the watchdog action is set to reset the system */ | |
455 | val = readl(SP5100_WDT_CONTROL(tcobase)); | |
7d841a4b AM |
456 | + /* |
457 | + * Save WatchDogFired status, because WatchDogFired flag is | |
458 | + * cleared here. | |
459 | + */ | |
460 | + tco_wdt_fired = val & SP5100_PM_WATCHDOG_FIRED; | |
2dfbb274 AM |
461 | val &= ~SP5100_PM_WATCHDOG_ACTION_RESET; |
462 | writel(val, SP5100_WDT_CONTROL(tcobase)); | |
7d841a4b AM |
463 | |
464 | @@ -355,6 +566,9 @@ static unsigned char __devinit sp5100_tco_setupdevice(void) | |
2dfbb274 AM |
465 | |
466 | unreg_mem_region: | |
467 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | |
468 | +unreg_resource: | |
469 | + if (resbase_phys) | |
470 | + release_resource(&wdt_res); | |
471 | unreg_region: | |
472 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | |
473 | exit: | |
7d841a4b AM |
474 | @@ -364,23 +578,18 @@ exit: |
475 | static int __devinit sp5100_tco_init(struct platform_device *dev) | |
476 | { | |
477 | int ret; | |
478 | - u32 val; | |
479 | + char addr_str[16]; | |
480 | ||
481 | - /* Check whether or not the hardware watchdog is there. If found, then | |
482 | + /* | |
483 | + * Check whether or not the hardware watchdog is there. If found, then | |
484 | * set it up. | |
485 | */ | |
486 | if (!sp5100_tco_setupdevice()) | |
487 | return -ENODEV; | |
488 | ||
489 | /* Check to see if last reboot was due to watchdog timeout */ | |
490 | - pr_info("Watchdog reboot %sdetected\n", | |
491 | - readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ? | |
492 | - "" : "not "); | |
493 | - | |
494 | - /* Clear out the old status */ | |
495 | - val = readl(SP5100_WDT_CONTROL(tcobase)); | |
496 | - val &= ~SP5100_PM_WATCHDOG_FIRED; | |
497 | - writel(val, SP5100_WDT_CONTROL(tcobase)); | |
498 | + pr_info("Last reboot was %striggered by watchdog.\n", | |
499 | + tco_wdt_fired ? "" : "not "); | |
500 | ||
501 | /* | |
502 | * Check that the heartbeat value is within it's range. | |
503 | @@ -400,14 +609,24 @@ static int __devinit sp5100_tco_init(struct platform_device *dev) | |
2dfbb274 AM |
504 | |
505 | clear_bit(0, &timer_alive); | |
506 | ||
507 | - pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", | |
508 | - tcobase, heartbeat, nowayout); | |
7d841a4b AM |
509 | + /* Show module parameters */ |
510 | + if (force_addr == tcobase_phys) | |
511 | + /* The force_addr is vaild */ | |
512 | + sprintf(addr_str, "0x%04x", force_addr); | |
513 | + else | |
514 | + strcpy(addr_str, "none"); | |
515 | + | |
2dfbb274 | 516 | + pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d, " |
7d841a4b AM |
517 | + "force_addr=%s)\n", |
518 | + tcobase, heartbeat, nowayout, addr_str); | |
2dfbb274 AM |
519 | |
520 | return 0; | |
521 | ||
522 | exit: | |
523 | iounmap(tcobase); | |
524 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | |
525 | + if (resbase_phys) | |
526 | + release_resource(&wdt_res); | |
527 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | |
528 | return ret; | |
529 | } | |
7d841a4b | 530 | @@ -422,6 +641,8 @@ static void __devexit sp5100_tco_cleanup(void) |
2dfbb274 AM |
531 | misc_deregister(&sp5100_tco_miscdev); |
532 | iounmap(tcobase); | |
533 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | |
534 | + if (resbase_phys) | |
535 | + release_resource(&wdt_res); | |
536 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | |
537 | } | |
538 | ||
7d841a4b | 539 | @@ -451,7 +672,7 @@ static int __init sp5100_tco_init_module(void) |
2dfbb274 AM |
540 | { |
541 | int err; | |
542 | ||
543 | - pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION); | |
544 | + pr_info("SP5100/SB800 TCO WatchDog Timer Driver v%s\n", TCO_VERSION); | |
545 | ||
546 | err = platform_driver_register(&sp5100_tco_driver); | |
547 | if (err) | |
7d841a4b | 548 | @@ -475,13 +696,13 @@ static void __exit sp5100_tco_cleanup_module(void) |
2dfbb274 AM |
549 | { |
550 | platform_device_unregister(sp5100_tco_platform_device); | |
551 | platform_driver_unregister(&sp5100_tco_driver); | |
552 | - pr_info("SP5100 TCO Watchdog Module Unloaded\n"); | |
553 | + pr_info("SP5100/SB800 TCO Watchdog Module Unloaded\n"); | |
554 | } | |
555 | ||
556 | module_init(sp5100_tco_init_module); | |
557 | module_exit(sp5100_tco_cleanup_module); | |
558 | ||
559 | MODULE_AUTHOR("Priyanka Gupta"); | |
560 | -MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset"); | |
561 | +MODULE_DESCRIPTION("TCO timer driver for SP5100/SB800 chipset"); | |
562 | MODULE_LICENSE("GPL"); | |
563 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | |
564 | diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h | |
565 | index a5a16cc..71594a0 100644 | |
566 | --- a/drivers/watchdog/sp5100_tco.h | |
567 | +++ b/drivers/watchdog/sp5100_tco.h | |
568 | @@ -9,33 +9,57 @@ | |
569 | /* | |
570 | * Some address definitions for the Watchdog | |
571 | */ | |
572 | - | |
573 | #define SP5100_WDT_MEM_MAP_SIZE 0x08 | |
574 | #define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */ | |
575 | #define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */ | |
576 | ||
577 | -#define SP5100_WDT_START_STOP_BIT 1 | |
578 | +#define SP5100_WDT_START_STOP_BIT (1 << 0) | |
579 | #define SP5100_WDT_TRIGGER_BIT (1 << 7) | |
580 | ||
581 | -#define SP5100_PCI_WATCHDOG_MISC_REG 0x41 | |
582 | -#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3) | |
583 | - | |
584 | #define SP5100_PM_IOPORTS_SIZE 0x02 | |
585 | ||
586 | -/* These two IO registers are hardcoded and there doesn't seem to be a way to | |
587 | +/* | |
588 | + * These two IO registers are hardcoded and there doesn't seem to be a way to | |
589 | * read them from a register. | |
590 | */ | |
591 | + | |
592 | +/* For SP5100/SB7x0 chipset */ | |
593 | #define SP5100_IO_PM_INDEX_REG 0xCD6 | |
594 | #define SP5100_IO_PM_DATA_REG 0xCD7 | |
595 | ||
596 | +#define SP5100_SB_RESOURCE_MMIO_BASE 0x9C | |
597 | + | |
598 | #define SP5100_PM_WATCHDOG_CONTROL 0x69 | |
599 | -#define SP5100_PM_WATCHDOG_BASE0 0x6C | |
600 | -#define SP5100_PM_WATCHDOG_BASE1 0x6D | |
601 | -#define SP5100_PM_WATCHDOG_BASE2 0x6E | |
602 | -#define SP5100_PM_WATCHDOG_BASE3 0x6F | |
603 | +#define SP5100_PM_WATCHDOG_BASE 0x6C | |
604 | ||
605 | #define SP5100_PM_WATCHDOG_FIRED (1 << 1) | |
606 | #define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2) | |
607 | ||
608 | -#define SP5100_PM_WATCHDOG_DISABLE 1 | |
609 | +#define SP5100_PCI_WATCHDOG_MISC_REG 0x41 | |
610 | +#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3) | |
611 | + | |
612 | +#define SP5100_PM_WATCHDOG_DISABLE (1 << 0) | |
613 | #define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1) | |
614 | + | |
615 | +#define SP5100_DEVNAME "SP5100 TCO" | |
616 | + | |
617 | + | |
618 | +/* For SB8x0(or later) chipset */ | |
619 | +#define SB800_IO_PM_INDEX_REG 0xCD6 | |
620 | +#define SB800_IO_PM_DATA_REG 0xCD7 | |
621 | + | |
622 | +#define SB800_PM_ACPI_MMIO_EN 0x24 | |
623 | +#define SB800_PM_WATCHDOG_CONTROL 0x48 | |
624 | +#define SB800_PM_WATCHDOG_BASE 0x48 | |
625 | +#define SB800_PM_WATCHDOG_CONFIG 0x4C | |
626 | + | |
627 | +#define SB800_PCI_WATCHDOG_DECODE_EN (1 << 0) | |
628 | +#define SB800_PM_WATCHDOG_DISABLE (1 << 2) | |
629 | +#define SB800_PM_WATCHDOG_SECOND_RES (3 << 0) | |
630 | +#define SB800_ACPI_MMIO_DECODE_EN (1 << 0) | |
631 | +#define SB800_ACPI_MMIO_SEL (1 << 2) | |
632 | + | |
633 | + | |
634 | +#define SB800_PM_WDT_MMIO_OFFSET 0xB00 | |
635 | + | |
636 | +#define SB800_DEVNAME "SB800 TCO" | |
7d841a4b AM |
637 | -- |
638 | 1.7.11.7 | |
639 | ||
0311d6d3 AM |
640 | From eba48cd0f05ff7a2f82291feae169c14b61b29af Mon Sep 17 00:00:00 2001 |
641 | From: Andrew Cooks <acooks@gmail.com> | |
642 | Date: Tue, 13 Nov 2012 12:39:07 +0800 | |
643 | Subject: [PATCH] PCI: Add GPL license for drivers/pci/ioapic module | |
644 | ||
645 | Config PCI_IOAPIC turned into a tristate in commit b95a7bd70046, but no | |
646 | module license is specified. This adds the missing module license. | |
647 | ||
648 | Signed-off-by: Andrew Cooks <acooks@gmail.com> | |
649 | Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> | |
650 | Acked-by: Jan Beulich <jbeulich@suse.com> | |
651 | --- | |
652 | drivers/pci/ioapic.c | 2 ++ | |
653 | 1 files changed, 2 insertions(+), 0 deletions(-) | |
654 | ||
655 | diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c | |
656 | index 205af8d..22436f7 100644 | |
657 | --- a/drivers/pci/ioapic.c | |
658 | +++ b/drivers/pci/ioapic.c | |
659 | @@ -125,3 +125,5 @@ static void __exit ioapic_exit(void) | |
660 | ||
661 | module_init(ioapic_init); | |
662 | module_exit(ioapic_exit); | |
663 | + | |
664 | +MODULE_LICENSE("GPL"); | |
665 | -- | |
666 | 1.7.6.5 | |
667 | ||
a92b037e | 668 | |
8a73b835 LM |
669 | diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c |
670 | index 042c1ff..d07c240 100644 | |
671 | --- a/drivers/regulator/core.c | |
672 | +++ b/drivers/regulator/core.c | |
673 | @@ -1872,7 +1872,14 @@ int regulator_count_voltages(struct regulator *regulator) | |
674 | { | |
675 | struct regulator_dev *rdev = regulator->rdev; | |
676 | ||
677 | - return rdev->desc->n_voltages ? : -EINVAL; | |
678 | + if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE) { | |
679 | + if (rdev->desc->n_voltages) | |
680 | + return rdev->desc->n_voltages; | |
681 | + else | |
682 | + return -EINVAL; | |
683 | + } else { | |
684 | + return 1; | |
685 | + } | |
686 | } | |
687 | EXPORT_SYMBOL_GPL(regulator_count_voltages); | |
688 | ||
689 | diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c | |
690 | index c7851c0..6f6534e 100644 | |
691 | --- a/drivers/mmc/host/sdhci.c | |
692 | +++ b/drivers/mmc/host/sdhci.c | |
693 | @@ -2923,7 +2923,7 @@ int sdhci_add_host(struct sdhci_host *host) | |
694 | regulator_enable(host->vmmc); | |
695 | ||
696 | #ifdef CONFIG_REGULATOR | |
697 | - if (host->vmmc) { | |
698 | + if (host->vmmc && regulator_count_voltages(host->vmmc) > 1) { | |
699 | ret = regulator_is_supported_voltage(host->vmmc, 3300000, | |
700 | 3300000); | |
701 | if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330))) | |
af554b14 PS |
702 | From 2d32b29a1c2830f7c42caa8258c714acd983961f Mon Sep 17 00:00:00 2001 |
703 | From: majianpeng <majianpeng@gmail.com> | |
704 | Date: Tue, 29 Jan 2013 13:16:06 +0800 | |
705 | Subject: nfsd: Fix memleak | |
706 | ||
707 | From: majianpeng <majianpeng@gmail.com> | |
708 | ||
709 | commit 2d32b29a1c2830f7c42caa8258c714acd983961f upstream. | |
710 | ||
711 | When free nfs-client, it must free the ->cl_stateids. | |
712 | ||
713 | Signed-off-by: Jianpeng Ma <majianpeng@gmail.com> | |
714 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | |
715 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
716 | ||
717 | --- | |
718 | fs/nfsd/nfs4state.c | 2 ++ | |
719 | 1 file changed, 2 insertions(+) | |
720 | ||
721 | --- a/fs/nfsd/nfs4state.c | |
722 | +++ b/fs/nfsd/nfs4state.c | |
723 | @@ -1053,6 +1053,8 @@ free_client(struct nfs4_client *clp) | |
724 | put_group_info(clp->cl_cred.cr_group_info); | |
725 | kfree(clp->cl_principal); | |
726 | kfree(clp->cl_name.data); | |
727 | + idr_remove_all(&clp->cl_stateids); | |
728 | + idr_destroy(&clp->cl_stateids); | |
729 | kfree(clp); | |
730 | } | |
731 | ||
732 | From e75bafbff2270993926abcc31358361db74a9bc2 Mon Sep 17 00:00:00 2001 | |
733 | From: "J. Bruce Fields" <bfields@redhat.com> | |
734 | Date: Sun, 10 Feb 2013 11:33:48 -0500 | |
735 | Subject: svcrpc: make svc_age_temp_xprts enqueue under sv_lock | |
736 | ||
737 | From: "J. Bruce Fields" <bfields@redhat.com> | |
738 | ||
739 | commit e75bafbff2270993926abcc31358361db74a9bc2 upstream. | |
740 | ||
741 | svc_age_temp_xprts expires xprts in a two-step process: first it takes | |
742 | the sv_lock and moves the xprts to expire off their server-wide list | |
743 | (sv_tempsocks or sv_permsocks) to a local list. Then it drops the | |
744 | sv_lock and enqueues and puts each one. | |
745 | ||
746 | I see no reason for this: svc_xprt_enqueue() will take sp_lock, but the | |
747 | sv_lock and sp_lock are not otherwise nested anywhere (and documentation | |
748 | at the top of this file claims it's correct to nest these with sp_lock | |
749 | inside.) | |
750 | ||
751 | Tested-by: Jason Tibbitts <tibbs@math.uh.edu> | |
752 | Tested-by: Paweł Sikora <pawel.sikora@agmk.net> | |
753 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | |
754 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
755 | ||
756 | --- | |
757 | net/sunrpc/svc_xprt.c | 15 ++------------- | |
758 | 1 file changed, 2 insertions(+), 13 deletions(-) | |
759 | ||
760 | --- a/net/sunrpc/svc_xprt.c | |
761 | +++ b/net/sunrpc/svc_xprt.c | |
762 | @@ -817,7 +817,6 @@ static void svc_age_temp_xprts(unsigned | |
763 | struct svc_serv *serv = (struct svc_serv *)closure; | |
764 | struct svc_xprt *xprt; | |
765 | struct list_head *le, *next; | |
766 | - LIST_HEAD(to_be_aged); | |
767 | ||
768 | dprintk("svc_age_temp_xprts\n"); | |
769 | ||
770 | @@ -838,25 +837,15 @@ static void svc_age_temp_xprts(unsigned | |
771 | if (atomic_read(&xprt->xpt_ref.refcount) > 1 || | |
772 | test_bit(XPT_BUSY, &xprt->xpt_flags)) | |
773 | continue; | |
774 | - svc_xprt_get(xprt); | |
775 | - list_move(le, &to_be_aged); | |
776 | + list_del_init(le); | |
777 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | |
778 | set_bit(XPT_DETACHED, &xprt->xpt_flags); | |
779 | - } | |
780 | - spin_unlock_bh(&serv->sv_lock); | |
781 | - | |
782 | - while (!list_empty(&to_be_aged)) { | |
783 | - le = to_be_aged.next; | |
784 | - /* fiddling the xpt_list node is safe 'cos we're XPT_DETACHED */ | |
785 | - list_del_init(le); | |
786 | - xprt = list_entry(le, struct svc_xprt, xpt_list); | |
787 | - | |
788 | dprintk("queuing xprt %p for closing\n", xprt); | |
789 | ||
790 | /* a thread will dequeue and close it soon */ | |
791 | svc_xprt_enqueue(xprt); | |
792 | - svc_xprt_put(xprt); | |
793 | } | |
794 | + spin_unlock_bh(&serv->sv_lock); | |
795 | ||
796 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); | |
797 | } | |
06d3ba47 PS |
798 | From cc630d9f476445927fca599f81182c7f06f79058 Mon Sep 17 00:00:00 2001 |
799 | From: "J. Bruce Fields" <bfields@redhat.com> | |
800 | Date: Sun, 10 Feb 2013 16:08:11 -0500 | |
801 | Subject: svcrpc: fix rpc server shutdown races | |
802 | ||
803 | From: "J. Bruce Fields" <bfields@redhat.com> | |
804 | ||
805 | commit cc630d9f476445927fca599f81182c7f06f79058 upstream. | |
806 | ||
807 | Rewrite server shutdown to remove the assumption that there are no | |
808 | longer any threads running (no longer true, for example, when shutting | |
809 | down the service in one network namespace while it's still running in | |
810 | others). | |
811 | ||
812 | Do that by doing what we'd do in normal circumstances: just CLOSE each | |
813 | socket, then enqueue it. | |
814 | ||
815 | Since there may not be threads to handle the resulting queued xprts, | |
816 | also run a simplified version of the svc_recv() loop run by a server to | |
817 | clean up any closed xprts afterwards. | |
818 | ||
819 | Tested-by: Jason Tibbitts <tibbs@math.uh.edu> | |
820 | Tested-by: Paweł Sikora <pawel.sikora@agmk.net> | |
821 | Acked-by: Stanislav Kinsbursky <skinsbursky@parallels.com> | |
822 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | |
823 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
824 | ||
825 | --- | |
826 | net/sunrpc/svc.c | 9 ------- | |
827 | net/sunrpc/svc_xprt.c | 57 ++++++++++++++++++++++++++++---------------------- | |
828 | 2 files changed, 32 insertions(+), 34 deletions(-) | |
829 | ||
830 | --- a/net/sunrpc/svc.c | |
831 | +++ b/net/sunrpc/svc.c | |
832 | @@ -515,15 +515,6 @@ EXPORT_SYMBOL_GPL(svc_create_pooled); | |
833 | ||
834 | void svc_shutdown_net(struct svc_serv *serv, struct net *net) | |
835 | { | |
836 | - /* | |
837 | - * The set of xprts (contained in the sv_tempsocks and | |
838 | - * sv_permsocks lists) is now constant, since it is modified | |
839 | - * only by accepting new sockets (done by service threads in | |
840 | - * svc_recv) or aging old ones (done by sv_temptimer), or | |
841 | - * configuration changes (excluded by whatever locking the | |
842 | - * caller is using--nfsd_mutex in the case of nfsd). So it's | |
843 | - * safe to traverse those lists and shut everything down: | |
844 | - */ | |
845 | svc_close_net(serv, net); | |
846 | ||
847 | if (serv->sv_shutdown) | |
848 | --- a/net/sunrpc/svc_xprt.c | |
849 | +++ b/net/sunrpc/svc_xprt.c | |
850 | @@ -948,21 +948,24 @@ void svc_close_xprt(struct svc_xprt *xpr | |
851 | } | |
852 | EXPORT_SYMBOL_GPL(svc_close_xprt); | |
853 | ||
854 | -static void svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) | |
855 | +static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) | |
856 | { | |
857 | struct svc_xprt *xprt; | |
858 | + int ret = 0; | |
859 | ||
860 | spin_lock(&serv->sv_lock); | |
861 | list_for_each_entry(xprt, xprt_list, xpt_list) { | |
862 | if (xprt->xpt_net != net) | |
863 | continue; | |
864 | + ret++; | |
865 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | |
866 | - set_bit(XPT_BUSY, &xprt->xpt_flags); | |
867 | + svc_xprt_enqueue(xprt); | |
868 | } | |
869 | spin_unlock(&serv->sv_lock); | |
870 | + return ret; | |
871 | } | |
872 | ||
873 | -static void svc_clear_pools(struct svc_serv *serv, struct net *net) | |
874 | +static struct svc_xprt *svc_dequeue_net(struct svc_serv *serv, struct net *net) | |
875 | { | |
876 | struct svc_pool *pool; | |
877 | struct svc_xprt *xprt; | |
878 | @@ -977,42 +980,46 @@ static void svc_clear_pools(struct svc_s | |
879 | if (xprt->xpt_net != net) | |
880 | continue; | |
881 | list_del_init(&xprt->xpt_ready); | |
882 | + spin_unlock_bh(&pool->sp_lock); | |
883 | + return xprt; | |
884 | } | |
885 | spin_unlock_bh(&pool->sp_lock); | |
886 | } | |
887 | + return NULL; | |
888 | } | |
889 | ||
890 | -static void svc_clear_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) | |
891 | +static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net) | |
892 | { | |
893 | struct svc_xprt *xprt; | |
894 | - struct svc_xprt *tmp; | |
895 | - LIST_HEAD(victims); | |
896 | - | |
897 | - spin_lock(&serv->sv_lock); | |
898 | - list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { | |
899 | - if (xprt->xpt_net != net) | |
900 | - continue; | |
901 | - list_move(&xprt->xpt_list, &victims); | |
902 | - } | |
903 | - spin_unlock(&serv->sv_lock); | |
904 | ||
905 | - list_for_each_entry_safe(xprt, tmp, &victims, xpt_list) | |
906 | + while ((xprt = svc_dequeue_net(serv, net))) { | |
907 | + set_bit(XPT_CLOSE, &xprt->xpt_flags); | |
908 | svc_delete_xprt(xprt); | |
909 | + } | |
910 | } | |
911 | ||
912 | +/* | |
913 | + * Server threads may still be running (especially in the case where the | |
914 | + * service is still running in other network namespaces). | |
915 | + * | |
916 | + * So we shut down sockets the same way we would on a running server, by | |
917 | + * setting XPT_CLOSE, enqueuing, and letting a thread pick it up to do | |
918 | + * the close. In the case there are no such other threads, | |
919 | + * threads running, svc_clean_up_xprts() does a simple version of a | |
920 | + * server's main event loop, and in the case where there are other | |
921 | + * threads, we may need to wait a little while and then check again to | |
922 | + * see if they're done. | |
923 | + */ | |
924 | void svc_close_net(struct svc_serv *serv, struct net *net) | |
925 | { | |
926 | - svc_close_list(serv, &serv->sv_tempsocks, net); | |
927 | - svc_close_list(serv, &serv->sv_permsocks, net); | |
928 | + int delay = 0; | |
929 | + | |
930 | + while (svc_close_list(serv, &serv->sv_permsocks, net) + | |
931 | + svc_close_list(serv, &serv->sv_tempsocks, net)) { | |
932 | ||
933 | - svc_clear_pools(serv, net); | |
934 | - /* | |
935 | - * At this point the sp_sockets lists will stay empty, since | |
936 | - * svc_xprt_enqueue will not add new entries without taking the | |
937 | - * sp_lock and checking XPT_BUSY. | |
938 | - */ | |
939 | - svc_clear_list(serv, &serv->sv_tempsocks, net); | |
940 | - svc_clear_list(serv, &serv->sv_permsocks, net); | |
941 | + svc_clean_up_xprts(serv, net); | |
942 | + msleep(delay++); | |
943 | + } | |
944 | } | |
945 | ||
946 | /* |