diff options
Diffstat (limited to 'drivers')
27 files changed, 374 insertions, 251 deletions
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 973be2f44195..4e28b35024ec 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c | |||
@@ -300,8 +300,7 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space) | |||
300 | if (space < 2) | 300 | if (space < 2) |
301 | return -1; | 301 | return -1; |
302 | tty->canon_column = tty->column = 0; | 302 | tty->canon_column = tty->column = 0; |
303 | tty_put_char(tty, '\r'); | 303 | tty->ops->write(tty, "\r\n", 2); |
304 | tty_put_char(tty, c); | ||
305 | return 2; | 304 | return 2; |
306 | } | 305 | } |
307 | tty->canon_column = tty->column; | 306 | tty->canon_column = tty->column; |
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index d083c73d784a..b33d6688e910 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -109,21 +109,13 @@ static int pty_space(struct tty_struct *to) | |||
109 | * the other side of the pty/tty pair. | 109 | * the other side of the pty/tty pair. |
110 | */ | 110 | */ |
111 | 111 | ||
112 | static int pty_write(struct tty_struct *tty, const unsigned char *buf, | 112 | static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) |
113 | int count) | ||
114 | { | 113 | { |
115 | struct tty_struct *to = tty->link; | 114 | struct tty_struct *to = tty->link; |
116 | int c; | ||
117 | 115 | ||
118 | if (tty->stopped) | 116 | if (tty->stopped) |
119 | return 0; | 117 | return 0; |
120 | 118 | ||
121 | /* This isn't locked but our 8K is quite sloppy so no | ||
122 | big deal */ | ||
123 | |||
124 | c = pty_space(to); | ||
125 | if (c > count) | ||
126 | c = count; | ||
127 | if (c > 0) { | 119 | if (c > 0) { |
128 | /* Stuff the data into the input queue of the other end */ | 120 | /* Stuff the data into the input queue of the other end */ |
129 | c = tty_insert_flip_string(to, buf, c); | 121 | c = tty_insert_flip_string(to, buf, c); |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index fd69086d08d5..2968ed6a9c49 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -1250,20 +1250,11 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) | |||
1250 | { | 1250 | { |
1251 | int ret = 0; | 1251 | int ret = 0; |
1252 | 1252 | ||
1253 | #ifdef __powerpc__ | ||
1254 | int cpu = sysdev->id; | 1253 | int cpu = sysdev->id; |
1255 | unsigned int cur_freq = 0; | ||
1256 | struct cpufreq_policy *cpu_policy; | 1254 | struct cpufreq_policy *cpu_policy; |
1257 | 1255 | ||
1258 | dprintk("suspending cpu %u\n", cpu); | 1256 | dprintk("suspending cpu %u\n", cpu); |
1259 | 1257 | ||
1260 | /* | ||
1261 | * This whole bogosity is here because Powerbooks are made of fail. | ||
1262 | * No sane platform should need any of the code below to be run. | ||
1263 | * (it's entirely the wrong thing to do, as driver->get may | ||
1264 | * reenable interrupts on some architectures). | ||
1265 | */ | ||
1266 | |||
1267 | if (!cpu_online(cpu)) | 1258 | if (!cpu_online(cpu)) |
1268 | return 0; | 1259 | return 0; |
1269 | 1260 | ||
@@ -1282,47 +1273,13 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) | |||
1282 | 1273 | ||
1283 | if (cpufreq_driver->suspend) { | 1274 | if (cpufreq_driver->suspend) { |
1284 | ret = cpufreq_driver->suspend(cpu_policy, pmsg); | 1275 | ret = cpufreq_driver->suspend(cpu_policy, pmsg); |
1285 | if (ret) { | 1276 | if (ret) |
1286 | printk(KERN_ERR "cpufreq: suspend failed in ->suspend " | 1277 | printk(KERN_ERR "cpufreq: suspend failed in ->suspend " |
1287 | "step on CPU %u\n", cpu_policy->cpu); | 1278 | "step on CPU %u\n", cpu_policy->cpu); |
1288 | goto out; | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) | ||
1293 | goto out; | ||
1294 | |||
1295 | if (cpufreq_driver->get) | ||
1296 | cur_freq = cpufreq_driver->get(cpu_policy->cpu); | ||
1297 | |||
1298 | if (!cur_freq || !cpu_policy->cur) { | ||
1299 | printk(KERN_ERR "cpufreq: suspend failed to assert current " | ||
1300 | "frequency is what timing core thinks it is.\n"); | ||
1301 | goto out; | ||
1302 | } | ||
1303 | |||
1304 | if (unlikely(cur_freq != cpu_policy->cur)) { | ||
1305 | struct cpufreq_freqs freqs; | ||
1306 | |||
1307 | if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) | ||
1308 | dprintk("Warning: CPU frequency is %u, " | ||
1309 | "cpufreq assumed %u kHz.\n", | ||
1310 | cur_freq, cpu_policy->cur); | ||
1311 | |||
1312 | freqs.cpu = cpu; | ||
1313 | freqs.old = cpu_policy->cur; | ||
1314 | freqs.new = cur_freq; | ||
1315 | |||
1316 | srcu_notifier_call_chain(&cpufreq_transition_notifier_list, | ||
1317 | CPUFREQ_SUSPENDCHANGE, &freqs); | ||
1318 | adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); | ||
1319 | |||
1320 | cpu_policy->cur = cur_freq; | ||
1321 | } | 1279 | } |
1322 | 1280 | ||
1323 | out: | 1281 | out: |
1324 | cpufreq_cpu_put(cpu_policy); | 1282 | cpufreq_cpu_put(cpu_policy); |
1325 | #endif /* __powerpc__ */ | ||
1326 | return ret; | 1283 | return ret; |
1327 | } | 1284 | } |
1328 | 1285 | ||
@@ -1330,24 +1287,21 @@ out: | |||
1330 | * cpufreq_resume - restore proper CPU frequency handling after resume | 1287 | * cpufreq_resume - restore proper CPU frequency handling after resume |
1331 | * | 1288 | * |
1332 | * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) | 1289 | * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) |
1333 | * 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync | 1290 | * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are |
1334 | * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are | 1291 | * restored. It will verify that the current freq is in sync with |
1335 | * restored. | 1292 | * what we believe it to be. This is a bit later than when it |
1293 | * should be, but nonethteless it's better than calling | ||
1294 | * cpufreq_driver->get() here which might re-enable interrupts... | ||
1336 | */ | 1295 | */ |
1337 | static int cpufreq_resume(struct sys_device *sysdev) | 1296 | static int cpufreq_resume(struct sys_device *sysdev) |
1338 | { | 1297 | { |
1339 | int ret = 0; | 1298 | int ret = 0; |
1340 | 1299 | ||
1341 | #ifdef __powerpc__ | ||
1342 | int cpu = sysdev->id; | 1300 | int cpu = sysdev->id; |
1343 | struct cpufreq_policy *cpu_policy; | 1301 | struct cpufreq_policy *cpu_policy; |
1344 | 1302 | ||
1345 | dprintk("resuming cpu %u\n", cpu); | 1303 | dprintk("resuming cpu %u\n", cpu); |
1346 | 1304 | ||
1347 | /* As with the ->suspend method, all the code below is | ||
1348 | * only necessary because Powerbooks suck. | ||
1349 | * See commit 42d4dc3f4e1e for jokes. */ | ||
1350 | |||
1351 | if (!cpu_online(cpu)) | 1305 | if (!cpu_online(cpu)) |
1352 | return 0; | 1306 | return 0; |
1353 | 1307 | ||
@@ -1373,45 +1327,10 @@ static int cpufreq_resume(struct sys_device *sysdev) | |||
1373 | } | 1327 | } |
1374 | } | 1328 | } |
1375 | 1329 | ||
1376 | if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { | ||
1377 | unsigned int cur_freq = 0; | ||
1378 | |||
1379 | if (cpufreq_driver->get) | ||
1380 | cur_freq = cpufreq_driver->get(cpu_policy->cpu); | ||
1381 | |||
1382 | if (!cur_freq || !cpu_policy->cur) { | ||
1383 | printk(KERN_ERR "cpufreq: resume failed to assert " | ||
1384 | "current frequency is what timing core " | ||
1385 | "thinks it is.\n"); | ||
1386 | goto out; | ||
1387 | } | ||
1388 | |||
1389 | if (unlikely(cur_freq != cpu_policy->cur)) { | ||
1390 | struct cpufreq_freqs freqs; | ||
1391 | |||
1392 | if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) | ||
1393 | dprintk("Warning: CPU frequency " | ||
1394 | "is %u, cpufreq assumed %u kHz.\n", | ||
1395 | cur_freq, cpu_policy->cur); | ||
1396 | |||
1397 | freqs.cpu = cpu; | ||
1398 | freqs.old = cpu_policy->cur; | ||
1399 | freqs.new = cur_freq; | ||
1400 | |||
1401 | srcu_notifier_call_chain( | ||
1402 | &cpufreq_transition_notifier_list, | ||
1403 | CPUFREQ_RESUMECHANGE, &freqs); | ||
1404 | adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); | ||
1405 | |||
1406 | cpu_policy->cur = cur_freq; | ||
1407 | } | ||
1408 | } | ||
1409 | |||
1410 | out: | ||
1411 | schedule_work(&cpu_policy->update); | 1330 | schedule_work(&cpu_policy->update); |
1331 | |||
1412 | fail: | 1332 | fail: |
1413 | cpufreq_cpu_put(cpu_policy); | 1333 | cpufreq_cpu_put(cpu_policy); |
1414 | #endif /* __powerpc__ */ | ||
1415 | return ret; | 1334 | return ret; |
1416 | } | 1335 | } |
1417 | 1336 | ||
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 110e731f5574..1c0b504a42f3 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c | |||
@@ -196,7 +196,7 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, | |||
196 | switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, | 196 | switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, |
197 | irm_id, generation, SCODE_100, | 197 | irm_id, generation, SCODE_100, |
198 | CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE, | 198 | CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE, |
199 | data, sizeof(data))) { | 199 | data, 8)) { |
200 | case RCODE_GENERATION: | 200 | case RCODE_GENERATION: |
201 | /* A generation change frees all bandwidth. */ | 201 | /* A generation change frees all bandwidth. */ |
202 | return allocate ? -EAGAIN : bandwidth; | 202 | return allocate ? -EAGAIN : bandwidth; |
@@ -233,7 +233,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation, | |||
233 | data[1] = old ^ c; | 233 | data[1] = old ^ c; |
234 | switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, | 234 | switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, |
235 | irm_id, generation, SCODE_100, | 235 | irm_id, generation, SCODE_100, |
236 | offset, data, sizeof(data))) { | 236 | offset, data, 8)) { |
237 | case RCODE_GENERATION: | 237 | case RCODE_GENERATION: |
238 | /* A generation change frees all channels. */ | 238 | /* A generation change frees all channels. */ |
239 | return allocate ? -EAGAIN : i; | 239 | return allocate ? -EAGAIN : i; |
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index ecddd11b797a..76b321bb73f9 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/moduleparam.h> | 35 | #include <linux/moduleparam.h> |
36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
37 | #include <linux/pci_ids.h> | ||
37 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
38 | #include <linux/string.h> | 39 | #include <linux/string.h> |
39 | 40 | ||
@@ -2372,6 +2373,9 @@ static void ohci_pmac_off(struct pci_dev *dev) | |||
2372 | #define ohci_pmac_off(dev) | 2373 | #define ohci_pmac_off(dev) |
2373 | #endif /* CONFIG_PPC_PMAC */ | 2374 | #endif /* CONFIG_PPC_PMAC */ |
2374 | 2375 | ||
2376 | #define PCI_VENDOR_ID_AGERE PCI_VENDOR_ID_ATT | ||
2377 | #define PCI_DEVICE_ID_AGERE_FW643 0x5901 | ||
2378 | |||
2375 | static int __devinit pci_probe(struct pci_dev *dev, | 2379 | static int __devinit pci_probe(struct pci_dev *dev, |
2376 | const struct pci_device_id *ent) | 2380 | const struct pci_device_id *ent) |
2377 | { | 2381 | { |
@@ -2422,6 +2426,16 @@ static int __devinit pci_probe(struct pci_dev *dev, | |||
2422 | version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; | 2426 | version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; |
2423 | ohci->use_dualbuffer = version >= OHCI_VERSION_1_1; | 2427 | ohci->use_dualbuffer = version >= OHCI_VERSION_1_1; |
2424 | 2428 | ||
2429 | /* dual-buffer mode is broken if more than one IR context is active */ | ||
2430 | if (dev->vendor == PCI_VENDOR_ID_AGERE && | ||
2431 | dev->device == PCI_DEVICE_ID_AGERE_FW643) | ||
2432 | ohci->use_dualbuffer = false; | ||
2433 | |||
2434 | /* dual-buffer mode is broken */ | ||
2435 | if (dev->vendor == PCI_VENDOR_ID_RICOH && | ||
2436 | dev->device == PCI_DEVICE_ID_RICOH_R5C832) | ||
2437 | ohci->use_dualbuffer = false; | ||
2438 | |||
2425 | /* x86-32 currently doesn't use highmem for dma_alloc_coherent */ | 2439 | /* x86-32 currently doesn't use highmem for dma_alloc_coherent */ |
2426 | #if !defined(CONFIG_X86_32) | 2440 | #if !defined(CONFIG_X86_32) |
2427 | /* dual-buffer mode is broken with descriptor addresses above 2G */ | 2441 | /* dual-buffer mode is broken with descriptor addresses above 2G */ |
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 8d51568ee143..e5df822a8130 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c | |||
@@ -456,12 +456,12 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request, | |||
456 | } | 456 | } |
457 | spin_unlock_irqrestore(&card->lock, flags); | 457 | spin_unlock_irqrestore(&card->lock, flags); |
458 | 458 | ||
459 | if (&orb->link != &lu->orb_list) | 459 | if (&orb->link != &lu->orb_list) { |
460 | orb->callback(orb, &status); | 460 | orb->callback(orb, &status); |
461 | else | 461 | kref_put(&orb->kref, free_orb); |
462 | } else { | ||
462 | fw_error("status write for unknown orb\n"); | 463 | fw_error("status write for unknown orb\n"); |
463 | 464 | } | |
464 | kref_put(&orb->kref, free_orb); | ||
465 | 465 | ||
466 | fw_send_response(card, request, RCODE_COMPLETE); | 466 | fw_send_response(card, request, RCODE_COMPLETE); |
467 | } | 467 | } |
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 95fe0452dae4..6c6a09b1c0fe 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -880,6 +880,14 @@ static unsigned int atkbd_hp_zv6100_forced_release_keys[] = { | |||
880 | }; | 880 | }; |
881 | 881 | ||
882 | /* | 882 | /* |
883 | * Perform fixup for HP (Compaq) Presario R4000 R4100 R4200 that don't generate | ||
884 | * release for their volume buttons | ||
885 | */ | ||
886 | static unsigned int atkbd_hp_r4000_forced_release_keys[] = { | ||
887 | 0xae, 0xb0, -1U | ||
888 | }; | ||
889 | |||
890 | /* | ||
883 | * Samsung NC10,NC20 with Fn+F? key release not working | 891 | * Samsung NC10,NC20 with Fn+F? key release not working |
884 | */ | 892 | */ |
885 | static unsigned int atkbd_samsung_forced_release_keys[] = { | 893 | static unsigned int atkbd_samsung_forced_release_keys[] = { |
@@ -1537,6 +1545,33 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1537 | .driver_data = atkbd_hp_zv6100_forced_release_keys, | 1545 | .driver_data = atkbd_hp_zv6100_forced_release_keys, |
1538 | }, | 1546 | }, |
1539 | { | 1547 | { |
1548 | .ident = "HP Presario R4000", | ||
1549 | .matches = { | ||
1550 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
1551 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), | ||
1552 | }, | ||
1553 | .callback = atkbd_setup_forced_release, | ||
1554 | .driver_data = atkbd_hp_r4000_forced_release_keys, | ||
1555 | }, | ||
1556 | { | ||
1557 | .ident = "HP Presario R4100", | ||
1558 | .matches = { | ||
1559 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
1560 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), | ||
1561 | }, | ||
1562 | .callback = atkbd_setup_forced_release, | ||
1563 | .driver_data = atkbd_hp_r4000_forced_release_keys, | ||
1564 | }, | ||
1565 | { | ||
1566 | .ident = "HP Presario R4200", | ||
1567 | .matches = { | ||
1568 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
1569 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), | ||
1570 | }, | ||
1571 | .callback = atkbd_setup_forced_release, | ||
1572 | .driver_data = atkbd_hp_r4000_forced_release_keys, | ||
1573 | }, | ||
1574 | { | ||
1540 | .ident = "Inventec Symphony", | 1575 | .ident = "Inventec Symphony", |
1541 | .matches = { | 1576 | .matches = { |
1542 | DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), | 1577 | DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), |
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index ae04d8a494e5..ccbf23ece8e3 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
@@ -382,6 +382,14 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { | |||
382 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), | 382 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), |
383 | }, | 383 | }, |
384 | }, | 384 | }, |
385 | { | ||
386 | .ident = "Acer Aspire 5536", | ||
387 | .matches = { | ||
388 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
389 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), | ||
390 | DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), | ||
391 | }, | ||
392 | }, | ||
385 | { } | 393 | { } |
386 | }; | 394 | }; |
387 | 395 | ||
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index 3710ff88fc10..556acff3952f 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
@@ -171,6 +171,14 @@ static int set_chunk_size(struct dm_exception_store *store, | |||
171 | */ | 171 | */ |
172 | chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9); | 172 | chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9); |
173 | 173 | ||
174 | return dm_exception_store_set_chunk_size(store, chunk_size_ulong, | ||
175 | error); | ||
176 | } | ||
177 | |||
178 | int dm_exception_store_set_chunk_size(struct dm_exception_store *store, | ||
179 | unsigned long chunk_size_ulong, | ||
180 | char **error) | ||
181 | { | ||
174 | /* Check chunk_size is a power of 2 */ | 182 | /* Check chunk_size is a power of 2 */ |
175 | if (!is_power_of_2(chunk_size_ulong)) { | 183 | if (!is_power_of_2(chunk_size_ulong)) { |
176 | *error = "Chunk size is not a power of 2"; | 184 | *error = "Chunk size is not a power of 2"; |
@@ -183,6 +191,11 @@ static int set_chunk_size(struct dm_exception_store *store, | |||
183 | return -EINVAL; | 191 | return -EINVAL; |
184 | } | 192 | } |
185 | 193 | ||
194 | if (chunk_size_ulong > INT_MAX >> SECTOR_SHIFT) { | ||
195 | *error = "Chunk size is too high"; | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
186 | store->chunk_size = chunk_size_ulong; | 199 | store->chunk_size = chunk_size_ulong; |
187 | store->chunk_mask = chunk_size_ulong - 1; | 200 | store->chunk_mask = chunk_size_ulong - 1; |
188 | store->chunk_shift = ffs(chunk_size_ulong) - 1; | 201 | store->chunk_shift = ffs(chunk_size_ulong) - 1; |
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index 2442c8c07898..812c71872ba0 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h | |||
@@ -168,6 +168,10 @@ static inline chunk_t sector_to_chunk(struct dm_exception_store *store, | |||
168 | int dm_exception_store_type_register(struct dm_exception_store_type *type); | 168 | int dm_exception_store_type_register(struct dm_exception_store_type *type); |
169 | int dm_exception_store_type_unregister(struct dm_exception_store_type *type); | 169 | int dm_exception_store_type_unregister(struct dm_exception_store_type *type); |
170 | 170 | ||
171 | int dm_exception_store_set_chunk_size(struct dm_exception_store *store, | ||
172 | unsigned long chunk_size_ulong, | ||
173 | char **error); | ||
174 | |||
171 | int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, | 175 | int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, |
172 | unsigned *args_used, | 176 | unsigned *args_used, |
173 | struct dm_exception_store **store); | 177 | struct dm_exception_store **store); |
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index e69b96560997..6e186b1a062d 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c | |||
@@ -21,6 +21,7 @@ struct log_c { | |||
21 | struct dm_target *ti; | 21 | struct dm_target *ti; |
22 | uint32_t region_size; | 22 | uint32_t region_size; |
23 | region_t region_count; | 23 | region_t region_count; |
24 | uint64_t luid; | ||
24 | char uuid[DM_UUID_LEN]; | 25 | char uuid[DM_UUID_LEN]; |
25 | 26 | ||
26 | char *usr_argv_str; | 27 | char *usr_argv_str; |
@@ -63,7 +64,7 @@ static int userspace_do_request(struct log_c *lc, const char *uuid, | |||
63 | * restored. | 64 | * restored. |
64 | */ | 65 | */ |
65 | retry: | 66 | retry: |
66 | r = dm_consult_userspace(uuid, request_type, data, | 67 | r = dm_consult_userspace(uuid, lc->luid, request_type, data, |
67 | data_size, rdata, rdata_size); | 68 | data_size, rdata, rdata_size); |
68 | 69 | ||
69 | if (r != -ESRCH) | 70 | if (r != -ESRCH) |
@@ -74,14 +75,15 @@ retry: | |||
74 | set_current_state(TASK_INTERRUPTIBLE); | 75 | set_current_state(TASK_INTERRUPTIBLE); |
75 | schedule_timeout(2*HZ); | 76 | schedule_timeout(2*HZ); |
76 | DMWARN("Attempting to contact userspace log server..."); | 77 | DMWARN("Attempting to contact userspace log server..."); |
77 | r = dm_consult_userspace(uuid, DM_ULOG_CTR, lc->usr_argv_str, | 78 | r = dm_consult_userspace(uuid, lc->luid, DM_ULOG_CTR, |
79 | lc->usr_argv_str, | ||
78 | strlen(lc->usr_argv_str) + 1, | 80 | strlen(lc->usr_argv_str) + 1, |
79 | NULL, NULL); | 81 | NULL, NULL); |
80 | if (!r) | 82 | if (!r) |
81 | break; | 83 | break; |
82 | } | 84 | } |
83 | DMINFO("Reconnected to userspace log server... DM_ULOG_CTR complete"); | 85 | DMINFO("Reconnected to userspace log server... DM_ULOG_CTR complete"); |
84 | r = dm_consult_userspace(uuid, DM_ULOG_RESUME, NULL, | 86 | r = dm_consult_userspace(uuid, lc->luid, DM_ULOG_RESUME, NULL, |
85 | 0, NULL, NULL); | 87 | 0, NULL, NULL); |
86 | if (!r) | 88 | if (!r) |
87 | goto retry; | 89 | goto retry; |
@@ -111,10 +113,9 @@ static int build_constructor_string(struct dm_target *ti, | |||
111 | return -ENOMEM; | 113 | return -ENOMEM; |
112 | } | 114 | } |
113 | 115 | ||
114 | for (i = 0, str_size = 0; i < argc; i++) | 116 | str_size = sprintf(str, "%llu", (unsigned long long)ti->len); |
115 | str_size += sprintf(str + str_size, "%s ", argv[i]); | 117 | for (i = 0; i < argc; i++) |
116 | str_size += sprintf(str + str_size, "%llu", | 118 | str_size += sprintf(str + str_size, " %s", argv[i]); |
117 | (unsigned long long)ti->len); | ||
118 | 119 | ||
119 | *ctr_str = str; | 120 | *ctr_str = str; |
120 | return str_size; | 121 | return str_size; |
@@ -154,6 +155,9 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, | |||
154 | return -ENOMEM; | 155 | return -ENOMEM; |
155 | } | 156 | } |
156 | 157 | ||
158 | /* The ptr value is sufficient for local unique id */ | ||
159 | lc->luid = (uint64_t)lc; | ||
160 | |||
157 | lc->ti = ti; | 161 | lc->ti = ti; |
158 | 162 | ||
159 | if (strlen(argv[0]) > (DM_UUID_LEN - 1)) { | 163 | if (strlen(argv[0]) > (DM_UUID_LEN - 1)) { |
@@ -173,7 +177,7 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, | |||
173 | } | 177 | } |
174 | 178 | ||
175 | /* Send table string */ | 179 | /* Send table string */ |
176 | r = dm_consult_userspace(lc->uuid, DM_ULOG_CTR, | 180 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR, |
177 | ctr_str, str_size, NULL, NULL); | 181 | ctr_str, str_size, NULL, NULL); |
178 | 182 | ||
179 | if (r == -ESRCH) { | 183 | if (r == -ESRCH) { |
@@ -183,7 +187,7 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, | |||
183 | 187 | ||
184 | /* Since the region size does not change, get it now */ | 188 | /* Since the region size does not change, get it now */ |
185 | rdata_size = sizeof(rdata); | 189 | rdata_size = sizeof(rdata); |
186 | r = dm_consult_userspace(lc->uuid, DM_ULOG_GET_REGION_SIZE, | 190 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_GET_REGION_SIZE, |
187 | NULL, 0, (char *)&rdata, &rdata_size); | 191 | NULL, 0, (char *)&rdata, &rdata_size); |
188 | 192 | ||
189 | if (r) { | 193 | if (r) { |
@@ -212,7 +216,7 @@ static void userspace_dtr(struct dm_dirty_log *log) | |||
212 | int r; | 216 | int r; |
213 | struct log_c *lc = log->context; | 217 | struct log_c *lc = log->context; |
214 | 218 | ||
215 | r = dm_consult_userspace(lc->uuid, DM_ULOG_DTR, | 219 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR, |
216 | NULL, 0, | 220 | NULL, 0, |
217 | NULL, NULL); | 221 | NULL, NULL); |
218 | 222 | ||
@@ -227,7 +231,7 @@ static int userspace_presuspend(struct dm_dirty_log *log) | |||
227 | int r; | 231 | int r; |
228 | struct log_c *lc = log->context; | 232 | struct log_c *lc = log->context; |
229 | 233 | ||
230 | r = dm_consult_userspace(lc->uuid, DM_ULOG_PRESUSPEND, | 234 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_PRESUSPEND, |
231 | NULL, 0, | 235 | NULL, 0, |
232 | NULL, NULL); | 236 | NULL, NULL); |
233 | 237 | ||
@@ -239,7 +243,7 @@ static int userspace_postsuspend(struct dm_dirty_log *log) | |||
239 | int r; | 243 | int r; |
240 | struct log_c *lc = log->context; | 244 | struct log_c *lc = log->context; |
241 | 245 | ||
242 | r = dm_consult_userspace(lc->uuid, DM_ULOG_POSTSUSPEND, | 246 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_POSTSUSPEND, |
243 | NULL, 0, | 247 | NULL, 0, |
244 | NULL, NULL); | 248 | NULL, NULL); |
245 | 249 | ||
@@ -252,7 +256,7 @@ static int userspace_resume(struct dm_dirty_log *log) | |||
252 | struct log_c *lc = log->context; | 256 | struct log_c *lc = log->context; |
253 | 257 | ||
254 | lc->in_sync_hint = 0; | 258 | lc->in_sync_hint = 0; |
255 | r = dm_consult_userspace(lc->uuid, DM_ULOG_RESUME, | 259 | r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_RESUME, |
256 | NULL, 0, | 260 | NULL, 0, |
257 | NULL, NULL); | 261 | NULL, NULL); |
258 | 262 | ||
@@ -561,6 +565,7 @@ static int userspace_status(struct dm_dirty_log *log, status_type_t status_type, | |||
561 | char *result, unsigned maxlen) | 565 | char *result, unsigned maxlen) |
562 | { | 566 | { |
563 | int r = 0; | 567 | int r = 0; |
568 | char *table_args; | ||
564 | size_t sz = (size_t)maxlen; | 569 | size_t sz = (size_t)maxlen; |
565 | struct log_c *lc = log->context; | 570 | struct log_c *lc = log->context; |
566 | 571 | ||
@@ -577,8 +582,12 @@ static int userspace_status(struct dm_dirty_log *log, status_type_t status_type, | |||
577 | break; | 582 | break; |
578 | case STATUSTYPE_TABLE: | 583 | case STATUSTYPE_TABLE: |
579 | sz = 0; | 584 | sz = 0; |
580 | DMEMIT("%s %u %s %s", log->type->name, lc->usr_argc + 1, | 585 | table_args = strstr(lc->usr_argv_str, " "); |
581 | lc->uuid, lc->usr_argv_str); | 586 | BUG_ON(!table_args); /* There will always be a ' ' */ |
587 | table_args++; | ||
588 | |||
589 | DMEMIT("%s %u %s %s ", log->type->name, lc->usr_argc, | ||
590 | lc->uuid, table_args); | ||
582 | break; | 591 | break; |
583 | } | 592 | } |
584 | return (r) ? 0 : (int)sz; | 593 | return (r) ? 0 : (int)sz; |
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c index 8ce74d95ae4d..ba0edad2d048 100644 --- a/drivers/md/dm-log-userspace-transfer.c +++ b/drivers/md/dm-log-userspace-transfer.c | |||
@@ -147,7 +147,8 @@ static void cn_ulog_callback(void *data) | |||
147 | 147 | ||
148 | /** | 148 | /** |
149 | * dm_consult_userspace | 149 | * dm_consult_userspace |
150 | * @uuid: log's uuid (must be DM_UUID_LEN in size) | 150 | * @uuid: log's universal unique identifier (must be DM_UUID_LEN in size) |
151 | * @luid: log's local unique identifier | ||
151 | * @request_type: found in include/linux/dm-log-userspace.h | 152 | * @request_type: found in include/linux/dm-log-userspace.h |
152 | * @data: data to tx to the server | 153 | * @data: data to tx to the server |
153 | * @data_size: size of data in bytes | 154 | * @data_size: size of data in bytes |
@@ -163,7 +164,7 @@ static void cn_ulog_callback(void *data) | |||
163 | * | 164 | * |
164 | * Returns: 0 on success, -EXXX on failure | 165 | * Returns: 0 on success, -EXXX on failure |
165 | **/ | 166 | **/ |
166 | int dm_consult_userspace(const char *uuid, int request_type, | 167 | int dm_consult_userspace(const char *uuid, uint64_t luid, int request_type, |
167 | char *data, size_t data_size, | 168 | char *data, size_t data_size, |
168 | char *rdata, size_t *rdata_size) | 169 | char *rdata, size_t *rdata_size) |
169 | { | 170 | { |
@@ -190,6 +191,7 @@ resend: | |||
190 | 191 | ||
191 | memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - overhead_size); | 192 | memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - overhead_size); |
192 | memcpy(tfr->uuid, uuid, DM_UUID_LEN); | 193 | memcpy(tfr->uuid, uuid, DM_UUID_LEN); |
194 | tfr->luid = luid; | ||
193 | tfr->seq = dm_ulog_seq++; | 195 | tfr->seq = dm_ulog_seq++; |
194 | 196 | ||
195 | /* | 197 | /* |
diff --git a/drivers/md/dm-log-userspace-transfer.h b/drivers/md/dm-log-userspace-transfer.h index c26d8e4e2710..04ee874f9153 100644 --- a/drivers/md/dm-log-userspace-transfer.h +++ b/drivers/md/dm-log-userspace-transfer.h | |||
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | int dm_ulog_tfr_init(void); | 12 | int dm_ulog_tfr_init(void); |
13 | void dm_ulog_tfr_exit(void); | 13 | void dm_ulog_tfr_exit(void); |
14 | int dm_consult_userspace(const char *uuid, int request_type, | 14 | int dm_consult_userspace(const char *uuid, uint64_t luid, int request_type, |
15 | char *data, size_t data_size, | 15 | char *data, size_t data_size, |
16 | char *rdata, size_t *rdata_size); | 16 | char *rdata, size_t *rdata_size); |
17 | 17 | ||
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 9726577cde49..33f179e66bf5 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -648,7 +648,13 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) | |||
648 | */ | 648 | */ |
649 | dm_rh_inc_pending(ms->rh, &sync); | 649 | dm_rh_inc_pending(ms->rh, &sync); |
650 | dm_rh_inc_pending(ms->rh, &nosync); | 650 | dm_rh_inc_pending(ms->rh, &nosync); |
651 | ms->log_failure = dm_rh_flush(ms->rh) ? 1 : 0; | 651 | |
652 | /* | ||
653 | * If the flush fails on a previous call and succeeds here, | ||
654 | * we must not reset the log_failure variable. We need | ||
655 | * userspace interaction to do that. | ||
656 | */ | ||
657 | ms->log_failure = dm_rh_flush(ms->rh) ? 1 : ms->log_failure; | ||
652 | 658 | ||
653 | /* | 659 | /* |
654 | * Dispatch io. | 660 | * Dispatch io. |
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 6e3fe4f14934..d5b2e08750d5 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c | |||
@@ -106,6 +106,13 @@ struct pstore { | |||
106 | void *zero_area; | 106 | void *zero_area; |
107 | 107 | ||
108 | /* | 108 | /* |
109 | * An area used for header. The header can be written | ||
110 | * concurrently with metadata (when invalidating the snapshot), | ||
111 | * so it needs a separate buffer. | ||
112 | */ | ||
113 | void *header_area; | ||
114 | |||
115 | /* | ||
109 | * Used to keep track of which metadata area the data in | 116 | * Used to keep track of which metadata area the data in |
110 | * 'chunk' refers to. | 117 | * 'chunk' refers to. |
111 | */ | 118 | */ |
@@ -148,16 +155,27 @@ static int alloc_area(struct pstore *ps) | |||
148 | */ | 155 | */ |
149 | ps->area = vmalloc(len); | 156 | ps->area = vmalloc(len); |
150 | if (!ps->area) | 157 | if (!ps->area) |
151 | return r; | 158 | goto err_area; |
152 | 159 | ||
153 | ps->zero_area = vmalloc(len); | 160 | ps->zero_area = vmalloc(len); |
154 | if (!ps->zero_area) { | 161 | if (!ps->zero_area) |
155 | vfree(ps->area); | 162 | goto err_zero_area; |
156 | return r; | ||
157 | } | ||
158 | memset(ps->zero_area, 0, len); | 163 | memset(ps->zero_area, 0, len); |
159 | 164 | ||
165 | ps->header_area = vmalloc(len); | ||
166 | if (!ps->header_area) | ||
167 | goto err_header_area; | ||
168 | |||
160 | return 0; | 169 | return 0; |
170 | |||
171 | err_header_area: | ||
172 | vfree(ps->zero_area); | ||
173 | |||
174 | err_zero_area: | ||
175 | vfree(ps->area); | ||
176 | |||
177 | err_area: | ||
178 | return r; | ||
161 | } | 179 | } |
162 | 180 | ||
163 | static void free_area(struct pstore *ps) | 181 | static void free_area(struct pstore *ps) |
@@ -169,6 +187,10 @@ static void free_area(struct pstore *ps) | |||
169 | if (ps->zero_area) | 187 | if (ps->zero_area) |
170 | vfree(ps->zero_area); | 188 | vfree(ps->zero_area); |
171 | ps->zero_area = NULL; | 189 | ps->zero_area = NULL; |
190 | |||
191 | if (ps->header_area) | ||
192 | vfree(ps->header_area); | ||
193 | ps->header_area = NULL; | ||
172 | } | 194 | } |
173 | 195 | ||
174 | struct mdata_req { | 196 | struct mdata_req { |
@@ -188,7 +210,8 @@ static void do_metadata(struct work_struct *work) | |||
188 | /* | 210 | /* |
189 | * Read or write a chunk aligned and sized block of data from a device. | 211 | * Read or write a chunk aligned and sized block of data from a device. |
190 | */ | 212 | */ |
191 | static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata) | 213 | static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw, |
214 | int metadata) | ||
192 | { | 215 | { |
193 | struct dm_io_region where = { | 216 | struct dm_io_region where = { |
194 | .bdev = ps->store->cow->bdev, | 217 | .bdev = ps->store->cow->bdev, |
@@ -198,7 +221,7 @@ static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata) | |||
198 | struct dm_io_request io_req = { | 221 | struct dm_io_request io_req = { |
199 | .bi_rw = rw, | 222 | .bi_rw = rw, |
200 | .mem.type = DM_IO_VMA, | 223 | .mem.type = DM_IO_VMA, |
201 | .mem.ptr.vma = ps->area, | 224 | .mem.ptr.vma = area, |
202 | .client = ps->io_client, | 225 | .client = ps->io_client, |
203 | .notify.fn = NULL, | 226 | .notify.fn = NULL, |
204 | }; | 227 | }; |
@@ -240,7 +263,7 @@ static int area_io(struct pstore *ps, int rw) | |||
240 | 263 | ||
241 | chunk = area_location(ps, ps->current_area); | 264 | chunk = area_location(ps, ps->current_area); |
242 | 265 | ||
243 | r = chunk_io(ps, chunk, rw, 0); | 266 | r = chunk_io(ps, ps->area, chunk, rw, 0); |
244 | if (r) | 267 | if (r) |
245 | return r; | 268 | return r; |
246 | 269 | ||
@@ -254,20 +277,7 @@ static void zero_memory_area(struct pstore *ps) | |||
254 | 277 | ||
255 | static int zero_disk_area(struct pstore *ps, chunk_t area) | 278 | static int zero_disk_area(struct pstore *ps, chunk_t area) |
256 | { | 279 | { |
257 | struct dm_io_region where = { | 280 | return chunk_io(ps, ps->zero_area, area_location(ps, area), WRITE, 0); |
258 | .bdev = ps->store->cow->bdev, | ||
259 | .sector = ps->store->chunk_size * area_location(ps, area), | ||
260 | .count = ps->store->chunk_size, | ||
261 | }; | ||
262 | struct dm_io_request io_req = { | ||
263 | .bi_rw = WRITE, | ||
264 | .mem.type = DM_IO_VMA, | ||
265 | .mem.ptr.vma = ps->zero_area, | ||
266 | .client = ps->io_client, | ||
267 | .notify.fn = NULL, | ||
268 | }; | ||
269 | |||
270 | return dm_io(&io_req, 1, &where, NULL); | ||
271 | } | 281 | } |
272 | 282 | ||
273 | static int read_header(struct pstore *ps, int *new_snapshot) | 283 | static int read_header(struct pstore *ps, int *new_snapshot) |
@@ -276,6 +286,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
276 | struct disk_header *dh; | 286 | struct disk_header *dh; |
277 | chunk_t chunk_size; | 287 | chunk_t chunk_size; |
278 | int chunk_size_supplied = 1; | 288 | int chunk_size_supplied = 1; |
289 | char *chunk_err; | ||
279 | 290 | ||
280 | /* | 291 | /* |
281 | * Use default chunk size (or hardsect_size, if larger) if none supplied | 292 | * Use default chunk size (or hardsect_size, if larger) if none supplied |
@@ -297,11 +308,11 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
297 | if (r) | 308 | if (r) |
298 | return r; | 309 | return r; |
299 | 310 | ||
300 | r = chunk_io(ps, 0, READ, 1); | 311 | r = chunk_io(ps, ps->header_area, 0, READ, 1); |
301 | if (r) | 312 | if (r) |
302 | goto bad; | 313 | goto bad; |
303 | 314 | ||
304 | dh = (struct disk_header *) ps->area; | 315 | dh = ps->header_area; |
305 | 316 | ||
306 | if (le32_to_cpu(dh->magic) == 0) { | 317 | if (le32_to_cpu(dh->magic) == 0) { |
307 | *new_snapshot = 1; | 318 | *new_snapshot = 1; |
@@ -319,20 +330,25 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
319 | ps->version = le32_to_cpu(dh->version); | 330 | ps->version = le32_to_cpu(dh->version); |
320 | chunk_size = le32_to_cpu(dh->chunk_size); | 331 | chunk_size = le32_to_cpu(dh->chunk_size); |
321 | 332 | ||
322 | if (!chunk_size_supplied || ps->store->chunk_size == chunk_size) | 333 | if (ps->store->chunk_size == chunk_size) |
323 | return 0; | 334 | return 0; |
324 | 335 | ||
325 | DMWARN("chunk size %llu in device metadata overrides " | 336 | if (chunk_size_supplied) |
326 | "table chunk size of %llu.", | 337 | DMWARN("chunk size %llu in device metadata overrides " |
327 | (unsigned long long)chunk_size, | 338 | "table chunk size of %llu.", |
328 | (unsigned long long)ps->store->chunk_size); | 339 | (unsigned long long)chunk_size, |
340 | (unsigned long long)ps->store->chunk_size); | ||
329 | 341 | ||
330 | /* We had a bogus chunk_size. Fix stuff up. */ | 342 | /* We had a bogus chunk_size. Fix stuff up. */ |
331 | free_area(ps); | 343 | free_area(ps); |
332 | 344 | ||
333 | ps->store->chunk_size = chunk_size; | 345 | r = dm_exception_store_set_chunk_size(ps->store, chunk_size, |
334 | ps->store->chunk_mask = chunk_size - 1; | 346 | &chunk_err); |
335 | ps->store->chunk_shift = ffs(chunk_size) - 1; | 347 | if (r) { |
348 | DMERR("invalid on-disk chunk size %llu: %s.", | ||
349 | (unsigned long long)chunk_size, chunk_err); | ||
350 | return r; | ||
351 | } | ||
336 | 352 | ||
337 | r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size), | 353 | r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size), |
338 | ps->io_client); | 354 | ps->io_client); |
@@ -351,15 +367,15 @@ static int write_header(struct pstore *ps) | |||
351 | { | 367 | { |
352 | struct disk_header *dh; | 368 | struct disk_header *dh; |
353 | 369 | ||
354 | memset(ps->area, 0, ps->store->chunk_size << SECTOR_SHIFT); | 370 | memset(ps->header_area, 0, ps->store->chunk_size << SECTOR_SHIFT); |
355 | 371 | ||
356 | dh = (struct disk_header *) ps->area; | 372 | dh = ps->header_area; |
357 | dh->magic = cpu_to_le32(SNAP_MAGIC); | 373 | dh->magic = cpu_to_le32(SNAP_MAGIC); |
358 | dh->valid = cpu_to_le32(ps->valid); | 374 | dh->valid = cpu_to_le32(ps->valid); |
359 | dh->version = cpu_to_le32(ps->version); | 375 | dh->version = cpu_to_le32(ps->version); |
360 | dh->chunk_size = cpu_to_le32(ps->store->chunk_size); | 376 | dh->chunk_size = cpu_to_le32(ps->store->chunk_size); |
361 | 377 | ||
362 | return chunk_io(ps, 0, WRITE, 1); | 378 | return chunk_io(ps, ps->header_area, 0, WRITE, 1); |
363 | } | 379 | } |
364 | 380 | ||
365 | /* | 381 | /* |
@@ -679,6 +695,8 @@ static int persistent_ctr(struct dm_exception_store *store, | |||
679 | ps->valid = 1; | 695 | ps->valid = 1; |
680 | ps->version = SNAPSHOT_DISK_VERSION; | 696 | ps->version = SNAPSHOT_DISK_VERSION; |
681 | ps->area = NULL; | 697 | ps->area = NULL; |
698 | ps->zero_area = NULL; | ||
699 | ps->header_area = NULL; | ||
682 | ps->next_free = 2; /* skipping the header and first area */ | 700 | ps->next_free = 2; /* skipping the header and first area */ |
683 | ps->current_committed = 0; | 701 | ps->current_committed = 0; |
684 | 702 | ||
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index d573165cd2b7..57f1bf7f3b7a 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -1176,6 +1176,15 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, | |||
1176 | return 0; | 1176 | return 0; |
1177 | } | 1177 | } |
1178 | 1178 | ||
1179 | static int snapshot_iterate_devices(struct dm_target *ti, | ||
1180 | iterate_devices_callout_fn fn, void *data) | ||
1181 | { | ||
1182 | struct dm_snapshot *snap = ti->private; | ||
1183 | |||
1184 | return fn(ti, snap->origin, 0, ti->len, data); | ||
1185 | } | ||
1186 | |||
1187 | |||
1179 | /*----------------------------------------------------------------- | 1188 | /*----------------------------------------------------------------- |
1180 | * Origin methods | 1189 | * Origin methods |
1181 | *---------------------------------------------------------------*/ | 1190 | *---------------------------------------------------------------*/ |
@@ -1410,20 +1419,29 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result, | |||
1410 | return 0; | 1419 | return 0; |
1411 | } | 1420 | } |
1412 | 1421 | ||
1422 | static int origin_iterate_devices(struct dm_target *ti, | ||
1423 | iterate_devices_callout_fn fn, void *data) | ||
1424 | { | ||
1425 | struct dm_dev *dev = ti->private; | ||
1426 | |||
1427 | return fn(ti, dev, 0, ti->len, data); | ||
1428 | } | ||
1429 | |||
1413 | static struct target_type origin_target = { | 1430 | static struct target_type origin_target = { |
1414 | .name = "snapshot-origin", | 1431 | .name = "snapshot-origin", |
1415 | .version = {1, 6, 0}, | 1432 | .version = {1, 7, 0}, |
1416 | .module = THIS_MODULE, | 1433 | .module = THIS_MODULE, |
1417 | .ctr = origin_ctr, | 1434 | .ctr = origin_ctr, |
1418 | .dtr = origin_dtr, | 1435 | .dtr = origin_dtr, |
1419 | .map = origin_map, | 1436 | .map = origin_map, |
1420 | .resume = origin_resume, | 1437 | .resume = origin_resume, |
1421 | .status = origin_status, | 1438 | .status = origin_status, |
1439 | .iterate_devices = origin_iterate_devices, | ||
1422 | }; | 1440 | }; |
1423 | 1441 | ||
1424 | static struct target_type snapshot_target = { | 1442 | static struct target_type snapshot_target = { |
1425 | .name = "snapshot", | 1443 | .name = "snapshot", |
1426 | .version = {1, 6, 0}, | 1444 | .version = {1, 7, 0}, |
1427 | .module = THIS_MODULE, | 1445 | .module = THIS_MODULE, |
1428 | .ctr = snapshot_ctr, | 1446 | .ctr = snapshot_ctr, |
1429 | .dtr = snapshot_dtr, | 1447 | .dtr = snapshot_dtr, |
@@ -1431,6 +1449,7 @@ static struct target_type snapshot_target = { | |||
1431 | .end_io = snapshot_end_io, | 1449 | .end_io = snapshot_end_io, |
1432 | .resume = snapshot_resume, | 1450 | .resume = snapshot_resume, |
1433 | .status = snapshot_status, | 1451 | .status = snapshot_status, |
1452 | .iterate_devices = snapshot_iterate_devices, | ||
1434 | }; | 1453 | }; |
1435 | 1454 | ||
1436 | static int __init dm_snapshot_init(void) | 1455 | static int __init dm_snapshot_init(void) |
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 4e0e5937e42a..3e563d251733 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -329,9 +329,19 @@ static int stripe_iterate_devices(struct dm_target *ti, | |||
329 | return ret; | 329 | return ret; |
330 | } | 330 | } |
331 | 331 | ||
332 | static void stripe_io_hints(struct dm_target *ti, | ||
333 | struct queue_limits *limits) | ||
334 | { | ||
335 | struct stripe_c *sc = ti->private; | ||
336 | unsigned chunk_size = (sc->chunk_mask + 1) << 9; | ||
337 | |||
338 | blk_limits_io_min(limits, chunk_size); | ||
339 | limits->io_opt = chunk_size * sc->stripes; | ||
340 | } | ||
341 | |||
332 | static struct target_type stripe_target = { | 342 | static struct target_type stripe_target = { |
333 | .name = "striped", | 343 | .name = "striped", |
334 | .version = {1, 2, 0}, | 344 | .version = {1, 3, 0}, |
335 | .module = THIS_MODULE, | 345 | .module = THIS_MODULE, |
336 | .ctr = stripe_ctr, | 346 | .ctr = stripe_ctr, |
337 | .dtr = stripe_dtr, | 347 | .dtr = stripe_dtr, |
@@ -339,6 +349,7 @@ static struct target_type stripe_target = { | |||
339 | .end_io = stripe_end_io, | 349 | .end_io = stripe_end_io, |
340 | .status = stripe_status, | 350 | .status = stripe_status, |
341 | .iterate_devices = stripe_iterate_devices, | 351 | .iterate_devices = stripe_iterate_devices, |
352 | .io_hints = stripe_io_hints, | ||
342 | }; | 353 | }; |
343 | 354 | ||
344 | int __init dm_stripe_init(void) | 355 | int __init dm_stripe_init(void) |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index d952b3441913..1a6cb3c7822e 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -343,10 +343,10 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md) | |||
343 | } | 343 | } |
344 | 344 | ||
345 | /* | 345 | /* |
346 | * If possible, this checks an area of a destination device is valid. | 346 | * If possible, this checks an area of a destination device is invalid. |
347 | */ | 347 | */ |
348 | static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev, | 348 | static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev, |
349 | sector_t start, sector_t len, void *data) | 349 | sector_t start, sector_t len, void *data) |
350 | { | 350 | { |
351 | struct queue_limits *limits = data; | 351 | struct queue_limits *limits = data; |
352 | struct block_device *bdev = dev->bdev; | 352 | struct block_device *bdev = dev->bdev; |
@@ -357,36 +357,40 @@ static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev, | |||
357 | char b[BDEVNAME_SIZE]; | 357 | char b[BDEVNAME_SIZE]; |
358 | 358 | ||
359 | if (!dev_size) | 359 | if (!dev_size) |
360 | return 1; | 360 | return 0; |
361 | 361 | ||
362 | if ((start >= dev_size) || (start + len > dev_size)) { | 362 | if ((start >= dev_size) || (start + len > dev_size)) { |
363 | DMWARN("%s: %s too small for target", | 363 | DMWARN("%s: %s too small for target: " |
364 | dm_device_name(ti->table->md), bdevname(bdev, b)); | 364 | "start=%llu, len=%llu, dev_size=%llu", |
365 | return 0; | 365 | dm_device_name(ti->table->md), bdevname(bdev, b), |
366 | (unsigned long long)start, | ||
367 | (unsigned long long)len, | ||
368 | (unsigned long long)dev_size); | ||
369 | return 1; | ||
366 | } | 370 | } |
367 | 371 | ||
368 | if (logical_block_size_sectors <= 1) | 372 | if (logical_block_size_sectors <= 1) |
369 | return 1; | 373 | return 0; |
370 | 374 | ||
371 | if (start & (logical_block_size_sectors - 1)) { | 375 | if (start & (logical_block_size_sectors - 1)) { |
372 | DMWARN("%s: start=%llu not aligned to h/w " | 376 | DMWARN("%s: start=%llu not aligned to h/w " |
373 | "logical block size %hu of %s", | 377 | "logical block size %u of %s", |
374 | dm_device_name(ti->table->md), | 378 | dm_device_name(ti->table->md), |
375 | (unsigned long long)start, | 379 | (unsigned long long)start, |
376 | limits->logical_block_size, bdevname(bdev, b)); | 380 | limits->logical_block_size, bdevname(bdev, b)); |
377 | return 0; | 381 | return 1; |
378 | } | 382 | } |
379 | 383 | ||
380 | if (len & (logical_block_size_sectors - 1)) { | 384 | if (len & (logical_block_size_sectors - 1)) { |
381 | DMWARN("%s: len=%llu not aligned to h/w " | 385 | DMWARN("%s: len=%llu not aligned to h/w " |
382 | "logical block size %hu of %s", | 386 | "logical block size %u of %s", |
383 | dm_device_name(ti->table->md), | 387 | dm_device_name(ti->table->md), |
384 | (unsigned long long)len, | 388 | (unsigned long long)len, |
385 | limits->logical_block_size, bdevname(bdev, b)); | 389 | limits->logical_block_size, bdevname(bdev, b)); |
386 | return 0; | 390 | return 1; |
387 | } | 391 | } |
388 | 392 | ||
389 | return 1; | 393 | return 0; |
390 | } | 394 | } |
391 | 395 | ||
392 | /* | 396 | /* |
@@ -496,8 +500,15 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, | |||
496 | } | 500 | } |
497 | 501 | ||
498 | if (blk_stack_limits(limits, &q->limits, start << 9) < 0) | 502 | if (blk_stack_limits(limits, &q->limits, start << 9) < 0) |
499 | DMWARN("%s: target device %s is misaligned", | 503 | DMWARN("%s: target device %s is misaligned: " |
500 | dm_device_name(ti->table->md), bdevname(bdev, b)); | 504 | "physical_block_size=%u, logical_block_size=%u, " |
505 | "alignment_offset=%u, start=%llu", | ||
506 | dm_device_name(ti->table->md), bdevname(bdev, b), | ||
507 | q->limits.physical_block_size, | ||
508 | q->limits.logical_block_size, | ||
509 | q->limits.alignment_offset, | ||
510 | (unsigned long long) start << 9); | ||
511 | |||
501 | 512 | ||
502 | /* | 513 | /* |
503 | * Check if merge fn is supported. | 514 | * Check if merge fn is supported. |
@@ -698,7 +709,7 @@ static int validate_hardware_logical_block_alignment(struct dm_table *table, | |||
698 | 709 | ||
699 | if (remaining) { | 710 | if (remaining) { |
700 | DMWARN("%s: table line %u (start sect %llu len %llu) " | 711 | DMWARN("%s: table line %u (start sect %llu len %llu) " |
701 | "not aligned to h/w logical block size %hu", | 712 | "not aligned to h/w logical block size %u", |
702 | dm_device_name(table->md), i, | 713 | dm_device_name(table->md), i, |
703 | (unsigned long long) ti->begin, | 714 | (unsigned long long) ti->begin, |
704 | (unsigned long long) ti->len, | 715 | (unsigned long long) ti->len, |
@@ -996,12 +1007,16 @@ int dm_calculate_queue_limits(struct dm_table *table, | |||
996 | ti->type->iterate_devices(ti, dm_set_device_limits, | 1007 | ti->type->iterate_devices(ti, dm_set_device_limits, |
997 | &ti_limits); | 1008 | &ti_limits); |
998 | 1009 | ||
1010 | /* Set I/O hints portion of queue limits */ | ||
1011 | if (ti->type->io_hints) | ||
1012 | ti->type->io_hints(ti, &ti_limits); | ||
1013 | |||
999 | /* | 1014 | /* |
1000 | * Check each device area is consistent with the target's | 1015 | * Check each device area is consistent with the target's |
1001 | * overall queue limits. | 1016 | * overall queue limits. |
1002 | */ | 1017 | */ |
1003 | if (!ti->type->iterate_devices(ti, device_area_is_valid, | 1018 | if (ti->type->iterate_devices(ti, device_area_is_invalid, |
1004 | &ti_limits)) | 1019 | &ti_limits)) |
1005 | return -EINVAL; | 1020 | return -EINVAL; |
1006 | 1021 | ||
1007 | combine_limits: | 1022 | combine_limits: |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 8a311ea0d441..b4845b14740d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -738,16 +738,22 @@ static void rq_completed(struct mapped_device *md, int run_queue) | |||
738 | dm_put(md); | 738 | dm_put(md); |
739 | } | 739 | } |
740 | 740 | ||
741 | static void free_rq_clone(struct request *clone) | ||
742 | { | ||
743 | struct dm_rq_target_io *tio = clone->end_io_data; | ||
744 | |||
745 | blk_rq_unprep_clone(clone); | ||
746 | free_rq_tio(tio); | ||
747 | } | ||
748 | |||
741 | static void dm_unprep_request(struct request *rq) | 749 | static void dm_unprep_request(struct request *rq) |
742 | { | 750 | { |
743 | struct request *clone = rq->special; | 751 | struct request *clone = rq->special; |
744 | struct dm_rq_target_io *tio = clone->end_io_data; | ||
745 | 752 | ||
746 | rq->special = NULL; | 753 | rq->special = NULL; |
747 | rq->cmd_flags &= ~REQ_DONTPREP; | 754 | rq->cmd_flags &= ~REQ_DONTPREP; |
748 | 755 | ||
749 | blk_rq_unprep_clone(clone); | 756 | free_rq_clone(clone); |
750 | free_rq_tio(tio); | ||
751 | } | 757 | } |
752 | 758 | ||
753 | /* | 759 | /* |
@@ -825,8 +831,7 @@ static void dm_end_request(struct request *clone, int error) | |||
825 | rq->sense_len = clone->sense_len; | 831 | rq->sense_len = clone->sense_len; |
826 | } | 832 | } |
827 | 833 | ||
828 | BUG_ON(clone->bio); | 834 | free_rq_clone(clone); |
829 | free_rq_tio(tio); | ||
830 | 835 | ||
831 | blk_end_request_all(rq, error); | 836 | blk_end_request_all(rq, error); |
832 | 837 | ||
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ae5fe91867e1..10ed195c0c1c 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -736,7 +736,7 @@ static int __devinit m25p_probe(struct spi_device *spi) | |||
736 | flash->partitioned = 1; | 736 | flash->partitioned = 1; |
737 | return add_mtd_partitions(&flash->mtd, parts, nr_parts); | 737 | return add_mtd_partitions(&flash->mtd, parts, nr_parts); |
738 | } | 738 | } |
739 | } else if (data->nr_parts) | 739 | } else if (data && data->nr_parts) |
740 | dev_warn(&spi->dev, "ignoring %d default partitions on %s\n", | 740 | dev_warn(&spi->dev, "ignoring %d default partitions on %s\n", |
741 | data->nr_parts, data->name); | 741 | data->nr_parts, data->name); |
742 | 742 | ||
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index fb86cacd5bdb..1002e1882996 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c | |||
@@ -135,16 +135,17 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev) | |||
135 | int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, | 135 | int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, |
136 | size_t *retlen, uint8_t *buf) | 136 | size_t *retlen, uint8_t *buf) |
137 | { | 137 | { |
138 | loff_t mask = mtd->writesize - 1; | ||
138 | struct mtd_oob_ops ops; | 139 | struct mtd_oob_ops ops; |
139 | int res; | 140 | int res; |
140 | 141 | ||
141 | ops.mode = MTD_OOB_PLACE; | 142 | ops.mode = MTD_OOB_PLACE; |
142 | ops.ooboffs = offs & (mtd->writesize - 1); | 143 | ops.ooboffs = offs & mask; |
143 | ops.ooblen = len; | 144 | ops.ooblen = len; |
144 | ops.oobbuf = buf; | 145 | ops.oobbuf = buf; |
145 | ops.datbuf = NULL; | 146 | ops.datbuf = NULL; |
146 | 147 | ||
147 | res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops); | 148 | res = mtd->read_oob(mtd, offs & ~mask, &ops); |
148 | *retlen = ops.oobretlen; | 149 | *retlen = ops.oobretlen; |
149 | return res; | 150 | return res; |
150 | } | 151 | } |
@@ -155,16 +156,17 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, | |||
155 | int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, | 156 | int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, |
156 | size_t *retlen, uint8_t *buf) | 157 | size_t *retlen, uint8_t *buf) |
157 | { | 158 | { |
159 | loff_t mask = mtd->writesize - 1; | ||
158 | struct mtd_oob_ops ops; | 160 | struct mtd_oob_ops ops; |
159 | int res; | 161 | int res; |
160 | 162 | ||
161 | ops.mode = MTD_OOB_PLACE; | 163 | ops.mode = MTD_OOB_PLACE; |
162 | ops.ooboffs = offs & (mtd->writesize - 1); | 164 | ops.ooboffs = offs & mask; |
163 | ops.ooblen = len; | 165 | ops.ooblen = len; |
164 | ops.oobbuf = buf; | 166 | ops.oobbuf = buf; |
165 | ops.datbuf = NULL; | 167 | ops.datbuf = NULL; |
166 | 168 | ||
167 | res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops); | 169 | res = mtd->write_oob(mtd, offs & ~mask, &ops); |
168 | *retlen = ops.oobretlen; | 170 | *retlen = ops.oobretlen; |
169 | return res; | 171 | return res; |
170 | } | 172 | } |
@@ -177,17 +179,18 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, | |||
177 | static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len, | 179 | static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len, |
178 | size_t *retlen, uint8_t *buf, uint8_t *oob) | 180 | size_t *retlen, uint8_t *buf, uint8_t *oob) |
179 | { | 181 | { |
182 | loff_t mask = mtd->writesize - 1; | ||
180 | struct mtd_oob_ops ops; | 183 | struct mtd_oob_ops ops; |
181 | int res; | 184 | int res; |
182 | 185 | ||
183 | ops.mode = MTD_OOB_PLACE; | 186 | ops.mode = MTD_OOB_PLACE; |
184 | ops.ooboffs = offs; | 187 | ops.ooboffs = offs & mask; |
185 | ops.ooblen = mtd->oobsize; | 188 | ops.ooblen = mtd->oobsize; |
186 | ops.oobbuf = oob; | 189 | ops.oobbuf = oob; |
187 | ops.datbuf = buf; | 190 | ops.datbuf = buf; |
188 | ops.len = len; | 191 | ops.len = len; |
189 | 192 | ||
190 | res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops); | 193 | res = mtd->write_oob(mtd, offs & ~mask, &ops); |
191 | *retlen = ops.retlen; | 194 | *retlen = ops.retlen; |
192 | return res; | 195 | return res; |
193 | } | 196 | } |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index e212f2c5448b..24f7ca5e17de 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -491,6 +491,7 @@ static int gfar_remove(struct of_device *ofdev) | |||
491 | 491 | ||
492 | dev_set_drvdata(&ofdev->dev, NULL); | 492 | dev_set_drvdata(&ofdev->dev, NULL); |
493 | 493 | ||
494 | unregister_netdev(dev); | ||
494 | iounmap(priv->regs); | 495 | iounmap(priv->regs); |
495 | free_netdev(priv->ndev); | 496 | free_netdev(priv->ndev); |
496 | 497 | ||
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 6dcac73b4d29..f593fbbb4e52 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c | |||
@@ -2874,45 +2874,27 @@ static int ipw_fw_dma_add_command_block(struct ipw_priv *priv, | |||
2874 | return 0; | 2874 | return 0; |
2875 | } | 2875 | } |
2876 | 2876 | ||
2877 | static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, | 2877 | static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address, |
2878 | u32 src_phys, u32 dest_address, u32 length) | 2878 | int nr, u32 dest_address, u32 len) |
2879 | { | 2879 | { |
2880 | u32 bytes_left = length; | 2880 | int ret, i; |
2881 | u32 src_offset = 0; | 2881 | u32 size; |
2882 | u32 dest_offset = 0; | 2882 | |
2883 | int status = 0; | ||
2884 | IPW_DEBUG_FW(">> \n"); | 2883 | IPW_DEBUG_FW(">> \n"); |
2885 | IPW_DEBUG_FW_INFO("src_phys=0x%x dest_address=0x%x length=0x%x\n", | 2884 | IPW_DEBUG_FW_INFO("nr=%d dest_address=0x%x len=0x%x\n", |
2886 | src_phys, dest_address, length); | 2885 | nr, dest_address, len); |
2887 | while (bytes_left > CB_MAX_LENGTH) { | 2886 | |
2888 | status = ipw_fw_dma_add_command_block(priv, | 2887 | for (i = 0; i < nr; i++) { |
2889 | src_phys + src_offset, | 2888 | size = min_t(u32, len - i * CB_MAX_LENGTH, CB_MAX_LENGTH); |
2890 | dest_address + | 2889 | ret = ipw_fw_dma_add_command_block(priv, src_address[i], |
2891 | dest_offset, | 2890 | dest_address + |
2892 | CB_MAX_LENGTH, 0, 0); | 2891 | i * CB_MAX_LENGTH, size, |
2893 | if (status) { | 2892 | 0, 0); |
2893 | if (ret) { | ||
2894 | IPW_DEBUG_FW_INFO(": Failed\n"); | 2894 | IPW_DEBUG_FW_INFO(": Failed\n"); |
2895 | return -1; | 2895 | return -1; |
2896 | } else | 2896 | } else |
2897 | IPW_DEBUG_FW_INFO(": Added new cb\n"); | 2897 | IPW_DEBUG_FW_INFO(": Added new cb\n"); |
2898 | |||
2899 | src_offset += CB_MAX_LENGTH; | ||
2900 | dest_offset += CB_MAX_LENGTH; | ||
2901 | bytes_left -= CB_MAX_LENGTH; | ||
2902 | } | ||
2903 | |||
2904 | /* add the buffer tail */ | ||
2905 | if (bytes_left > 0) { | ||
2906 | status = | ||
2907 | ipw_fw_dma_add_command_block(priv, src_phys + src_offset, | ||
2908 | dest_address + dest_offset, | ||
2909 | bytes_left, 0, 0); | ||
2910 | if (status) { | ||
2911 | IPW_DEBUG_FW_INFO(": Failed on the buffer tail\n"); | ||
2912 | return -1; | ||
2913 | } else | ||
2914 | IPW_DEBUG_FW_INFO | ||
2915 | (": Adding new cb - the buffer tail\n"); | ||
2916 | } | 2898 | } |
2917 | 2899 | ||
2918 | IPW_DEBUG_FW("<< \n"); | 2900 | IPW_DEBUG_FW("<< \n"); |
@@ -3160,59 +3142,91 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) | |||
3160 | 3142 | ||
3161 | static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) | 3143 | static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) |
3162 | { | 3144 | { |
3163 | int rc = -1; | 3145 | int ret = -1; |
3164 | int offset = 0; | 3146 | int offset = 0; |
3165 | struct fw_chunk *chunk; | 3147 | struct fw_chunk *chunk; |
3166 | dma_addr_t shared_phys; | 3148 | int total_nr = 0; |
3167 | u8 *shared_virt; | 3149 | int i; |
3150 | struct pci_pool *pool; | ||
3151 | u32 *virts[CB_NUMBER_OF_ELEMENTS_SMALL]; | ||
3152 | dma_addr_t phys[CB_NUMBER_OF_ELEMENTS_SMALL]; | ||
3168 | 3153 | ||
3169 | IPW_DEBUG_TRACE("<< : \n"); | 3154 | IPW_DEBUG_TRACE("<< : \n"); |
3170 | shared_virt = pci_alloc_consistent(priv->pci_dev, len, &shared_phys); | ||
3171 | 3155 | ||
3172 | if (!shared_virt) | 3156 | pool = pci_pool_create("ipw2200", priv->pci_dev, CB_MAX_LENGTH, 0, 0); |
3157 | if (!pool) { | ||
3158 | IPW_ERROR("pci_pool_create failed\n"); | ||
3173 | return -ENOMEM; | 3159 | return -ENOMEM; |
3174 | 3160 | } | |
3175 | memmove(shared_virt, data, len); | ||
3176 | 3161 | ||
3177 | /* Start the Dma */ | 3162 | /* Start the Dma */ |
3178 | rc = ipw_fw_dma_enable(priv); | 3163 | ret = ipw_fw_dma_enable(priv); |
3179 | 3164 | ||
3180 | /* the DMA is already ready this would be a bug. */ | 3165 | /* the DMA is already ready this would be a bug. */ |
3181 | BUG_ON(priv->sram_desc.last_cb_index > 0); | 3166 | BUG_ON(priv->sram_desc.last_cb_index > 0); |
3182 | 3167 | ||
3183 | do { | 3168 | do { |
3169 | u32 chunk_len; | ||
3170 | u8 *start; | ||
3171 | int size; | ||
3172 | int nr = 0; | ||
3173 | |||
3184 | chunk = (struct fw_chunk *)(data + offset); | 3174 | chunk = (struct fw_chunk *)(data + offset); |
3185 | offset += sizeof(struct fw_chunk); | 3175 | offset += sizeof(struct fw_chunk); |
3176 | chunk_len = le32_to_cpu(chunk->length); | ||
3177 | start = data + offset; | ||
3178 | |||
3179 | nr = (chunk_len + CB_MAX_LENGTH - 1) / CB_MAX_LENGTH; | ||
3180 | for (i = 0; i < nr; i++) { | ||
3181 | virts[total_nr] = pci_pool_alloc(pool, GFP_KERNEL, | ||
3182 | &phys[total_nr]); | ||
3183 | if (!virts[total_nr]) { | ||
3184 | ret = -ENOMEM; | ||
3185 | goto out; | ||
3186 | } | ||
3187 | size = min_t(u32, chunk_len - i * CB_MAX_LENGTH, | ||
3188 | CB_MAX_LENGTH); | ||
3189 | memcpy(virts[total_nr], start, size); | ||
3190 | start += size; | ||
3191 | total_nr++; | ||
3192 | /* We don't support fw chunk larger than 64*8K */ | ||
3193 | BUG_ON(total_nr > CB_NUMBER_OF_ELEMENTS_SMALL); | ||
3194 | } | ||
3195 | |||
3186 | /* build DMA packet and queue up for sending */ | 3196 | /* build DMA packet and queue up for sending */ |
3187 | /* dma to chunk->address, the chunk->length bytes from data + | 3197 | /* dma to chunk->address, the chunk->length bytes from data + |
3188 | * offeset*/ | 3198 | * offeset*/ |
3189 | /* Dma loading */ | 3199 | /* Dma loading */ |
3190 | rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, | 3200 | ret = ipw_fw_dma_add_buffer(priv, &phys[total_nr - nr], |
3191 | le32_to_cpu(chunk->address), | 3201 | nr, le32_to_cpu(chunk->address), |
3192 | le32_to_cpu(chunk->length)); | 3202 | chunk_len); |
3193 | if (rc) { | 3203 | if (ret) { |
3194 | IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); | 3204 | IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); |
3195 | goto out; | 3205 | goto out; |
3196 | } | 3206 | } |
3197 | 3207 | ||
3198 | offset += le32_to_cpu(chunk->length); | 3208 | offset += chunk_len; |
3199 | } while (offset < len); | 3209 | } while (offset < len); |
3200 | 3210 | ||
3201 | /* Run the DMA and wait for the answer */ | 3211 | /* Run the DMA and wait for the answer */ |
3202 | rc = ipw_fw_dma_kick(priv); | 3212 | ret = ipw_fw_dma_kick(priv); |
3203 | if (rc) { | 3213 | if (ret) { |
3204 | IPW_ERROR("dmaKick Failed\n"); | 3214 | IPW_ERROR("dmaKick Failed\n"); |
3205 | goto out; | 3215 | goto out; |
3206 | } | 3216 | } |
3207 | 3217 | ||
3208 | rc = ipw_fw_dma_wait(priv); | 3218 | ret = ipw_fw_dma_wait(priv); |
3209 | if (rc) { | 3219 | if (ret) { |
3210 | IPW_ERROR("dmaWaitSync Failed\n"); | 3220 | IPW_ERROR("dmaWaitSync Failed\n"); |
3211 | goto out; | 3221 | goto out; |
3212 | } | 3222 | } |
3213 | out: | 3223 | out: |
3214 | pci_free_consistent(priv->pci_dev, len, shared_virt, shared_phys); | 3224 | for (i = 0; i < total_nr; i++) |
3215 | return rc; | 3225 | pci_pool_free(pool, virts[i], phys[i]); |
3226 | |||
3227 | pci_pool_destroy(pool); | ||
3228 | |||
3229 | return ret; | ||
3216 | } | 3230 | } |
3217 | 3231 | ||
3218 | /* stop nic */ | 3232 | /* stop nic */ |
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index e3a87210e947..e03fe98f0619 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c | |||
@@ -598,6 +598,29 @@ int pci_iov_resource_bar(struct pci_dev *dev, int resno, | |||
598 | } | 598 | } |
599 | 599 | ||
600 | /** | 600 | /** |
601 | * pci_sriov_resource_alignment - get resource alignment for VF BAR | ||
602 | * @dev: the PCI device | ||
603 | * @resno: the resource number | ||
604 | * | ||
605 | * Returns the alignment of the VF BAR found in the SR-IOV capability. | ||
606 | * This is not the same as the resource size which is defined as | ||
607 | * the VF BAR size multiplied by the number of VFs. The alignment | ||
608 | * is just the VF BAR size. | ||
609 | */ | ||
610 | int pci_sriov_resource_alignment(struct pci_dev *dev, int resno) | ||
611 | { | ||
612 | struct resource tmp; | ||
613 | enum pci_bar_type type; | ||
614 | int reg = pci_iov_resource_bar(dev, resno, &type); | ||
615 | |||
616 | if (!reg) | ||
617 | return 0; | ||
618 | |||
619 | __pci_read_base(dev, type, &tmp, reg); | ||
620 | return resource_alignment(&tmp); | ||
621 | } | ||
622 | |||
623 | /** | ||
601 | * pci_restore_iov_state - restore the state of the IOV capability | 624 | * pci_restore_iov_state - restore the state of the IOV capability |
602 | * @dev: the PCI device | 625 | * @dev: the PCI device |
603 | */ | 626 | */ |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index f73bcbedf37c..5ff4d25bf0e9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -243,6 +243,7 @@ extern int pci_iov_init(struct pci_dev *dev); | |||
243 | extern void pci_iov_release(struct pci_dev *dev); | 243 | extern void pci_iov_release(struct pci_dev *dev); |
244 | extern int pci_iov_resource_bar(struct pci_dev *dev, int resno, | 244 | extern int pci_iov_resource_bar(struct pci_dev *dev, int resno, |
245 | enum pci_bar_type *type); | 245 | enum pci_bar_type *type); |
246 | extern int pci_sriov_resource_alignment(struct pci_dev *dev, int resno); | ||
246 | extern void pci_restore_iov_state(struct pci_dev *dev); | 247 | extern void pci_restore_iov_state(struct pci_dev *dev); |
247 | extern int pci_iov_bus_range(struct pci_bus *bus); | 248 | extern int pci_iov_bus_range(struct pci_bus *bus); |
248 | 249 | ||
@@ -298,4 +299,16 @@ static inline int pci_ats_enabled(struct pci_dev *dev) | |||
298 | } | 299 | } |
299 | #endif /* CONFIG_PCI_IOV */ | 300 | #endif /* CONFIG_PCI_IOV */ |
300 | 301 | ||
302 | static inline int pci_resource_alignment(struct pci_dev *dev, | ||
303 | struct resource *res) | ||
304 | { | ||
305 | #ifdef CONFIG_PCI_IOV | ||
306 | int resno = res - dev->resource; | ||
307 | |||
308 | if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END) | ||
309 | return pci_sriov_resource_alignment(dev, resno); | ||
310 | #endif | ||
311 | return resource_alignment(res); | ||
312 | } | ||
313 | |||
301 | #endif /* DRIVERS_PCI_H */ | 314 | #endif /* DRIVERS_PCI_H */ |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index b636e245445d..7c443b4583ab 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <linux/cache.h> | 26 | #include <linux/cache.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | 28 | #include "pci.h" | |
29 | 29 | ||
30 | static void pbus_assign_resources_sorted(const struct pci_bus *bus) | 30 | static void pbus_assign_resources_sorted(const struct pci_bus *bus) |
31 | { | 31 | { |
@@ -384,7 +384,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long | |||
384 | continue; | 384 | continue; |
385 | r_size = resource_size(r); | 385 | r_size = resource_size(r); |
386 | /* For bridges size != alignment */ | 386 | /* For bridges size != alignment */ |
387 | align = resource_alignment(r); | 387 | align = pci_resource_alignment(dev, r); |
388 | order = __ffs(align) - 20; | 388 | order = __ffs(align) - 20; |
389 | if (order > 11) { | 389 | if (order > 11) { |
390 | dev_warn(&dev->dev, "BAR %d bad alignment %llx: " | 390 | dev_warn(&dev->dev, "BAR %d bad alignment %llx: " |
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 1898c7b47907..88cdd1a937d6 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c | |||
@@ -144,7 +144,7 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, | |||
144 | 144 | ||
145 | size = resource_size(res); | 145 | size = resource_size(res); |
146 | min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; | 146 | min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; |
147 | align = resource_alignment(res); | 147 | align = pci_resource_alignment(dev, res); |
148 | 148 | ||
149 | /* First, try exact prefetching match.. */ | 149 | /* First, try exact prefetching match.. */ |
150 | ret = pci_bus_alloc_resource(bus, res, size, align, min, | 150 | ret = pci_bus_alloc_resource(bus, res, size, align, min, |
@@ -178,7 +178,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) | |||
178 | struct pci_bus *bus; | 178 | struct pci_bus *bus; |
179 | int ret; | 179 | int ret; |
180 | 180 | ||
181 | align = resource_alignment(res); | 181 | align = pci_resource_alignment(dev, res); |
182 | if (!align) { | 182 | if (!align) { |
183 | dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " | 183 | dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " |
184 | "alignment) %pR flags %#lx\n", | 184 | "alignment) %pR flags %#lx\n", |
@@ -259,7 +259,7 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | |||
259 | if (!(r->flags) || r->parent) | 259 | if (!(r->flags) || r->parent) |
260 | continue; | 260 | continue; |
261 | 261 | ||
262 | r_align = resource_alignment(r); | 262 | r_align = pci_resource_alignment(dev, r); |
263 | if (!r_align) { | 263 | if (!r_align) { |
264 | dev_warn(&dev->dev, "BAR %d: bogus alignment " | 264 | dev_warn(&dev->dev, "BAR %d: bogus alignment " |
265 | "%pR flags %#lx\n", | 265 | "%pR flags %#lx\n", |
@@ -271,7 +271,7 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | |||
271 | struct resource_list *ln = list->next; | 271 | struct resource_list *ln = list->next; |
272 | 272 | ||
273 | if (ln) | 273 | if (ln) |
274 | align = resource_alignment(ln->res); | 274 | align = pci_resource_alignment(ln->dev, ln->res); |
275 | 275 | ||
276 | if (r_align > align) { | 276 | if (r_align > align) { |
277 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | 277 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |