Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'md-3.8' of git://neil.brown.name/md

Pull md update from Neil Brown:
"Mostly just little fixes. Probably biggest part is AVX accelerated
RAID6 calculations."

* tag 'md-3.8' of git://neil.brown.name/md:
md/raid5: add blktrace calls
md/raid5: use async_tx_quiesce() instead of open-coding it.
md: Use ->curr_resync as last completed request when cleanly aborting resync.
lib/raid6: build proper files on corresponding arch
lib/raid6: Add AVX2 optimized gen_syndrome functions
lib/raid6: Add AVX2 optimized recovery functions
md: Update checkpoint of resync/recovery based on time.
md:Add place to update ->recovery_cp.
md.c: re-indent various 'switch' statements.
md: close race between removing and adding a device.
md: removed unused variable in calc_sb_1_csm.

+813 -162
+3 -2
arch/x86/Makefile
··· 123 123 # does binutils support specific instructions? 124 124 asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1) 125 125 avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1) 126 + avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1) 126 127 127 - KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) 128 - KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) 128 + KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) 129 + KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) 129 130 130 131 LDFLAGS := -m elf_$(UTS_MACHINE) 131 132
+137 -127
drivers/md/md.c
··· 1414 1414 unsigned long long newcsum; 1415 1415 int size = 256 + le32_to_cpu(sb->max_dev)*2; 1416 1416 __le32 *isuper = (__le32*)sb; 1417 - int i; 1418 1417 1419 1418 disk_csum = sb->sb_csum; 1420 1419 sb->sb_csum = 0; 1421 1420 newcsum = 0; 1422 - for (i=0; size>=4; size -= 4 ) 1421 + for (; size >= 4; size -= 4) 1423 1422 newcsum += le32_to_cpu(*isuper++); 1424 1423 1425 1424 if (size == 2) ··· 4752 4753 } 4753 4754 mddev_get(mddev); 4754 4755 spin_unlock(&all_mddevs_lock); 4756 + if (entry->store == new_dev_store) 4757 + flush_workqueue(md_misc_wq); 4755 4758 rv = mddev_lock(mddev); 4756 4759 if (!rv) { 4757 4760 rv = entry->store(mddev, page, length); ··· 6347 6346 * Commands dealing with the RAID driver but not any 6348 6347 * particular array: 6349 6348 */ 6350 - switch (cmd) 6351 - { 6352 - case RAID_VERSION: 6353 - err = get_version(argp); 6354 - goto done; 6349 + switch (cmd) { 6350 + case RAID_VERSION: 6351 + err = get_version(argp); 6352 + goto done; 6355 6353 6356 - case PRINT_RAID_DEBUG: 6357 - err = 0; 6358 - md_print_devices(); 6359 - goto done; 6354 + case PRINT_RAID_DEBUG: 6355 + err = 0; 6356 + md_print_devices(); 6357 + goto done; 6360 6358 6361 6359 #ifndef MODULE 6362 - case RAID_AUTORUN: 6363 - err = 0; 6364 - autostart_arrays(arg); 6365 - goto done; 6360 + case RAID_AUTORUN: 6361 + err = 0; 6362 + autostart_arrays(arg); 6363 + goto done; 6366 6364 #endif 6367 - default:; 6365 + default:; 6368 6366 } 6369 6367 6370 6368 /* ··· 6398 6398 goto abort; 6399 6399 } 6400 6400 6401 + if (cmd == ADD_NEW_DISK) 6402 + /* need to ensure md_delayed_delete() has completed */ 6403 + flush_workqueue(md_misc_wq); 6404 + 6401 6405 err = mddev_lock(mddev); 6402 6406 if (err) { 6403 6407 printk(KERN_INFO ··· 6410 6406 goto abort; 6411 6407 } 6412 6408 6413 - switch (cmd) 6414 - { 6415 - case SET_ARRAY_INFO: 6416 - { 6417 - mdu_array_info_t info; 6418 - if (!arg) 6419 - memset(&info, 0, sizeof(info)); 6420 - else if (copy_from_user(&info, argp, sizeof(info))) { 6421 - err = -EFAULT; 6422 - goto abort_unlock; 6423 - } 6424 - if (mddev->pers) { 6425 - err = update_array_info(mddev, &info); 6426 - if (err) { 6427 - printk(KERN_WARNING "md: couldn't update" 6428 - " array info. %d\n", err); 6429 - goto abort_unlock; 6430 - } 6431 - goto done_unlock; 6432 - } 6433 - if (!list_empty(&mddev->disks)) { 6434 - printk(KERN_WARNING 6435 - "md: array %s already has disks!\n", 6436 - mdname(mddev)); 6437 - err = -EBUSY; 6438 - goto abort_unlock; 6439 - } 6440 - if (mddev->raid_disks) { 6441 - printk(KERN_WARNING 6442 - "md: array %s already initialised!\n", 6443 - mdname(mddev)); 6444 - err = -EBUSY; 6445 - goto abort_unlock; 6446 - } 6447 - err = set_array_info(mddev, &info); 6448 - if (err) { 6449 - printk(KERN_WARNING "md: couldn't set" 6450 - " array info. %d\n", err); 6451 - goto abort_unlock; 6452 - } 6409 + if (cmd == SET_ARRAY_INFO) { 6410 + mdu_array_info_t info; 6411 + if (!arg) 6412 + memset(&info, 0, sizeof(info)); 6413 + else if (copy_from_user(&info, argp, sizeof(info))) { 6414 + err = -EFAULT; 6415 + goto abort_unlock; 6416 + } 6417 + if (mddev->pers) { 6418 + err = update_array_info(mddev, &info); 6419 + if (err) { 6420 + printk(KERN_WARNING "md: couldn't update" 6421 + " array info. %d\n", err); 6422 + goto abort_unlock; 6453 6423 } 6454 6424 goto done_unlock; 6455 - 6456 - default:; 6425 + } 6426 + if (!list_empty(&mddev->disks)) { 6427 + printk(KERN_WARNING 6428 + "md: array %s already has disks!\n", 6429 + mdname(mddev)); 6430 + err = -EBUSY; 6431 + goto abort_unlock; 6432 + } 6433 + if (mddev->raid_disks) { 6434 + printk(KERN_WARNING 6435 + "md: array %s already initialised!\n", 6436 + mdname(mddev)); 6437 + err = -EBUSY; 6438 + goto abort_unlock; 6439 + } 6440 + err = set_array_info(mddev, &info); 6441 + if (err) { 6442 + printk(KERN_WARNING "md: couldn't set" 6443 + " array info. %d\n", err); 6444 + goto abort_unlock; 6445 + } 6446 + goto done_unlock; 6457 6447 } 6458 6448 6459 6449 /* ··· 6466 6468 /* 6467 6469 * Commands even a read-only array can execute: 6468 6470 */ 6469 - switch (cmd) 6470 - { 6471 - case GET_BITMAP_FILE: 6472 - err = get_bitmap_file(mddev, argp); 6471 + switch (cmd) { 6472 + case GET_BITMAP_FILE: 6473 + err = get_bitmap_file(mddev, argp); 6474 + goto done_unlock; 6475 + 6476 + case RESTART_ARRAY_RW: 6477 + err = restart_array(mddev); 6478 + goto done_unlock; 6479 + 6480 + case STOP_ARRAY: 6481 + err = do_md_stop(mddev, 0, bdev); 6482 + goto done_unlock; 6483 + 6484 + case STOP_ARRAY_RO: 6485 + err = md_set_readonly(mddev, bdev); 6486 + goto done_unlock; 6487 + 6488 + case BLKROSET: 6489 + if (get_user(ro, (int __user *)(arg))) { 6490 + err = -EFAULT; 6491 + goto done_unlock; 6492 + } 6493 + err = -EINVAL; 6494 + 6495 + /* if the bdev is going readonly the value of mddev->ro 6496 + * does not matter, no writes are coming 6497 + */ 6498 + if (ro) 6473 6499 goto done_unlock; 6474 6500 6475 - case RESTART_ARRAY_RW: 6501 + /* are we are already prepared for writes? */ 6502 + if (mddev->ro != 1) 6503 + goto done_unlock; 6504 + 6505 + /* transitioning to readauto need only happen for 6506 + * arrays that call md_write_start 6507 + */ 6508 + if (mddev->pers) { 6476 6509 err = restart_array(mddev); 6477 - goto done_unlock; 6478 - 6479 - case STOP_ARRAY: 6480 - err = do_md_stop(mddev, 0, bdev); 6481 - goto done_unlock; 6482 - 6483 - case STOP_ARRAY_RO: 6484 - err = md_set_readonly(mddev, bdev); 6485 - goto done_unlock; 6486 - 6487 - case BLKROSET: 6488 - if (get_user(ro, (int __user *)(arg))) { 6489 - err = -EFAULT; 6490 - goto done_unlock; 6510 + if (err == 0) { 6511 + mddev->ro = 2; 6512 + set_disk_ro(mddev->gendisk, 0); 6491 6513 } 6492 - err = -EINVAL; 6493 - 6494 - /* if the bdev is going readonly the value of mddev->ro 6495 - * does not matter, no writes are coming 6496 - */ 6497 - if (ro) 6498 - goto done_unlock; 6499 - 6500 - /* are we are already prepared for writes? */ 6501 - if (mddev->ro != 1) 6502 - goto done_unlock; 6503 - 6504 - /* transitioning to readauto need only happen for 6505 - * arrays that call md_write_start 6506 - */ 6507 - if (mddev->pers) { 6508 - err = restart_array(mddev); 6509 - if (err == 0) { 6510 - mddev->ro = 2; 6511 - set_disk_ro(mddev->gendisk, 0); 6512 - } 6513 - } 6514 - goto done_unlock; 6514 + } 6515 + goto done_unlock; 6515 6516 } 6516 6517 6517 6518 /* ··· 6532 6535 } 6533 6536 } 6534 6537 6535 - switch (cmd) 6538 + switch (cmd) { 6539 + case ADD_NEW_DISK: 6536 6540 { 6537 - case ADD_NEW_DISK: 6538 - { 6539 - mdu_disk_info_t info; 6540 - if (copy_from_user(&info, argp, sizeof(info))) 6541 - err = -EFAULT; 6542 - else 6543 - err = add_new_disk(mddev, &info); 6544 - goto done_unlock; 6545 - } 6541 + mdu_disk_info_t info; 6542 + if (copy_from_user(&info, argp, sizeof(info))) 6543 + err = -EFAULT; 6544 + else 6545 + err = add_new_disk(mddev, &info); 6546 + goto done_unlock; 6547 + } 6546 6548 6547 - case HOT_REMOVE_DISK: 6548 - err = hot_remove_disk(mddev, new_decode_dev(arg)); 6549 - goto done_unlock; 6549 + case HOT_REMOVE_DISK: 6550 + err = hot_remove_disk(mddev, new_decode_dev(arg)); 6551 + goto done_unlock; 6550 6552 6551 - case HOT_ADD_DISK: 6552 - err = hot_add_disk(mddev, new_decode_dev(arg)); 6553 - goto done_unlock; 6553 + case HOT_ADD_DISK: 6554 + err = hot_add_disk(mddev, new_decode_dev(arg)); 6555 + goto done_unlock; 6554 6556 6555 - case RUN_ARRAY: 6556 - err = do_md_run(mddev); 6557 - goto done_unlock; 6557 + case RUN_ARRAY: 6558 + err = do_md_run(mddev); 6559 + goto done_unlock; 6558 6560 6559 - case SET_BITMAP_FILE: 6560 - err = set_bitmap_file(mddev, (int)arg); 6561 - goto done_unlock; 6561 + case SET_BITMAP_FILE: 6562 + err = set_bitmap_file(mddev, (int)arg); 6563 + goto done_unlock; 6562 6564 6563 - default: 6564 - err = -EINVAL; 6565 - goto abort_unlock; 6565 + default: 6566 + err = -EINVAL; 6567 + goto abort_unlock; 6566 6568 } 6567 6569 6568 6570 done_unlock: ··· 7180 7184 wake_up(&mddev->recovery_wait); 7181 7185 if (!ok) { 7182 7186 set_bit(MD_RECOVERY_INTR, &mddev->recovery); 7187 + set_bit(MD_RECOVERY_ERROR, &mddev->recovery); 7183 7188 md_wakeup_thread(mddev->thread); 7184 7189 // stop recovery, signal do_sync .... 7185 7190 } ··· 7278 7281 7279 7282 #define SYNC_MARKS 10 7280 7283 #define SYNC_MARK_STEP (3*HZ) 7284 + #define UPDATE_FREQUENCY (5*60*HZ) 7281 7285 void md_do_sync(struct md_thread *thread) 7282 7286 { 7283 7287 struct mddev *mddev = thread->mddev; ··· 7287 7289 window; 7288 7290 sector_t max_sectors,j, io_sectors; 7289 7291 unsigned long mark[SYNC_MARKS]; 7292 + unsigned long update_time; 7290 7293 sector_t mark_cnt[SYNC_MARKS]; 7291 7294 int last_mark,m; 7292 7295 struct list_head *tmp; ··· 7447 7448 mddev->curr_resync_completed = j; 7448 7449 sysfs_notify(&mddev->kobj, NULL, "sync_completed"); 7449 7450 md_new_event(mddev); 7451 + update_time = jiffies; 7450 7452 7451 7453 blk_start_plug(&plug); 7452 7454 while (j < max_sectors) { ··· 7459 7459 ((mddev->curr_resync > mddev->curr_resync_completed && 7460 7460 (mddev->curr_resync - mddev->curr_resync_completed) 7461 7461 > (max_sectors >> 4)) || 7462 + time_after_eq(jiffies, update_time + UPDATE_FREQUENCY) || 7462 7463 (j - mddev->curr_resync_completed)*2 7463 7464 >= mddev->resync_max - mddev->curr_resync_completed 7464 7465 )) { ··· 7467 7466 wait_event(mddev->recovery_wait, 7468 7467 atomic_read(&mddev->recovery_active) == 0); 7469 7468 mddev->curr_resync_completed = j; 7469 + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && 7470 + j > mddev->recovery_cp) 7471 + mddev->recovery_cp = j; 7472 + update_time = jiffies; 7470 7473 set_bit(MD_CHANGE_CLEAN, &mddev->flags); 7471 7474 sysfs_notify(&mddev->kobj, NULL, "sync_completed"); 7472 7475 } ··· 7575 7570 printk(KERN_INFO 7576 7571 "md: checkpointing %s of %s.\n", 7577 7572 desc, mdname(mddev)); 7578 - mddev->recovery_cp = 7579 - mddev->curr_resync_completed; 7573 + if (test_bit(MD_RECOVERY_ERROR, 7574 + &mddev->recovery)) 7575 + mddev->recovery_cp = 7576 + mddev->curr_resync_completed; 7577 + else 7578 + mddev->recovery_cp = 7579 + mddev->curr_resync; 7580 7580 } 7581 7581 } else 7582 7582 mddev->recovery_cp = MaxSector;
+2
drivers/md/md.h
··· 307 307 * REQUEST: user-space has requested a sync (used with SYNC) 308 308 * CHECK: user-space request for check-only, no repair 309 309 * RESHAPE: A reshape is happening 310 + * ERROR: sync-action interrupted because io-error 310 311 * 311 312 * If neither SYNC or RESHAPE are set, then it is a recovery. 312 313 */ ··· 321 320 #define MD_RECOVERY_CHECK 7 322 321 #define MD_RECOVERY_RESHAPE 8 323 322 #define MD_RECOVERY_FROZEN 9 323 + #define MD_RECOVERY_ERROR 10 324 324 325 325 unsigned long recovery; 326 326 /* If a RAID personality determines that recovery (of a particular
+36 -7
drivers/md/raid5.c
··· 53 53 #include <linux/cpu.h> 54 54 #include <linux/slab.h> 55 55 #include <linux/ratelimit.h> 56 + #include <trace/events/block.h> 57 + 56 58 #include "md.h" 57 59 #include "raid5.h" 58 60 #include "raid0.h" ··· 184 182 return_bi = bi->bi_next; 185 183 bi->bi_next = NULL; 186 184 bi->bi_size = 0; 185 + trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), 186 + bi, 0); 187 187 bio_endio(bi, 0); 188 188 bi = return_bi; 189 189 } ··· 674 670 bi->bi_next = NULL; 675 671 if (rrdev) 676 672 set_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags); 673 + trace_block_bio_remap(bdev_get_queue(bi->bi_bdev), 674 + bi, disk_devt(conf->mddev->gendisk), 675 + sh->dev[i].sector); 677 676 generic_make_request(bi); 678 677 } 679 678 if (rrdev) { ··· 704 697 rbi->bi_io_vec[0].bv_offset = 0; 705 698 rbi->bi_size = STRIPE_SIZE; 706 699 rbi->bi_next = NULL; 700 + trace_block_bio_remap(bdev_get_queue(rbi->bi_bdev), 701 + rbi, disk_devt(conf->mddev->gendisk), 702 + sh->dev[i].sector); 707 703 generic_make_request(rbi); 708 704 } 709 705 if (!rdev && !rrdev) { ··· 2863 2853 pr_debug("for sector %llu, rmw=%d rcw=%d\n", 2864 2854 (unsigned long long)sh->sector, rmw, rcw); 2865 2855 set_bit(STRIPE_HANDLE, &sh->state); 2866 - if (rmw < rcw && rmw > 0) 2856 + if (rmw < rcw && rmw > 0) { 2867 2857 /* prefer read-modify-write, but need to get some data */ 2858 + blk_add_trace_msg(conf->mddev->queue, "raid5 rmw %llu %d", 2859 + (unsigned long long)sh->sector, rmw); 2868 2860 for (i = disks; i--; ) { 2869 2861 struct r5dev *dev = &sh->dev[i]; 2870 2862 if ((dev->towrite || i == sh->pd_idx) && ··· 2877 2865 if ( 2878 2866 test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { 2879 2867 pr_debug("Read_old block " 2880 - "%d for r-m-w\n", i); 2868 + "%d for r-m-w\n", i); 2881 2869 set_bit(R5_LOCKED, &dev->flags); 2882 2870 set_bit(R5_Wantread, &dev->flags); 2883 2871 s->locked++; ··· 2887 2875 } 2888 2876 } 2889 2877 } 2878 + } 2890 2879 if (rcw <= rmw && rcw > 0) { 2891 2880 /* want reconstruct write, but need to get some data */ 2881 + int qread =0; 2892 2882 rcw = 0; 2893 2883 for (i = disks; i--; ) { 2894 2884 struct r5dev *dev = &sh->dev[i]; ··· 2909 2895 set_bit(R5_LOCKED, &dev->flags); 2910 2896 set_bit(R5_Wantread, &dev->flags); 2911 2897 s->locked++; 2898 + qread++; 2912 2899 } else { 2913 2900 set_bit(STRIPE_DELAYED, &sh->state); 2914 2901 set_bit(STRIPE_HANDLE, &sh->state); 2915 2902 } 2916 2903 } 2917 2904 } 2905 + if (rcw) 2906 + blk_add_trace_msg(conf->mddev->queue, "raid5 rcw %llu %d %d %d", 2907 + (unsigned long long)sh->sector, 2908 + rcw, qread, test_bit(STRIPE_DELAYED, &sh->state)); 2918 2909 } 2919 2910 /* now if nothing is locked, and if we have enough data, 2920 2911 * we can start a write request ··· 3241 3222 3242 3223 } 3243 3224 /* done submitting copies, wait for them to complete */ 3244 - if (tx) { 3245 - async_tx_ack(tx); 3246 - dma_wait_for_async_tx(tx); 3247 - } 3225 + async_tx_quiesce(&tx); 3248 3226 } 3249 3227 3250 3228 /* ··· 3917 3901 rdev_dec_pending(rdev, conf->mddev); 3918 3902 3919 3903 if (!error && uptodate) { 3904 + trace_block_bio_complete(bdev_get_queue(raid_bi->bi_bdev), 3905 + raid_bi, 0); 3920 3906 bio_endio(raid_bi, 0); 3921 3907 if (atomic_dec_and_test(&conf->active_aligned_reads)) 3922 3908 wake_up(&conf->wait_for_stripe); ··· 4023 4005 atomic_inc(&conf->active_aligned_reads); 4024 4006 spin_unlock_irq(&conf->device_lock); 4025 4007 4008 + trace_block_bio_remap(bdev_get_queue(align_bi->bi_bdev), 4009 + align_bi, disk_devt(mddev->gendisk), 4010 + raid_bio->bi_sector); 4026 4011 generic_make_request(align_bi); 4027 4012 return 1; 4028 4013 } else { ··· 4100 4079 struct stripe_head *sh; 4101 4080 struct mddev *mddev = cb->cb.data; 4102 4081 struct r5conf *conf = mddev->private; 4082 + int cnt = 0; 4103 4083 4104 4084 if (cb->list.next && !list_empty(&cb->list)) { 4105 4085 spin_lock_irq(&conf->device_lock); ··· 4115 4093 smp_mb__before_clear_bit(); 4116 4094 clear_bit(STRIPE_ON_UNPLUG_LIST, &sh->state); 4117 4095 __release_stripe(conf, sh); 4096 + cnt++; 4118 4097 } 4119 4098 spin_unlock_irq(&conf->device_lock); 4120 4099 } 4100 + trace_block_unplug(mddev->queue, cnt, !from_schedule); 4121 4101 kfree(cb); 4122 4102 } 4123 4103 ··· 4377 4353 if ( rw == WRITE ) 4378 4354 md_write_end(mddev); 4379 4355 4356 + trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), 4357 + bi, 0); 4380 4358 bio_endio(bi, 0); 4381 4359 } 4382 4360 } ··· 4755 4729 handled++; 4756 4730 } 4757 4731 remaining = raid5_dec_bi_active_stripes(raid_bio); 4758 - if (remaining == 0) 4732 + if (remaining == 0) { 4733 + trace_block_bio_complete(bdev_get_queue(raid_bio->bi_bdev), 4734 + raid_bio, 0); 4759 4735 bio_endio(raid_bio, 0); 4736 + } 4760 4737 if (atomic_dec_and_test(&conf->active_aligned_reads)) 4761 4738 wake_up(&conf->wait_for_stripe); 4762 4739 return handled;
+4
include/linux/raid/pq.h
··· 98 98 extern const struct raid6_calls raid6_altivec2; 99 99 extern const struct raid6_calls raid6_altivec4; 100 100 extern const struct raid6_calls raid6_altivec8; 101 + extern const struct raid6_calls raid6_avx2x1; 102 + extern const struct raid6_calls raid6_avx2x2; 103 + extern const struct raid6_calls raid6_avx2x4; 101 104 102 105 struct raid6_recov_calls { 103 106 void (*data2)(int, size_t, int, int, void **); ··· 112 109 113 110 extern const struct raid6_recov_calls raid6_recov_intx1; 114 111 extern const struct raid6_recov_calls raid6_recov_ssse3; 112 + extern const struct raid6_recov_calls raid6_recov_avx2; 115 113 116 114 /* Algorithm list */ 117 115 extern const struct raid6_calls * const raid6_algos[];
+6 -3
lib/raid6/Makefile
··· 1 1 obj-$(CONFIG_RAID6_PQ) += raid6_pq.o 2 2 3 - raid6_pq-y += algos.o recov.o recov_ssse3.o tables.o int1.o int2.o int4.o \ 4 - int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \ 5 - altivec8.o mmx.o sse1.o sse2.o 3 + raid6_pq-y += algos.o recov.o tables.o int1.o int2.o int4.o \ 4 + int8.o int16.o int32.o 5 + 6 + raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o 7 + raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o 8 + 6 9 hostprogs-y += mktables 7 10 8 11 quiet_cmd_unroll = UNROLL $@
+12
lib/raid6/algos.c
··· 45 45 &raid6_sse1x2, 46 46 &raid6_sse2x1, 47 47 &raid6_sse2x2, 48 + #ifdef CONFIG_AS_AVX2 49 + &raid6_avx2x1, 50 + &raid6_avx2x2, 51 + #endif 48 52 #endif 49 53 #if defined(__x86_64__) && !defined(__arch_um__) 50 54 &raid6_sse2x1, 51 55 &raid6_sse2x2, 52 56 &raid6_sse2x4, 57 + #ifdef CONFIG_AS_AVX2 58 + &raid6_avx2x1, 59 + &raid6_avx2x2, 60 + &raid6_avx2x4, 61 + #endif 53 62 #endif 54 63 #ifdef CONFIG_ALTIVEC 55 64 &raid6_altivec1, ··· 81 72 82 73 const struct raid6_recov_calls *const raid6_recov_algos[] = { 83 74 #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) 75 + #ifdef CONFIG_AS_AVX2 76 + &raid6_recov_avx2, 77 + #endif 84 78 &raid6_recov_ssse3, 85 79 #endif 86 80 &raid6_recov_intx1,
-3
lib/raid6/altivec.uc
··· 24 24 25 25 #include <linux/raid/pq.h> 26 26 27 - #ifdef CONFIG_ALTIVEC 28 - 29 27 #include <altivec.h> 30 28 #ifdef __KERNEL__ 31 29 # include <asm/cputable.h> 32 30 # include <asm/switch_to.h> 33 - #endif 34 31 35 32 /* 36 33 * This is the C data type to use. We use a vector of
+251
lib/raid6/avx2.c
··· 1 + /* -*- linux-c -*- ------------------------------------------------------- * 2 + * 3 + * Copyright (C) 2012 Intel Corporation 4 + * Author: Yuanhan Liu <yuanhan.liu@linux.intel.com> 5 + * 6 + * Based on sse2.c: Copyright 2002 H. Peter Anvin - All Rights Reserved 7 + * 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 12 + * Boston MA 02111-1307, USA; either version 2 of the License, or 13 + * (at your option) any later version; incorporated herein by reference. 14 + * 15 + * ----------------------------------------------------------------------- */ 16 + 17 + /* 18 + * AVX2 implementation of RAID-6 syndrome functions 19 + * 20 + */ 21 + 22 + #ifdef CONFIG_AS_AVX2 23 + 24 + #include <linux/raid/pq.h> 25 + #include "x86.h" 26 + 27 + static const struct raid6_avx2_constants { 28 + u64 x1d[4]; 29 + } raid6_avx2_constants __aligned(32) = { 30 + { 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL, 31 + 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,}, 32 + }; 33 + 34 + static int raid6_have_avx2(void) 35 + { 36 + return boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_AVX); 37 + } 38 + 39 + /* 40 + * Plain AVX2 implementation 41 + */ 42 + static void raid6_avx21_gen_syndrome(int disks, size_t bytes, void **ptrs) 43 + { 44 + u8 **dptr = (u8 **)ptrs; 45 + u8 *p, *q; 46 + int d, z, z0; 47 + 48 + z0 = disks - 3; /* Highest data disk */ 49 + p = dptr[z0+1]; /* XOR parity */ 50 + q = dptr[z0+2]; /* RS syndrome */ 51 + 52 + kernel_fpu_begin(); 53 + 54 + asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0])); 55 + asm volatile("vpxor %ymm3,%ymm3,%ymm3"); /* Zero temp */ 56 + 57 + for (d = 0; d < bytes; d += 32) { 58 + asm volatile("prefetchnta %0" : : "m" (dptr[z0][d])); 59 + asm volatile("vmovdqa %0,%%ymm2" : : "m" (dptr[z0][d]));/* P[0] */ 60 + asm volatile("prefetchnta %0" : : "m" (dptr[z0-1][d])); 61 + asm volatile("vmovdqa %ymm2,%ymm4");/* Q[0] */ 62 + asm volatile("vmovdqa %0,%%ymm6" : : "m" (dptr[z0-1][d])); 63 + for (z = z0-2; z >= 0; z--) { 64 + asm volatile("prefetchnta %0" : : "m" (dptr[z][d])); 65 + asm volatile("vpcmpgtb %ymm4,%ymm3,%ymm5"); 66 + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); 67 + asm volatile("vpand %ymm0,%ymm5,%ymm5"); 68 + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); 69 + asm volatile("vpxor %ymm6,%ymm2,%ymm2"); 70 + asm volatile("vpxor %ymm6,%ymm4,%ymm4"); 71 + asm volatile("vmovdqa %0,%%ymm6" : : "m" (dptr[z][d])); 72 + } 73 + asm volatile("vpcmpgtb %ymm4,%ymm3,%ymm5"); 74 + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); 75 + asm volatile("vpand %ymm0,%ymm5,%ymm5"); 76 + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); 77 + asm volatile("vpxor %ymm6,%ymm2,%ymm2"); 78 + asm volatile("vpxor %ymm6,%ymm4,%ymm4"); 79 + 80 + asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d])); 81 + asm volatile("vpxor %ymm2,%ymm2,%ymm2"); 82 + asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d])); 83 + asm volatile("vpxor %ymm4,%ymm4,%ymm4"); 84 + } 85 + 86 + asm volatile("sfence" : : : "memory"); 87 + kernel_fpu_end(); 88 + } 89 + 90 + const struct raid6_calls raid6_avx2x1 = { 91 + raid6_avx21_gen_syndrome, 92 + raid6_have_avx2, 93 + "avx2x1", 94 + 1 /* Has cache hints */ 95 + }; 96 + 97 + /* 98 + * Unrolled-by-2 AVX2 implementation 99 + */ 100 + static void raid6_avx22_gen_syndrome(int disks, size_t bytes, void **ptrs) 101 + { 102 + u8 **dptr = (u8 **)ptrs; 103 + u8 *p, *q; 104 + int d, z, z0; 105 + 106 + z0 = disks - 3; /* Highest data disk */ 107 + p = dptr[z0+1]; /* XOR parity */ 108 + q = dptr[z0+2]; /* RS syndrome */ 109 + 110 + kernel_fpu_begin(); 111 + 112 + asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0])); 113 + asm volatile("vpxor %ymm1,%ymm1,%ymm1"); /* Zero temp */ 114 + 115 + /* We uniformly assume a single prefetch covers at least 32 bytes */ 116 + for (d = 0; d < bytes; d += 64) { 117 + asm volatile("prefetchnta %0" : : "m" (dptr[z0][d])); 118 + asm volatile("prefetchnta %0" : : "m" (dptr[z0][d+32])); 119 + asm volatile("vmovdqa %0,%%ymm2" : : "m" (dptr[z0][d]));/* P[0] */ 120 + asm volatile("vmovdqa %0,%%ymm3" : : "m" (dptr[z0][d+32]));/* P[1] */ 121 + asm volatile("vmovdqa %ymm2,%ymm4"); /* Q[0] */ 122 + asm volatile("vmovdqa %ymm3,%ymm6"); /* Q[1] */ 123 + for (z = z0-1; z >= 0; z--) { 124 + asm volatile("prefetchnta %0" : : "m" (dptr[z][d])); 125 + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+32])); 126 + asm volatile("vpcmpgtb %ymm4,%ymm1,%ymm5"); 127 + asm volatile("vpcmpgtb %ymm6,%ymm1,%ymm7"); 128 + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); 129 + asm volatile("vpaddb %ymm6,%ymm6,%ymm6"); 130 + asm volatile("vpand %ymm0,%ymm5,%ymm5"); 131 + asm volatile("vpand %ymm0,%ymm7,%ymm7"); 132 + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); 133 + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); 134 + asm volatile("vmovdqa %0,%%ymm5" : : "m" (dptr[z][d])); 135 + asm volatile("vmovdqa %0,%%ymm7" : : "m" (dptr[z][d+32])); 136 + asm volatile("vpxor %ymm5,%ymm2,%ymm2"); 137 + asm volatile("vpxor %ymm7,%ymm3,%ymm3"); 138 + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); 139 + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); 140 + } 141 + asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d])); 142 + asm volatile("vmovntdq %%ymm3,%0" : "=m" (p[d+32])); 143 + asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d])); 144 + asm volatile("vmovntdq %%ymm6,%0" : "=m" (q[d+32])); 145 + } 146 + 147 + asm volatile("sfence" : : : "memory"); 148 + kernel_fpu_end(); 149 + } 150 + 151 + const struct raid6_calls raid6_avx2x2 = { 152 + raid6_avx22_gen_syndrome, 153 + raid6_have_avx2, 154 + "avx2x2", 155 + 1 /* Has cache hints */ 156 + }; 157 + 158 + #ifdef CONFIG_X86_64 159 + 160 + /* 161 + * Unrolled-by-4 AVX2 implementation 162 + */ 163 + static void raid6_avx24_gen_syndrome(int disks, size_t bytes, void **ptrs) 164 + { 165 + u8 **dptr = (u8 **)ptrs; 166 + u8 *p, *q; 167 + int d, z, z0; 168 + 169 + z0 = disks - 3; /* Highest data disk */ 170 + p = dptr[z0+1]; /* XOR parity */ 171 + q = dptr[z0+2]; /* RS syndrome */ 172 + 173 + kernel_fpu_begin(); 174 + 175 + asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0])); 176 + asm volatile("vpxor %ymm1,%ymm1,%ymm1"); /* Zero temp */ 177 + asm volatile("vpxor %ymm2,%ymm2,%ymm2"); /* P[0] */ 178 + asm volatile("vpxor %ymm3,%ymm3,%ymm3"); /* P[1] */ 179 + asm volatile("vpxor %ymm4,%ymm4,%ymm4"); /* Q[0] */ 180 + asm volatile("vpxor %ymm6,%ymm6,%ymm6"); /* Q[1] */ 181 + asm volatile("vpxor %ymm10,%ymm10,%ymm10"); /* P[2] */ 182 + asm volatile("vpxor %ymm11,%ymm11,%ymm11"); /* P[3] */ 183 + asm volatile("vpxor %ymm12,%ymm12,%ymm12"); /* Q[2] */ 184 + asm volatile("vpxor %ymm14,%ymm14,%ymm14"); /* Q[3] */ 185 + 186 + for (d = 0; d < bytes; d += 128) { 187 + for (z = z0; z >= 0; z--) { 188 + asm volatile("prefetchnta %0" : : "m" (dptr[z][d])); 189 + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+32])); 190 + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+64])); 191 + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+96])); 192 + asm volatile("vpcmpgtb %ymm4,%ymm1,%ymm5"); 193 + asm volatile("vpcmpgtb %ymm6,%ymm1,%ymm7"); 194 + asm volatile("vpcmpgtb %ymm12,%ymm1,%ymm13"); 195 + asm volatile("vpcmpgtb %ymm14,%ymm1,%ymm15"); 196 + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); 197 + asm volatile("vpaddb %ymm6,%ymm6,%ymm6"); 198 + asm volatile("vpaddb %ymm12,%ymm12,%ymm12"); 199 + asm volatile("vpaddb %ymm14,%ymm14,%ymm14"); 200 + asm volatile("vpand %ymm0,%ymm5,%ymm5"); 201 + asm volatile("vpand %ymm0,%ymm7,%ymm7"); 202 + asm volatile("vpand %ymm0,%ymm13,%ymm13"); 203 + asm volatile("vpand %ymm0,%ymm15,%ymm15"); 204 + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); 205 + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); 206 + asm volatile("vpxor %ymm13,%ymm12,%ymm12"); 207 + asm volatile("vpxor %ymm15,%ymm14,%ymm14"); 208 + asm volatile("vmovdqa %0,%%ymm5" : : "m" (dptr[z][d])); 209 + asm volatile("vmovdqa %0,%%ymm7" : : "m" (dptr[z][d+32])); 210 + asm volatile("vmovdqa %0,%%ymm13" : : "m" (dptr[z][d+64])); 211 + asm volatile("vmovdqa %0,%%ymm15" : : "m" (dptr[z][d+96])); 212 + asm volatile("vpxor %ymm5,%ymm2,%ymm2"); 213 + asm volatile("vpxor %ymm7,%ymm3,%ymm3"); 214 + asm volatile("vpxor %ymm13,%ymm10,%ymm10"); 215 + asm volatile("vpxor %ymm15,%ymm11,%ymm11"); 216 + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); 217 + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); 218 + asm volatile("vpxor %ymm13,%ymm12,%ymm12"); 219 + asm volatile("vpxor %ymm15,%ymm14,%ymm14"); 220 + } 221 + asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d])); 222 + asm volatile("vpxor %ymm2,%ymm2,%ymm2"); 223 + asm volatile("vmovntdq %%ymm3,%0" : "=m" (p[d+32])); 224 + asm volatile("vpxor %ymm3,%ymm3,%ymm3"); 225 + asm volatile("vmovntdq %%ymm10,%0" : "=m" (p[d+64])); 226 + asm volatile("vpxor %ymm10,%ymm10,%ymm10"); 227 + asm volatile("vmovntdq %%ymm11,%0" : "=m" (p[d+96])); 228 + asm volatile("vpxor %ymm11,%ymm11,%ymm11"); 229 + asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d])); 230 + asm volatile("vpxor %ymm4,%ymm4,%ymm4"); 231 + asm volatile("vmovntdq %%ymm6,%0" : "=m" (q[d+32])); 232 + asm volatile("vpxor %ymm6,%ymm6,%ymm6"); 233 + asm volatile("vmovntdq %%ymm12,%0" : "=m" (q[d+64])); 234 + asm volatile("vpxor %ymm12,%ymm12,%ymm12"); 235 + asm volatile("vmovntdq %%ymm14,%0" : "=m" (q[d+96])); 236 + asm volatile("vpxor %ymm14,%ymm14,%ymm14"); 237 + } 238 + 239 + asm volatile("sfence" : : : "memory"); 240 + kernel_fpu_end(); 241 + } 242 + 243 + const struct raid6_calls raid6_avx2x4 = { 244 + raid6_avx24_gen_syndrome, 245 + raid6_have_avx2, 246 + "avx2x4", 247 + 1 /* Has cache hints */ 248 + }; 249 + #endif 250 + 251 + #endif /* CONFIG_AS_AVX2 */
+1 -1
lib/raid6/mmx.c
··· 16 16 * MMX implementation of RAID-6 syndrome functions 17 17 */ 18 18 19 - #if defined(__i386__) && !defined(__arch_um__) 19 + #ifdef CONFIG_X86_32 20 20 21 21 #include <linux/raid/pq.h> 22 22 #include "x86.h"
+323
lib/raid6/recov_avx2.c
··· 1 + /* 2 + * Copyright (C) 2012 Intel Corporation 3 + * Author: Jim Kukunas <james.t.kukunas@linux.intel.com> 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify it under the terms of the GNU General Public License 7 + * as published by the Free Software Foundation; version 2 8 + * of the License. 9 + */ 10 + 11 + #if CONFIG_AS_AVX2 12 + 13 + #include <linux/raid/pq.h> 14 + #include "x86.h" 15 + 16 + static int raid6_has_avx2(void) 17 + { 18 + return boot_cpu_has(X86_FEATURE_AVX2) && 19 + boot_cpu_has(X86_FEATURE_AVX); 20 + } 21 + 22 + static void raid6_2data_recov_avx2(int disks, size_t bytes, int faila, 23 + int failb, void **ptrs) 24 + { 25 + u8 *p, *q, *dp, *dq; 26 + const u8 *pbmul; /* P multiplier table for B data */ 27 + const u8 *qmul; /* Q multiplier table (for both) */ 28 + const u8 x0f = 0x0f; 29 + 30 + p = (u8 *)ptrs[disks-2]; 31 + q = (u8 *)ptrs[disks-1]; 32 + 33 + /* Compute syndrome with zero for the missing data pages 34 + Use the dead data pages as temporary storage for 35 + delta p and delta q */ 36 + dp = (u8 *)ptrs[faila]; 37 + ptrs[faila] = (void *)raid6_empty_zero_page; 38 + ptrs[disks-2] = dp; 39 + dq = (u8 *)ptrs[failb]; 40 + ptrs[failb] = (void *)raid6_empty_zero_page; 41 + ptrs[disks-1] = dq; 42 + 43 + raid6_call.gen_syndrome(disks, bytes, ptrs); 44 + 45 + /* Restore pointer table */ 46 + ptrs[faila] = dp; 47 + ptrs[failb] = dq; 48 + ptrs[disks-2] = p; 49 + ptrs[disks-1] = q; 50 + 51 + /* Now, pick the proper data tables */ 52 + pbmul = raid6_vgfmul[raid6_gfexi[failb-faila]]; 53 + qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^ 54 + raid6_gfexp[failb]]]; 55 + 56 + kernel_fpu_begin(); 57 + 58 + /* ymm0 = x0f[16] */ 59 + asm volatile("vpbroadcastb %0, %%ymm7" : : "m" (x0f)); 60 + 61 + while (bytes) { 62 + #ifdef CONFIG_X86_64 63 + asm volatile("vmovdqa %0, %%ymm1" : : "m" (q[0])); 64 + asm volatile("vmovdqa %0, %%ymm9" : : "m" (q[32])); 65 + asm volatile("vmovdqa %0, %%ymm0" : : "m" (p[0])); 66 + asm volatile("vmovdqa %0, %%ymm8" : : "m" (p[32])); 67 + asm volatile("vpxor %0, %%ymm1, %%ymm1" : : "m" (dq[0])); 68 + asm volatile("vpxor %0, %%ymm9, %%ymm9" : : "m" (dq[32])); 69 + asm volatile("vpxor %0, %%ymm0, %%ymm0" : : "m" (dp[0])); 70 + asm volatile("vpxor %0, %%ymm8, %%ymm8" : : "m" (dp[32])); 71 + 72 + /* 73 + * 1 = dq[0] ^ q[0] 74 + * 9 = dq[32] ^ q[32] 75 + * 0 = dp[0] ^ p[0] 76 + * 8 = dp[32] ^ p[32] 77 + */ 78 + 79 + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (qmul[0])); 80 + asm volatile("vbroadcasti128 %0, %%ymm5" : : "m" (qmul[16])); 81 + 82 + asm volatile("vpsraw $4, %ymm1, %ymm3"); 83 + asm volatile("vpsraw $4, %ymm9, %ymm12"); 84 + asm volatile("vpand %ymm7, %ymm1, %ymm1"); 85 + asm volatile("vpand %ymm7, %ymm9, %ymm9"); 86 + asm volatile("vpand %ymm7, %ymm3, %ymm3"); 87 + asm volatile("vpand %ymm7, %ymm12, %ymm12"); 88 + asm volatile("vpshufb %ymm9, %ymm4, %ymm14"); 89 + asm volatile("vpshufb %ymm1, %ymm4, %ymm4"); 90 + asm volatile("vpshufb %ymm12, %ymm5, %ymm15"); 91 + asm volatile("vpshufb %ymm3, %ymm5, %ymm5"); 92 + asm volatile("vpxor %ymm14, %ymm15, %ymm15"); 93 + asm volatile("vpxor %ymm4, %ymm5, %ymm5"); 94 + 95 + /* 96 + * 5 = qx[0] 97 + * 15 = qx[32] 98 + */ 99 + 100 + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (pbmul[0])); 101 + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (pbmul[16])); 102 + asm volatile("vpsraw $4, %ymm0, %ymm2"); 103 + asm volatile("vpsraw $4, %ymm8, %ymm6"); 104 + asm volatile("vpand %ymm7, %ymm0, %ymm3"); 105 + asm volatile("vpand %ymm7, %ymm8, %ymm14"); 106 + asm volatile("vpand %ymm7, %ymm2, %ymm2"); 107 + asm volatile("vpand %ymm7, %ymm6, %ymm6"); 108 + asm volatile("vpshufb %ymm14, %ymm4, %ymm12"); 109 + asm volatile("vpshufb %ymm3, %ymm4, %ymm4"); 110 + asm volatile("vpshufb %ymm6, %ymm1, %ymm13"); 111 + asm volatile("vpshufb %ymm2, %ymm1, %ymm1"); 112 + asm volatile("vpxor %ymm4, %ymm1, %ymm1"); 113 + asm volatile("vpxor %ymm12, %ymm13, %ymm13"); 114 + 115 + /* 116 + * 1 = pbmul[px[0]] 117 + * 13 = pbmul[px[32]] 118 + */ 119 + asm volatile("vpxor %ymm5, %ymm1, %ymm1"); 120 + asm volatile("vpxor %ymm15, %ymm13, %ymm13"); 121 + 122 + /* 123 + * 1 = db = DQ 124 + * 13 = db[32] = DQ[32] 125 + */ 126 + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); 127 + asm volatile("vmovdqa %%ymm13,%0" : "=m" (dq[32])); 128 + asm volatile("vpxor %ymm1, %ymm0, %ymm0"); 129 + asm volatile("vpxor %ymm13, %ymm8, %ymm8"); 130 + 131 + asm volatile("vmovdqa %%ymm0, %0" : "=m" (dp[0])); 132 + asm volatile("vmovdqa %%ymm8, %0" : "=m" (dp[32])); 133 + 134 + bytes -= 64; 135 + p += 64; 136 + q += 64; 137 + dp += 64; 138 + dq += 64; 139 + #else 140 + asm volatile("vmovdqa %0, %%ymm1" : : "m" (*q)); 141 + asm volatile("vmovdqa %0, %%ymm0" : : "m" (*p)); 142 + asm volatile("vpxor %0, %%ymm1, %%ymm1" : : "m" (*dq)); 143 + asm volatile("vpxor %0, %%ymm0, %%ymm0" : : "m" (*dp)); 144 + 145 + /* 1 = dq ^ q; 0 = dp ^ p */ 146 + 147 + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (qmul[0])); 148 + asm volatile("vbroadcasti128 %0, %%ymm5" : : "m" (qmul[16])); 149 + 150 + /* 151 + * 1 = dq ^ q 152 + * 3 = dq ^ p >> 4 153 + */ 154 + asm volatile("vpsraw $4, %ymm1, %ymm3"); 155 + asm volatile("vpand %ymm7, %ymm1, %ymm1"); 156 + asm volatile("vpand %ymm7, %ymm3, %ymm3"); 157 + asm volatile("vpshufb %ymm1, %ymm4, %ymm4"); 158 + asm volatile("vpshufb %ymm3, %ymm5, %ymm5"); 159 + asm volatile("vpxor %ymm4, %ymm5, %ymm5"); 160 + 161 + /* 5 = qx */ 162 + 163 + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (pbmul[0])); 164 + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (pbmul[16])); 165 + 166 + asm volatile("vpsraw $4, %ymm0, %ymm2"); 167 + asm volatile("vpand %ymm7, %ymm0, %ymm3"); 168 + asm volatile("vpand %ymm7, %ymm2, %ymm2"); 169 + asm volatile("vpshufb %ymm3, %ymm4, %ymm4"); 170 + asm volatile("vpshufb %ymm2, %ymm1, %ymm1"); 171 + asm volatile("vpxor %ymm4, %ymm1, %ymm1"); 172 + 173 + /* 1 = pbmul[px] */ 174 + asm volatile("vpxor %ymm5, %ymm1, %ymm1"); 175 + /* 1 = db = DQ */ 176 + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); 177 + 178 + asm volatile("vpxor %ymm1, %ymm0, %ymm0"); 179 + asm volatile("vmovdqa %%ymm0, %0" : "=m" (dp[0])); 180 + 181 + bytes -= 32; 182 + p += 32; 183 + q += 32; 184 + dp += 32; 185 + dq += 32; 186 + #endif 187 + } 188 + 189 + kernel_fpu_end(); 190 + } 191 + 192 + static void raid6_datap_recov_avx2(int disks, size_t bytes, int faila, 193 + void **ptrs) 194 + { 195 + u8 *p, *q, *dq; 196 + const u8 *qmul; /* Q multiplier table */ 197 + const u8 x0f = 0x0f; 198 + 199 + p = (u8 *)ptrs[disks-2]; 200 + q = (u8 *)ptrs[disks-1]; 201 + 202 + /* Compute syndrome with zero for the missing data page 203 + Use the dead data page as temporary storage for delta q */ 204 + dq = (u8 *)ptrs[faila]; 205 + ptrs[faila] = (void *)raid6_empty_zero_page; 206 + ptrs[disks-1] = dq; 207 + 208 + raid6_call.gen_syndrome(disks, bytes, ptrs); 209 + 210 + /* Restore pointer table */ 211 + ptrs[faila] = dq; 212 + ptrs[disks-1] = q; 213 + 214 + /* Now, pick the proper data tables */ 215 + qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]]; 216 + 217 + kernel_fpu_begin(); 218 + 219 + asm volatile("vpbroadcastb %0, %%ymm7" : : "m" (x0f)); 220 + 221 + while (bytes) { 222 + #ifdef CONFIG_X86_64 223 + asm volatile("vmovdqa %0, %%ymm3" : : "m" (dq[0])); 224 + asm volatile("vmovdqa %0, %%ymm8" : : "m" (dq[32])); 225 + asm volatile("vpxor %0, %%ymm3, %%ymm3" : : "m" (q[0])); 226 + asm volatile("vpxor %0, %%ymm8, %%ymm8" : : "m" (q[32])); 227 + 228 + /* 229 + * 3 = q[0] ^ dq[0] 230 + * 8 = q[32] ^ dq[32] 231 + */ 232 + asm volatile("vbroadcasti128 %0, %%ymm0" : : "m" (qmul[0])); 233 + asm volatile("vmovapd %ymm0, %ymm13"); 234 + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (qmul[16])); 235 + asm volatile("vmovapd %ymm1, %ymm14"); 236 + 237 + asm volatile("vpsraw $4, %ymm3, %ymm6"); 238 + asm volatile("vpsraw $4, %ymm8, %ymm12"); 239 + asm volatile("vpand %ymm7, %ymm3, %ymm3"); 240 + asm volatile("vpand %ymm7, %ymm8, %ymm8"); 241 + asm volatile("vpand %ymm7, %ymm6, %ymm6"); 242 + asm volatile("vpand %ymm7, %ymm12, %ymm12"); 243 + asm volatile("vpshufb %ymm3, %ymm0, %ymm0"); 244 + asm volatile("vpshufb %ymm8, %ymm13, %ymm13"); 245 + asm volatile("vpshufb %ymm6, %ymm1, %ymm1"); 246 + asm volatile("vpshufb %ymm12, %ymm14, %ymm14"); 247 + asm volatile("vpxor %ymm0, %ymm1, %ymm1"); 248 + asm volatile("vpxor %ymm13, %ymm14, %ymm14"); 249 + 250 + /* 251 + * 1 = qmul[q[0] ^ dq[0]] 252 + * 14 = qmul[q[32] ^ dq[32]] 253 + */ 254 + asm volatile("vmovdqa %0, %%ymm2" : : "m" (p[0])); 255 + asm volatile("vmovdqa %0, %%ymm12" : : "m" (p[32])); 256 + asm volatile("vpxor %ymm1, %ymm2, %ymm2"); 257 + asm volatile("vpxor %ymm14, %ymm12, %ymm12"); 258 + 259 + /* 260 + * 2 = p[0] ^ qmul[q[0] ^ dq[0]] 261 + * 12 = p[32] ^ qmul[q[32] ^ dq[32]] 262 + */ 263 + 264 + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); 265 + asm volatile("vmovdqa %%ymm14, %0" : "=m" (dq[32])); 266 + asm volatile("vmovdqa %%ymm2, %0" : "=m" (p[0])); 267 + asm volatile("vmovdqa %%ymm12,%0" : "=m" (p[32])); 268 + 269 + bytes -= 64; 270 + p += 64; 271 + q += 64; 272 + dq += 64; 273 + #else 274 + asm volatile("vmovdqa %0, %%ymm3" : : "m" (dq[0])); 275 + asm volatile("vpxor %0, %%ymm3, %%ymm3" : : "m" (q[0])); 276 + 277 + /* 3 = q ^ dq */ 278 + 279 + asm volatile("vbroadcasti128 %0, %%ymm0" : : "m" (qmul[0])); 280 + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (qmul[16])); 281 + 282 + asm volatile("vpsraw $4, %ymm3, %ymm6"); 283 + asm volatile("vpand %ymm7, %ymm3, %ymm3"); 284 + asm volatile("vpand %ymm7, %ymm6, %ymm6"); 285 + asm volatile("vpshufb %ymm3, %ymm0, %ymm0"); 286 + asm volatile("vpshufb %ymm6, %ymm1, %ymm1"); 287 + asm volatile("vpxor %ymm0, %ymm1, %ymm1"); 288 + 289 + /* 1 = qmul[q ^ dq] */ 290 + 291 + asm volatile("vmovdqa %0, %%ymm2" : : "m" (p[0])); 292 + asm volatile("vpxor %ymm1, %ymm2, %ymm2"); 293 + 294 + /* 2 = p ^ qmul[q ^ dq] */ 295 + 296 + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); 297 + asm volatile("vmovdqa %%ymm2, %0" : "=m" (p[0])); 298 + 299 + bytes -= 32; 300 + p += 32; 301 + q += 32; 302 + dq += 32; 303 + #endif 304 + } 305 + 306 + kernel_fpu_end(); 307 + } 308 + 309 + const struct raid6_recov_calls raid6_recov_avx2 = { 310 + .data2 = raid6_2data_recov_avx2, 311 + .datap = raid6_datap_recov_avx2, 312 + .valid = raid6_has_avx2, 313 + #ifdef CONFIG_X86_64 314 + .name = "avx2x2", 315 + #else 316 + .name = "avx2x1", 317 + #endif 318 + .priority = 2, 319 + }; 320 + 321 + #else 322 + #warning "your version of binutils lacks AVX2 support" 323 + #endif
-4
lib/raid6/recov_ssse3.c
··· 7 7 * of the License. 8 8 */ 9 9 10 - #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) 11 - 12 10 #include <linux/raid/pq.h> 13 11 #include "x86.h" 14 12 ··· 330 332 #endif 331 333 .priority = 1, 332 334 }; 333 - 334 - #endif
+1 -1
lib/raid6/sse1.c
··· 21 21 * worthwhile as a separate implementation. 22 22 */ 23 23 24 - #if defined(__i386__) && !defined(__arch_um__) 24 + #ifdef CONFIG_X86_32 25 25 26 26 #include <linux/raid/pq.h> 27 27 #include "x86.h"
+2 -6
lib/raid6/sse2.c
··· 17 17 * 18 18 */ 19 19 20 - #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) 21 - 22 20 #include <linux/raid/pq.h> 23 21 #include "x86.h" 24 22 ··· 157 159 1 /* Has cache hints */ 158 160 }; 159 161 160 - #endif 161 - 162 - #if defined(__x86_64__) && !defined(__arch_um__) 162 + #ifdef CONFIG_X86_64 163 163 164 164 /* 165 165 * Unrolled-by-4 SSE2 implementation ··· 255 259 1 /* Has cache hints */ 256 260 }; 257 261 258 - #endif 262 + #endif /* CONFIG_X86_64 */
+26 -3
lib/raid6/test/Makefile
··· 10 10 AWK = awk -f 11 11 AR = ar 12 12 RANLIB = ranlib 13 + OBJS = int1.o int2.o int4.o int8.o int16.o int32.o recov.o algos.o tables.o 14 + 15 + ARCH := $(shell uname -m 2>/dev/null | sed -e /s/i.86/i386/) 16 + ifeq ($(ARCH),i386) 17 + CFLAGS += -DCONFIG_X86_32 18 + IS_X86 = yes 19 + endif 20 + ifeq ($(ARCH),x86_64) 21 + CFLAGS += -DCONFIG_X86_64 22 + IS_X86 = yes 23 + endif 24 + 25 + ifeq ($(IS_X86),yes) 26 + OBJS += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o 27 + CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" | \ 28 + gcc -c -x assembler - >&/dev/null && \ 29 + rm ./-.o && echo -DCONFIG_AS_AVX2=1) 30 + else 31 + HAS_ALTIVEC := $(shell echo -e '\#include <altivec.h>\nvector int a;' |\ 32 + gcc -c -x c - >&/dev/null && \ 33 + rm ./-.o && echo yes) 34 + ifeq ($(HAS_ALTIVEC),yes) 35 + OBJS += altivec1.o altivec2.o altivec4.o altivec8.o 36 + endif 37 + endif 13 38 14 39 .c.o: 15 40 $(CC) $(CFLAGS) -c -o $@ $< ··· 47 22 48 23 all: raid6.a raid6test 49 24 50 - raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o \ 51 - altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o algos.o \ 52 - tables.o 25 + raid6.a: $(OBJS) 53 26 rm -f $@ 54 27 $(AR) cq $@ $^ 55 28 $(RANLIB) $@
+9 -5
lib/raid6/x86.h
··· 45 45 #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ 46 46 #define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental SSE-3 */ 47 47 #define X86_FEATURE_AVX (4*32+28) /* Advanced Vector Extensions */ 48 + #define X86_FEATURE_AVX2 (9*32+ 5) /* AVX2 instructions */ 48 49 #define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ 49 50 50 51 /* Should work well enough on modern CPUs for testing */ 51 52 static inline int boot_cpu_has(int flag) 52 53 { 53 - u32 eax = (flag & 0x20) ? 0x80000001 : 1; 54 - u32 ecx, edx; 54 + u32 eax, ebx, ecx, edx; 55 + 56 + eax = (flag & 0x100) ? 7 : 57 + (flag & 0x20) ? 0x80000001 : 1; 58 + ecx = 0; 55 59 56 60 asm volatile("cpuid" 57 - : "+a" (eax), "=d" (edx), "=c" (ecx) 58 - : : "ebx"); 61 + : "+a" (eax), "=b" (ebx), "=d" (edx), "+c" (ecx)); 59 62 60 - return ((flag & 0x80 ? ecx : edx) >> (flag & 31)) & 1; 63 + return ((flag & 0x100 ? ebx : 64 + (flag & 0x80) ? ecx : edx) >> (flag & 31)) & 1; 61 65 } 62 66 63 67 #endif /* ndef __KERNEL__ */