diff options
Diffstat (limited to 'drivers')
67 files changed, 7403 insertions, 476 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 448ce5e29c56..c8f43295d42a 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -971,8 +971,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) | |||
971 | struct acpi_resource_fixed_memory32 *fixmem32; | 971 | struct acpi_resource_fixed_memory32 *fixmem32; |
972 | 972 | ||
973 | fixmem32 = &res->data.fixed_memory32; | 973 | fixmem32 = &res->data.fixed_memory32; |
974 | if (!fixmem32) | ||
975 | return AE_NO_MEMORY; | ||
976 | 974 | ||
977 | hdp->hd_phys_address = fixmem32->address; | 975 | hdp->hd_phys_address = fixmem32->address; |
978 | hdp->hd_address = ioremap(fixmem32->address, | 976 | hdp->hd_address = ioremap(fixmem32->address, |
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 190d4423653f..2f685f6eda48 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c | |||
@@ -193,8 +193,8 @@ int misc_register(struct miscdevice * misc) | |||
193 | if (misc->minor == MISC_DYNAMIC_MINOR) { | 193 | if (misc->minor == MISC_DYNAMIC_MINOR) { |
194 | int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); | 194 | int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); |
195 | if (i >= DYNAMIC_MINORS) { | 195 | if (i >= DYNAMIC_MINORS) { |
196 | mutex_unlock(&misc_mtx); | 196 | err = -EBUSY; |
197 | return -EBUSY; | 197 | goto out; |
198 | } | 198 | } |
199 | misc->minor = DYNAMIC_MINORS - i - 1; | 199 | misc->minor = DYNAMIC_MINORS - i - 1; |
200 | set_bit(i, misc_minors); | 200 | set_bit(i, misc_minors); |
@@ -203,8 +203,8 @@ int misc_register(struct miscdevice * misc) | |||
203 | 203 | ||
204 | list_for_each_entry(c, &misc_list, list) { | 204 | list_for_each_entry(c, &misc_list, list) { |
205 | if (c->minor == misc->minor) { | 205 | if (c->minor == misc->minor) { |
206 | mutex_unlock(&misc_mtx); | 206 | err = -EBUSY; |
207 | return -EBUSY; | 207 | goto out; |
208 | } | 208 | } |
209 | } | 209 | } |
210 | } | 210 | } |
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 5224da5202d3..a7f65c2b2cb5 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c | |||
@@ -721,7 +721,7 @@ static int hwicap_remove(struct device *dev) | |||
721 | { | 721 | { |
722 | struct hwicap_drvdata *drvdata; | 722 | struct hwicap_drvdata *drvdata; |
723 | 723 | ||
724 | drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev); | 724 | drvdata = dev_get_drvdata(dev); |
725 | 725 | ||
726 | if (!drvdata) | 726 | if (!drvdata) |
727 | return 0; | 727 | return 0; |
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index ec9a14e05fdd..3c55ec856e39 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
@@ -565,11 +565,10 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
565 | } | 565 | } |
566 | 566 | ||
567 | ret = arizona_hpdet_read(info); | 567 | ret = arizona_hpdet_read(info); |
568 | if (ret == -EAGAIN) { | 568 | if (ret == -EAGAIN) |
569 | goto out; | 569 | goto out; |
570 | } else if (ret < 0) { | 570 | else if (ret < 0) |
571 | goto done; | 571 | goto done; |
572 | } | ||
573 | reading = ret; | 572 | reading = ret; |
574 | 573 | ||
575 | /* Reset back to starting range */ | 574 | /* Reset back to starting range */ |
@@ -579,11 +578,10 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
579 | 0); | 578 | 0); |
580 | 579 | ||
581 | ret = arizona_hpdet_do_id(info, &reading, &mic); | 580 | ret = arizona_hpdet_do_id(info, &reading, &mic); |
582 | if (ret == -EAGAIN) { | 581 | if (ret == -EAGAIN) |
583 | goto out; | 582 | goto out; |
584 | } else if (ret < 0) { | 583 | else if (ret < 0) |
585 | goto done; | 584 | goto done; |
586 | } | ||
587 | 585 | ||
588 | /* Report high impedence cables as line outputs */ | 586 | /* Report high impedence cables as line outputs */ |
589 | if (reading >= 5000) | 587 | if (reading >= 5000) |
@@ -739,8 +737,8 @@ err: | |||
739 | static void arizona_micd_timeout_work(struct work_struct *work) | 737 | static void arizona_micd_timeout_work(struct work_struct *work) |
740 | { | 738 | { |
741 | struct arizona_extcon_info *info = container_of(work, | 739 | struct arizona_extcon_info *info = container_of(work, |
742 | struct arizona_extcon_info, | 740 | struct arizona_extcon_info, |
743 | micd_timeout_work.work); | 741 | micd_timeout_work.work); |
744 | 742 | ||
745 | mutex_lock(&info->lock); | 743 | mutex_lock(&info->lock); |
746 | 744 | ||
@@ -757,8 +755,8 @@ static void arizona_micd_timeout_work(struct work_struct *work) | |||
757 | static void arizona_micd_detect(struct work_struct *work) | 755 | static void arizona_micd_detect(struct work_struct *work) |
758 | { | 756 | { |
759 | struct arizona_extcon_info *info = container_of(work, | 757 | struct arizona_extcon_info *info = container_of(work, |
760 | struct arizona_extcon_info, | 758 | struct arizona_extcon_info, |
761 | micd_detect_work.work); | 759 | micd_detect_work.work); |
762 | struct arizona *arizona = info->arizona; | 760 | struct arizona *arizona = info->arizona; |
763 | unsigned int val = 0, lvl; | 761 | unsigned int val = 0, lvl; |
764 | int ret, i, key; | 762 | int ret, i, key; |
@@ -770,7 +768,8 @@ static void arizona_micd_detect(struct work_struct *work) | |||
770 | for (i = 0; i < 10 && !(val & 0x7fc); i++) { | 768 | for (i = 0; i < 10 && !(val & 0x7fc); i++) { |
771 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); | 769 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); |
772 | if (ret != 0) { | 770 | if (ret != 0) { |
773 | dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); | 771 | dev_err(arizona->dev, |
772 | "Failed to read MICDET: %d\n", ret); | ||
774 | mutex_unlock(&info->lock); | 773 | mutex_unlock(&info->lock); |
775 | return; | 774 | return; |
776 | } | 775 | } |
@@ -778,7 +777,8 @@ static void arizona_micd_detect(struct work_struct *work) | |||
778 | dev_dbg(arizona->dev, "MICDET: %x\n", val); | 777 | dev_dbg(arizona->dev, "MICDET: %x\n", val); |
779 | 778 | ||
780 | if (!(val & ARIZONA_MICD_VALID)) { | 779 | if (!(val & ARIZONA_MICD_VALID)) { |
781 | dev_warn(arizona->dev, "Microphone detection state invalid\n"); | 780 | dev_warn(arizona->dev, |
781 | "Microphone detection state invalid\n"); | ||
782 | mutex_unlock(&info->lock); | 782 | mutex_unlock(&info->lock); |
783 | return; | 783 | return; |
784 | } | 784 | } |
@@ -926,8 +926,8 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
926 | static void arizona_hpdet_work(struct work_struct *work) | 926 | static void arizona_hpdet_work(struct work_struct *work) |
927 | { | 927 | { |
928 | struct arizona_extcon_info *info = container_of(work, | 928 | struct arizona_extcon_info *info = container_of(work, |
929 | struct arizona_extcon_info, | 929 | struct arizona_extcon_info, |
930 | hpdet_work.work); | 930 | hpdet_work.work); |
931 | 931 | ||
932 | mutex_lock(&info->lock); | 932 | mutex_lock(&info->lock); |
933 | arizona_start_hpdet_acc_id(info); | 933 | arizona_start_hpdet_acc_id(info); |
@@ -974,10 +974,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
974 | &info->hpdet_work, | 974 | &info->hpdet_work, |
975 | msecs_to_jiffies(HPDET_DEBOUNCE)); | 975 | msecs_to_jiffies(HPDET_DEBOUNCE)); |
976 | 976 | ||
977 | if (cancelled_mic) | 977 | if (cancelled_mic) { |
978 | int micd_timeout = info->micd_timeout; | ||
979 | |||
978 | queue_delayed_work(system_power_efficient_wq, | 980 | queue_delayed_work(system_power_efficient_wq, |
979 | &info->micd_timeout_work, | 981 | &info->micd_timeout_work, |
980 | msecs_to_jiffies(info->micd_timeout)); | 982 | msecs_to_jiffies(micd_timeout)); |
983 | } | ||
981 | 984 | ||
982 | goto out; | 985 | goto out; |
983 | } | 986 | } |
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c index 84902d3fee11..15443d3b6be1 100644 --- a/drivers/extcon/extcon-class.c +++ b/drivers/extcon/extcon-class.c | |||
@@ -129,7 +129,6 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, | |||
129 | return count; | 129 | return count; |
130 | } | 130 | } |
131 | 131 | ||
132 | int extcon_set_state(struct extcon_dev *edev, u32 state); | ||
133 | static ssize_t state_store(struct device *dev, struct device_attribute *attr, | 132 | static ssize_t state_store(struct device *dev, struct device_attribute *attr, |
134 | const char *buf, size_t count) | 133 | const char *buf, size_t count) |
135 | { | 134 | { |
@@ -452,7 +451,8 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj, | |||
452 | if (!obj->edev) | 451 | if (!obj->edev) |
453 | return -ENODEV; | 452 | return -ENODEV; |
454 | 453 | ||
455 | obj->cable_index = extcon_find_cable_index(obj->edev, cable_name); | 454 | obj->cable_index = extcon_find_cable_index(obj->edev, |
455 | cable_name); | ||
456 | if (obj->cable_index < 0) | 456 | if (obj->cable_index < 0) |
457 | return obj->cable_index; | 457 | return obj->cable_index; |
458 | 458 | ||
@@ -460,7 +460,8 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj, | |||
460 | 460 | ||
461 | obj->internal_nb.notifier_call = _call_per_cable; | 461 | obj->internal_nb.notifier_call = _call_per_cable; |
462 | 462 | ||
463 | return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb); | 463 | return raw_notifier_chain_register(&obj->edev->nh, |
464 | &obj->internal_nb); | ||
464 | } else { | 465 | } else { |
465 | struct class_dev_iter iter; | 466 | struct class_dev_iter iter; |
466 | struct extcon_dev *extd; | 467 | struct extcon_dev *extd; |
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index ab9bc24e1a52..da268fbc901b 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c | |||
@@ -189,14 +189,17 @@ enum max77693_muic_acc_type { | |||
189 | 189 | ||
190 | /* The below accessories have same ADC value so ADCLow and | 190 | /* The below accessories have same ADC value so ADCLow and |
191 | ADC1K bit is used to separate specific accessory */ | 191 | ADC1K bit is used to separate specific accessory */ |
192 | MAX77693_MUIC_GND_USB_OTG = 0x100, /* ADC:0x0, VBVolot:0, ADCLow:0, ADC1K:0 */ | 192 | /* ADC|VBVolot|ADCLow|ADC1K| */ |
193 | MAX77693_MUIC_GND_USB_OTG_VB = 0x104, /* ADC:0x0, VBVolot:1, ADCLow:0, ADC1K:0 */ | 193 | MAX77693_MUIC_GND_USB_OTG = 0x100, /* 0x0| 0| 0| 0| */ |
194 | MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:0 */ | 194 | MAX77693_MUIC_GND_USB_OTG_VB = 0x104, /* 0x0| 1| 0| 0| */ |
195 | MAX77693_MUIC_GND_MHL = 0x103, /* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:1 */ | 195 | MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* 0x0| 0| 1| 0| */ |
196 | MAX77693_MUIC_GND_MHL_VB = 0x107, /* ADC:0x0, VBVolot:1, ADCLow:1, ADC1K:1 */ | 196 | MAX77693_MUIC_GND_MHL = 0x103, /* 0x0| 0| 1| 1| */ |
197 | MAX77693_MUIC_GND_MHL_VB = 0x107, /* 0x0| 1| 1| 1| */ | ||
197 | }; | 198 | }; |
198 | 199 | ||
199 | /* MAX77693 MUIC device support below list of accessories(external connector) */ | 200 | /* |
201 | * MAX77693 MUIC device support below list of accessories(external connector) | ||
202 | */ | ||
200 | enum { | 203 | enum { |
201 | EXTCON_CABLE_USB = 0, | 204 | EXTCON_CABLE_USB = 0, |
202 | EXTCON_CABLE_USB_HOST, | 205 | EXTCON_CABLE_USB_HOST, |
@@ -395,12 +398,12 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, | |||
395 | vbvolt >>= STATUS2_VBVOLT_SHIFT; | 398 | vbvolt >>= STATUS2_VBVOLT_SHIFT; |
396 | 399 | ||
397 | /** | 400 | /** |
398 | * [0x1][VBVolt][ADCLow][ADC1K] | 401 | * [0x1|VBVolt|ADCLow|ADC1K] |
399 | * [0x1 0 0 0 ] : USB_OTG | 402 | * [0x1| 0| 0| 0] USB_OTG |
400 | * [0x1 1 0 0 ] : USB_OTG_VB | 403 | * [0x1| 1| 0| 0] USB_OTG_VB |
401 | * [0x1 0 1 0 ] : Audio Video Cable with load | 404 | * [0x1| 0| 1| 0] Audio Video cable with load |
402 | * [0x1 0 1 1 ] : MHL without charging connector | 405 | * [0x1| 0| 1| 1] MHL without charging cable |
403 | * [0x1 1 1 1 ] : MHL with charging connector | 406 | * [0x1| 1| 1| 1] MHL with charging cable |
404 | */ | 407 | */ |
405 | cable_type = ((0x1 << 8) | 408 | cable_type = ((0x1 << 8) |
406 | | (vbvolt << 2) | 409 | | (vbvolt << 2) |
@@ -723,11 +726,11 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info) | |||
723 | if (ret < 0) | 726 | if (ret < 0) |
724 | return ret; | 727 | return ret; |
725 | break; | 728 | break; |
726 | case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: /* DOCK_KEY_PREV */ | 729 | case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: /* DOCK_KEY_PREV */ |
727 | case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: /* DOCK_KEY_NEXT */ | 730 | case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: /* DOCK_KEY_NEXT */ |
728 | case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: /* DOCK_VOL_DOWN */ | 731 | case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: /* DOCK_VOL_DOWN */ |
729 | case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: /* DOCK_VOL_UP */ | 732 | case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: /* DOCK_VOL_UP */ |
730 | case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON: /* DOCK_KEY_PLAY_PAUSE */ | 733 | case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON: /* DOCK_KEY_PLAY_PAUSE */ |
731 | /* | 734 | /* |
732 | * Button of DOCK device | 735 | * Button of DOCK device |
733 | * - the Prev/Next/Volume Up/Volume Down/Play-Pause button | 736 | * - the Prev/Next/Volume Up/Volume Down/Play-Pause button |
@@ -815,19 +818,21 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) | |||
815 | case MAX77693_MUIC_GND_MHL_VB: | 818 | case MAX77693_MUIC_GND_MHL_VB: |
816 | /* | 819 | /* |
817 | * MHL cable with MHL_TA(USB/TA) cable | 820 | * MHL cable with MHL_TA(USB/TA) cable |
818 | * - MHL cable include two port(HDMI line and separate micro- | 821 | * - MHL cable include two port(HDMI line and separate |
819 | * usb port. When the target connect MHL cable, extcon driver | 822 | * micro-usb port. When the target connect MHL cable, |
820 | * check whether MHL_TA(USB/TA) cable is connected. If MHL_TA | 823 | * extcon driver check whether MHL_TA(USB/TA) cable is |
821 | * cable is connected, extcon driver notify state to notifiee | 824 | * connected. If MHL_TA cable is connected, extcon |
822 | * for charging battery. | 825 | * driver notify state to notifiee for charging battery. |
823 | * | 826 | * |
824 | * Features of 'MHL_TA(USB/TA) with MHL cable' | 827 | * Features of 'MHL_TA(USB/TA) with MHL cable' |
825 | * - Support MHL | 828 | * - Support MHL |
826 | * - Support charging through micro-usb port without data connection | 829 | * - Support charging through micro-usb port without |
830 | * data connection | ||
827 | */ | 831 | */ |
828 | extcon_set_cable_state(info->edev, "MHL_TA", attached); | 832 | extcon_set_cable_state(info->edev, "MHL_TA", attached); |
829 | if (!cable_attached) | 833 | if (!cable_attached) |
830 | extcon_set_cable_state(info->edev, "MHL", cable_attached); | 834 | extcon_set_cable_state(info->edev, |
835 | "MHL", cable_attached); | ||
831 | break; | 836 | break; |
832 | } | 837 | } |
833 | 838 | ||
@@ -839,47 +844,51 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) | |||
839 | case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ | 844 | case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ |
840 | /* | 845 | /* |
841 | * Dock-Audio device with USB/TA cable | 846 | * Dock-Audio device with USB/TA cable |
842 | * - Dock device include two port(Dock-Audio and micro-usb | 847 | * - Dock device include two port(Dock-Audio and micro- |
843 | * port). When the target connect Dock-Audio device, extcon | 848 | * usb port). When the target connect Dock-Audio device, |
844 | * driver check whether USB/TA cable is connected. If USB/TA | 849 | * extcon driver check whether USB/TA cable is connected |
845 | * cable is connected, extcon driver notify state to notifiee | 850 | * or not. If USB/TA cable is connected, extcon driver |
846 | * for charging battery. | 851 | * notify state to notifiee for charging battery. |
847 | * | 852 | * |
848 | * Features of 'USB/TA cable with Dock-Audio device' | 853 | * Features of 'USB/TA cable with Dock-Audio device' |
849 | * - Support external output feature of audio. | 854 | * - Support external output feature of audio. |
850 | * - Support charging through micro-usb port without data | 855 | * - Support charging through micro-usb port without |
851 | * connection. | 856 | * data connection. |
852 | */ | 857 | */ |
853 | extcon_set_cable_state(info->edev, "USB", attached); | 858 | extcon_set_cable_state(info->edev, "USB", attached); |
854 | 859 | ||
855 | if (!cable_attached) | 860 | if (!cable_attached) |
856 | extcon_set_cable_state(info->edev, "Dock-Audio", cable_attached); | 861 | extcon_set_cable_state(info->edev, "Dock-Audio", |
862 | cable_attached); | ||
857 | break; | 863 | break; |
858 | case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ | 864 | case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ |
859 | /* | 865 | /* |
860 | * Dock-Smart device with USB/TA cable | 866 | * Dock-Smart device with USB/TA cable |
861 | * - Dock-Desk device include three type of cable which | 867 | * - Dock-Desk device include three type of cable which |
862 | * are HDMI, USB for mouse/keyboard and micro-usb port | 868 | * are HDMI, USB for mouse/keyboard and micro-usb port |
863 | * for USB/TA cable. Dock-Smart device need always exteranl | 869 | * for USB/TA cable. Dock-Smart device need always |
864 | * power supply(USB/TA cable through micro-usb cable). Dock- | 870 | * exteranl power supply(USB/TA cable through micro-usb |
865 | * Smart device support screen output of target to separate | 871 | * cable). Dock-Smart device support screen output of |
866 | * monitor and mouse/keyboard for desktop mode. | 872 | * target to separate monitor and mouse/keyboard for |
873 | * desktop mode. | ||
867 | * | 874 | * |
868 | * Features of 'USB/TA cable with Dock-Smart device' | 875 | * Features of 'USB/TA cable with Dock-Smart device' |
869 | * - Support MHL | 876 | * - Support MHL |
870 | * - Support external output feature of audio | 877 | * - Support external output feature of audio |
871 | * - Support charging through micro-usb port without data | 878 | * - Support charging through micro-usb port without |
872 | * connection if TA cable is connected to target. | 879 | * data connection if TA cable is connected to target. |
873 | * - Support charging and data connection through micro-usb port | 880 | * - Support charging and data connection through micro- |
874 | * if USB cable is connected between target and host | 881 | * usb port if USB cable is connected between target |
875 | * device. | 882 | * and host device |
876 | * - Support OTG device (Mouse/Keyboard) | 883 | * - Support OTG device (Mouse/Keyboard) |
877 | */ | 884 | */ |
878 | ret = max77693_muic_set_path(info, info->path_usb, attached); | 885 | ret = max77693_muic_set_path(info, info->path_usb, |
886 | attached); | ||
879 | if (ret < 0) | 887 | if (ret < 0) |
880 | return ret; | 888 | return ret; |
881 | 889 | ||
882 | extcon_set_cable_state(info->edev, "Dock-Smart", attached); | 890 | extcon_set_cable_state(info->edev, "Dock-Smart", |
891 | attached); | ||
883 | extcon_set_cable_state(info->edev, "MHL", attached); | 892 | extcon_set_cable_state(info->edev, "MHL", attached); |
884 | 893 | ||
885 | break; | 894 | break; |
@@ -889,25 +898,28 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) | |||
889 | switch (chg_type) { | 898 | switch (chg_type) { |
890 | case MAX77693_CHARGER_TYPE_NONE: | 899 | case MAX77693_CHARGER_TYPE_NONE: |
891 | /* | 900 | /* |
892 | * When MHL(with USB/TA cable) or Dock-Audio with USB/TA cable | 901 | * When MHL(with USB/TA cable) or Dock-Audio with USB/TA |
893 | * is attached, muic device happen below two interrupt. | 902 | * cable is attached, muic device happen below two irq. |
894 | * - 'MAX77693_MUIC_IRQ_INT1_ADC' for detecting MHL/Dock-Audio. | 903 | * - 'MAX77693_MUIC_IRQ_INT1_ADC' for detecting |
895 | * - 'MAX77693_MUIC_IRQ_INT2_CHGTYP' for detecting USB/TA cable | 904 | * MHL/Dock-Audio. |
896 | * connected to MHL or Dock-Audio. | 905 | * - 'MAX77693_MUIC_IRQ_INT2_CHGTYP' for detecting |
897 | * Always, happen eariler MAX77693_MUIC_IRQ_INT1_ADC interrupt | 906 | * USB/TA cable connected to MHL or Dock-Audio. |
898 | * than MAX77693_MUIC_IRQ_INT2_CHGTYP interrupt. | 907 | * Always, happen eariler MAX77693_MUIC_IRQ_INT1_ADC |
908 | * irq than MAX77693_MUIC_IRQ_INT2_CHGTYP irq. | ||
899 | * | 909 | * |
900 | * If user attach MHL (with USB/TA cable and immediately detach | 910 | * If user attach MHL (with USB/TA cable and immediately |
901 | * MHL with USB/TA cable before MAX77693_MUIC_IRQ_INT2_CHGTYP | 911 | * detach MHL with USB/TA cable before MAX77693_MUIC_IRQ |
902 | * interrupt is happened, USB/TA cable remain connected state to | 912 | * _INT2_CHGTYP irq is happened, USB/TA cable remain |
903 | * target. But USB/TA cable isn't connected to target. The user | 913 | * connected state to target. But USB/TA cable isn't |
904 | * be face with unusual action. So, driver should check this | 914 | * connected to target. The user be face with unusual |
905 | * situation in spite of, that previous charger type is N/A. | 915 | * action. So, driver should check this situation in |
916 | * spite of, that previous charger type is N/A. | ||
906 | */ | 917 | */ |
907 | break; | 918 | break; |
908 | case MAX77693_CHARGER_TYPE_USB: | 919 | case MAX77693_CHARGER_TYPE_USB: |
909 | /* Only USB cable, PATH:AP_USB */ | 920 | /* Only USB cable, PATH:AP_USB */ |
910 | ret = max77693_muic_set_path(info, info->path_usb, attached); | 921 | ret = max77693_muic_set_path(info, info->path_usb, |
922 | attached); | ||
911 | if (ret < 0) | 923 | if (ret < 0) |
912 | return ret; | 924 | return ret; |
913 | 925 | ||
@@ -1215,7 +1227,8 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
1215 | } | 1227 | } |
1216 | 1228 | ||
1217 | if (pdata->muic_data) { | 1229 | if (pdata->muic_data) { |
1218 | struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; | 1230 | struct max77693_muic_platform_data *muic_pdata |
1231 | = pdata->muic_data; | ||
1219 | 1232 | ||
1220 | /* | 1233 | /* |
1221 | * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB | 1234 | * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB |
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 0b1cbb5fdf9e..6a00464658c5 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c | |||
@@ -426,7 +426,8 @@ static int max8997_muic_adc_handler(struct max8997_muic_info *info) | |||
426 | break; | 426 | break; |
427 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF: | 427 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF: |
428 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON: | 428 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON: |
429 | ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, attached); | 429 | ret = max8997_muic_handle_usb(info, |
430 | MAX8997_USB_DEVICE, attached); | ||
430 | if (ret < 0) | 431 | if (ret < 0) |
431 | return ret; | 432 | return ret; |
432 | break; | 433 | break; |
@@ -504,7 +505,8 @@ static int max8997_muic_chg_handler(struct max8997_muic_info *info) | |||
504 | } | 505 | } |
505 | break; | 506 | break; |
506 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: | 507 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: |
507 | extcon_set_cable_state(info->edev, "Charge-downstream", attached); | 508 | extcon_set_cable_state(info->edev, |
509 | "Charge-downstream", attached); | ||
508 | break; | 510 | break; |
509 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: | 511 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: |
510 | extcon_set_cable_state(info->edev, "TA", attached); | 512 | extcon_set_cable_state(info->edev, "TA", attached); |
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 6de6c98ce6eb..cea623c36ae2 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
@@ -47,8 +47,8 @@ static void vmbus_setevent(struct vmbus_channel *channel) | |||
47 | (unsigned long *) vmbus_connection.send_int_page + | 47 | (unsigned long *) vmbus_connection.send_int_page + |
48 | (channel->offermsg.child_relid >> 5)); | 48 | (channel->offermsg.child_relid >> 5)); |
49 | 49 | ||
50 | monitorpage = vmbus_connection.monitor_pages; | 50 | /* Get the child to parent monitor page */ |
51 | monitorpage++; /* Get the child to parent monitor page */ | 51 | monitorpage = vmbus_connection.monitor_pages[1]; |
52 | 52 | ||
53 | sync_set_bit(channel->monitor_bit, | 53 | sync_set_bit(channel->monitor_bit, |
54 | (unsigned long *)&monitorpage->trigger_group | 54 | (unsigned long *)&monitorpage->trigger_group |
@@ -60,50 +60,6 @@ static void vmbus_setevent(struct vmbus_channel *channel) | |||
60 | } | 60 | } |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * vmbus_get_debug_info -Retrieve various channel debug info | ||
64 | */ | ||
65 | void vmbus_get_debug_info(struct vmbus_channel *channel, | ||
66 | struct vmbus_channel_debug_info *debuginfo) | ||
67 | { | ||
68 | struct hv_monitor_page *monitorpage; | ||
69 | u8 monitor_group = (u8)channel->offermsg.monitorid / 32; | ||
70 | u8 monitor_offset = (u8)channel->offermsg.monitorid % 32; | ||
71 | |||
72 | debuginfo->relid = channel->offermsg.child_relid; | ||
73 | debuginfo->state = channel->state; | ||
74 | memcpy(&debuginfo->interfacetype, | ||
75 | &channel->offermsg.offer.if_type, sizeof(uuid_le)); | ||
76 | memcpy(&debuginfo->interface_instance, | ||
77 | &channel->offermsg.offer.if_instance, | ||
78 | sizeof(uuid_le)); | ||
79 | |||
80 | monitorpage = (struct hv_monitor_page *)vmbus_connection.monitor_pages; | ||
81 | |||
82 | debuginfo->monitorid = channel->offermsg.monitorid; | ||
83 | |||
84 | debuginfo->servermonitor_pending = | ||
85 | monitorpage->trigger_group[monitor_group].pending; | ||
86 | debuginfo->servermonitor_latency = | ||
87 | monitorpage->latency[monitor_group][monitor_offset]; | ||
88 | debuginfo->servermonitor_connectionid = | ||
89 | monitorpage->parameter[monitor_group] | ||
90 | [monitor_offset].connectionid.u.id; | ||
91 | |||
92 | monitorpage++; | ||
93 | |||
94 | debuginfo->clientmonitor_pending = | ||
95 | monitorpage->trigger_group[monitor_group].pending; | ||
96 | debuginfo->clientmonitor_latency = | ||
97 | monitorpage->latency[monitor_group][monitor_offset]; | ||
98 | debuginfo->clientmonitor_connectionid = | ||
99 | monitorpage->parameter[monitor_group] | ||
100 | [monitor_offset].connectionid.u.id; | ||
101 | |||
102 | hv_ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound); | ||
103 | hv_ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * vmbus_open - Open the specified channel. | 63 | * vmbus_open - Open the specified channel. |
108 | */ | 64 | */ |
109 | int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, | 65 | int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, |
@@ -855,6 +811,6 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, | |||
855 | if (signal) | 811 | if (signal) |
856 | vmbus_setevent(channel); | 812 | vmbus_setevent(channel); |
857 | 813 | ||
858 | return 0; | 814 | return ret; |
859 | } | 815 | } |
860 | EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); | 816 | EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); |
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 8f4743ab5fb2..4faea979975e 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c | |||
@@ -76,10 +76,8 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, | |||
76 | msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; | 76 | msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; |
77 | msg->vmbus_version_requested = version; | 77 | msg->vmbus_version_requested = version; |
78 | msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); | 78 | msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); |
79 | msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages); | 79 | msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); |
80 | msg->monitor_page2 = virt_to_phys( | 80 | msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); |
81 | (void *)((unsigned long)vmbus_connection.monitor_pages + | ||
82 | PAGE_SIZE)); | ||
83 | 81 | ||
84 | /* | 82 | /* |
85 | * Add to list before we send the request since we may | 83 | * Add to list before we send the request since we may |
@@ -169,9 +167,10 @@ int vmbus_connect(void) | |||
169 | * Setup the monitor notification facility. The 1st page for | 167 | * Setup the monitor notification facility. The 1st page for |
170 | * parent->child and the 2nd page for child->parent | 168 | * parent->child and the 2nd page for child->parent |
171 | */ | 169 | */ |
172 | vmbus_connection.monitor_pages = | 170 | vmbus_connection.monitor_pages[0] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0); |
173 | (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 1); | 171 | vmbus_connection.monitor_pages[1] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0); |
174 | if (vmbus_connection.monitor_pages == NULL) { | 172 | if ((vmbus_connection.monitor_pages[0] == NULL) || |
173 | (vmbus_connection.monitor_pages[1] == NULL)) { | ||
175 | ret = -ENOMEM; | 174 | ret = -ENOMEM; |
176 | goto cleanup; | 175 | goto cleanup; |
177 | } | 176 | } |
@@ -229,10 +228,10 @@ cleanup: | |||
229 | vmbus_connection.int_page = NULL; | 228 | vmbus_connection.int_page = NULL; |
230 | } | 229 | } |
231 | 230 | ||
232 | if (vmbus_connection.monitor_pages) { | 231 | free_pages((unsigned long)vmbus_connection.monitor_pages[0], 1); |
233 | free_pages((unsigned long)vmbus_connection.monitor_pages, 1); | 232 | free_pages((unsigned long)vmbus_connection.monitor_pages[1], 1); |
234 | vmbus_connection.monitor_pages = NULL; | 233 | vmbus_connection.monitor_pages[0] = NULL; |
235 | } | 234 | vmbus_connection.monitor_pages[1] = NULL; |
236 | 235 | ||
237 | kfree(msginfo); | 236 | kfree(msginfo); |
238 | 237 | ||
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index cb82233541b1..9113850edb43 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c | |||
@@ -82,7 +82,7 @@ static void shutdown_onchannelcallback(void *context) | |||
82 | struct vmbus_channel *channel = context; | 82 | struct vmbus_channel *channel = context; |
83 | u32 recvlen; | 83 | u32 recvlen; |
84 | u64 requestid; | 84 | u64 requestid; |
85 | u8 execute_shutdown = false; | 85 | bool execute_shutdown = false; |
86 | u8 *shut_txf_buf = util_shutdown.recv_buffer; | 86 | u8 *shut_txf_buf = util_shutdown.recv_buffer; |
87 | 87 | ||
88 | struct shutdown_msg_data *shutdown_msg; | 88 | struct shutdown_msg_data *shutdown_msg; |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index d84918fe19ab..e05517616a06 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
@@ -514,6 +514,13 @@ struct hv_context { | |||
514 | 514 | ||
515 | extern struct hv_context hv_context; | 515 | extern struct hv_context hv_context; |
516 | 516 | ||
517 | struct hv_ring_buffer_debug_info { | ||
518 | u32 current_interrupt_mask; | ||
519 | u32 current_read_index; | ||
520 | u32 current_write_index; | ||
521 | u32 bytes_avail_toread; | ||
522 | u32 bytes_avail_towrite; | ||
523 | }; | ||
517 | 524 | ||
518 | /* Hv Interface */ | 525 | /* Hv Interface */ |
519 | 526 | ||
@@ -612,7 +619,7 @@ struct vmbus_connection { | |||
612 | * 2 pages - 1st page for parent->child notification and 2nd | 619 | * 2 pages - 1st page for parent->child notification and 2nd |
613 | * is child->parent notification | 620 | * is child->parent notification |
614 | */ | 621 | */ |
615 | void *monitor_pages; | 622 | struct hv_monitor_page *monitor_pages[2]; |
616 | struct list_head chn_msg_list; | 623 | struct list_head chn_msg_list; |
617 | spinlock_t channelmsg_lock; | 624 | spinlock_t channelmsg_lock; |
618 | 625 | ||
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index f9fe46f52cfa..48aad4faea06 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
@@ -46,24 +46,6 @@ static struct tasklet_struct msg_dpc; | |||
46 | static struct completion probe_event; | 46 | static struct completion probe_event; |
47 | static int irq; | 47 | static int irq; |
48 | 48 | ||
49 | struct hv_device_info { | ||
50 | u32 chn_id; | ||
51 | u32 chn_state; | ||
52 | uuid_le chn_type; | ||
53 | uuid_le chn_instance; | ||
54 | |||
55 | u32 monitor_id; | ||
56 | u32 server_monitor_pending; | ||
57 | u32 server_monitor_latency; | ||
58 | u32 server_monitor_conn_id; | ||
59 | u32 client_monitor_pending; | ||
60 | u32 client_monitor_latency; | ||
61 | u32 client_monitor_conn_id; | ||
62 | |||
63 | struct hv_dev_port_info inbound; | ||
64 | struct hv_dev_port_info outbound; | ||
65 | }; | ||
66 | |||
67 | static int vmbus_exists(void) | 49 | static int vmbus_exists(void) |
68 | { | 50 | { |
69 | if (hv_acpi_dev == NULL) | 51 | if (hv_acpi_dev == NULL) |
@@ -72,169 +54,361 @@ static int vmbus_exists(void) | |||
72 | return 0; | 54 | return 0; |
73 | } | 55 | } |
74 | 56 | ||
57 | #define VMBUS_ALIAS_LEN ((sizeof((struct hv_vmbus_device_id *)0)->guid) * 2) | ||
58 | static void print_alias_name(struct hv_device *hv_dev, char *alias_name) | ||
59 | { | ||
60 | int i; | ||
61 | for (i = 0; i < VMBUS_ALIAS_LEN; i += 2) | ||
62 | sprintf(&alias_name[i], "%02x", hv_dev->dev_type.b[i/2]); | ||
63 | } | ||
75 | 64 | ||
76 | static void get_channel_info(struct hv_device *device, | 65 | static u8 channel_monitor_group(struct vmbus_channel *channel) |
77 | struct hv_device_info *info) | ||
78 | { | 66 | { |
79 | struct vmbus_channel_debug_info debug_info; | 67 | return (u8)channel->offermsg.monitorid / 32; |
68 | } | ||
80 | 69 | ||
81 | if (!device->channel) | 70 | static u8 channel_monitor_offset(struct vmbus_channel *channel) |
82 | return; | 71 | { |
72 | return (u8)channel->offermsg.monitorid % 32; | ||
73 | } | ||
83 | 74 | ||
84 | vmbus_get_debug_info(device->channel, &debug_info); | 75 | static u32 channel_pending(struct vmbus_channel *channel, |
76 | struct hv_monitor_page *monitor_page) | ||
77 | { | ||
78 | u8 monitor_group = channel_monitor_group(channel); | ||
79 | return monitor_page->trigger_group[monitor_group].pending; | ||
80 | } | ||
85 | 81 | ||
86 | info->chn_id = debug_info.relid; | 82 | static u32 channel_latency(struct vmbus_channel *channel, |
87 | info->chn_state = debug_info.state; | 83 | struct hv_monitor_page *monitor_page) |
88 | memcpy(&info->chn_type, &debug_info.interfacetype, | 84 | { |
89 | sizeof(uuid_le)); | 85 | u8 monitor_group = channel_monitor_group(channel); |
90 | memcpy(&info->chn_instance, &debug_info.interface_instance, | 86 | u8 monitor_offset = channel_monitor_offset(channel); |
91 | sizeof(uuid_le)); | 87 | return monitor_page->latency[monitor_group][monitor_offset]; |
88 | } | ||
92 | 89 | ||
93 | info->monitor_id = debug_info.monitorid; | 90 | static u32 channel_conn_id(struct vmbus_channel *channel, |
91 | struct hv_monitor_page *monitor_page) | ||
92 | { | ||
93 | u8 monitor_group = channel_monitor_group(channel); | ||
94 | u8 monitor_offset = channel_monitor_offset(channel); | ||
95 | return monitor_page->parameter[monitor_group][monitor_offset].connectionid.u.id; | ||
96 | } | ||
94 | 97 | ||
95 | info->server_monitor_pending = debug_info.servermonitor_pending; | 98 | static ssize_t id_show(struct device *dev, struct device_attribute *dev_attr, |
96 | info->server_monitor_latency = debug_info.servermonitor_latency; | 99 | char *buf) |
97 | info->server_monitor_conn_id = debug_info.servermonitor_connectionid; | 100 | { |
101 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
98 | 102 | ||
99 | info->client_monitor_pending = debug_info.clientmonitor_pending; | 103 | if (!hv_dev->channel) |
100 | info->client_monitor_latency = debug_info.clientmonitor_latency; | 104 | return -ENODEV; |
101 | info->client_monitor_conn_id = debug_info.clientmonitor_connectionid; | 105 | return sprintf(buf, "%d\n", hv_dev->channel->offermsg.child_relid); |
106 | } | ||
107 | static DEVICE_ATTR_RO(id); | ||
102 | 108 | ||
103 | info->inbound.int_mask = debug_info.inbound.current_interrupt_mask; | 109 | static ssize_t state_show(struct device *dev, struct device_attribute *dev_attr, |
104 | info->inbound.read_idx = debug_info.inbound.current_read_index; | 110 | char *buf) |
105 | info->inbound.write_idx = debug_info.inbound.current_write_index; | 111 | { |
106 | info->inbound.bytes_avail_toread = | 112 | struct hv_device *hv_dev = device_to_hv_device(dev); |
107 | debug_info.inbound.bytes_avail_toread; | ||
108 | info->inbound.bytes_avail_towrite = | ||
109 | debug_info.inbound.bytes_avail_towrite; | ||
110 | 113 | ||
111 | info->outbound.int_mask = | 114 | if (!hv_dev->channel) |
112 | debug_info.outbound.current_interrupt_mask; | 115 | return -ENODEV; |
113 | info->outbound.read_idx = debug_info.outbound.current_read_index; | 116 | return sprintf(buf, "%d\n", hv_dev->channel->state); |
114 | info->outbound.write_idx = debug_info.outbound.current_write_index; | ||
115 | info->outbound.bytes_avail_toread = | ||
116 | debug_info.outbound.bytes_avail_toread; | ||
117 | info->outbound.bytes_avail_towrite = | ||
118 | debug_info.outbound.bytes_avail_towrite; | ||
119 | } | 117 | } |
118 | static DEVICE_ATTR_RO(state); | ||
120 | 119 | ||
121 | #define VMBUS_ALIAS_LEN ((sizeof((struct hv_vmbus_device_id *)0)->guid) * 2) | 120 | static ssize_t monitor_id_show(struct device *dev, |
122 | static void print_alias_name(struct hv_device *hv_dev, char *alias_name) | 121 | struct device_attribute *dev_attr, char *buf) |
123 | { | 122 | { |
124 | int i; | 123 | struct hv_device *hv_dev = device_to_hv_device(dev); |
125 | for (i = 0; i < VMBUS_ALIAS_LEN; i += 2) | 124 | |
126 | sprintf(&alias_name[i], "%02x", hv_dev->dev_type.b[i/2]); | 125 | if (!hv_dev->channel) |
126 | return -ENODEV; | ||
127 | return sprintf(buf, "%d\n", hv_dev->channel->offermsg.monitorid); | ||
127 | } | 128 | } |
129 | static DEVICE_ATTR_RO(monitor_id); | ||
128 | 130 | ||
129 | /* | 131 | static ssize_t class_id_show(struct device *dev, |
130 | * vmbus_show_device_attr - Show the device attribute in sysfs. | 132 | struct device_attribute *dev_attr, char *buf) |
131 | * | 133 | { |
132 | * This is invoked when user does a | 134 | struct hv_device *hv_dev = device_to_hv_device(dev); |
133 | * "cat /sys/bus/vmbus/devices/<busdevice>/<attr name>" | 135 | |
134 | */ | 136 | if (!hv_dev->channel) |
135 | static ssize_t vmbus_show_device_attr(struct device *dev, | 137 | return -ENODEV; |
136 | struct device_attribute *dev_attr, | 138 | return sprintf(buf, "{%pUl}\n", |
137 | char *buf) | 139 | hv_dev->channel->offermsg.offer.if_type.b); |
140 | } | ||
141 | static DEVICE_ATTR_RO(class_id); | ||
142 | |||
143 | static ssize_t device_id_show(struct device *dev, | ||
144 | struct device_attribute *dev_attr, char *buf) | ||
145 | { | ||
146 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
147 | |||
148 | if (!hv_dev->channel) | ||
149 | return -ENODEV; | ||
150 | return sprintf(buf, "{%pUl}\n", | ||
151 | hv_dev->channel->offermsg.offer.if_instance.b); | ||
152 | } | ||
153 | static DEVICE_ATTR_RO(device_id); | ||
154 | |||
155 | static ssize_t modalias_show(struct device *dev, | ||
156 | struct device_attribute *dev_attr, char *buf) | ||
138 | { | 157 | { |
139 | struct hv_device *hv_dev = device_to_hv_device(dev); | 158 | struct hv_device *hv_dev = device_to_hv_device(dev); |
140 | struct hv_device_info *device_info; | ||
141 | char alias_name[VMBUS_ALIAS_LEN + 1]; | 159 | char alias_name[VMBUS_ALIAS_LEN + 1]; |
142 | int ret = 0; | ||
143 | 160 | ||
144 | device_info = kzalloc(sizeof(struct hv_device_info), GFP_KERNEL); | 161 | print_alias_name(hv_dev, alias_name); |
145 | if (!device_info) | 162 | return sprintf(buf, "vmbus:%s\n", alias_name); |
146 | return ret; | 163 | } |
164 | static DEVICE_ATTR_RO(modalias); | ||
147 | 165 | ||
148 | get_channel_info(hv_dev, device_info); | 166 | static ssize_t server_monitor_pending_show(struct device *dev, |
149 | 167 | struct device_attribute *dev_attr, | |
150 | if (!strcmp(dev_attr->attr.name, "class_id")) { | 168 | char *buf) |
151 | ret = sprintf(buf, "{%pUl}\n", device_info->chn_type.b); | 169 | { |
152 | } else if (!strcmp(dev_attr->attr.name, "device_id")) { | 170 | struct hv_device *hv_dev = device_to_hv_device(dev); |
153 | ret = sprintf(buf, "{%pUl}\n", device_info->chn_instance.b); | ||
154 | } else if (!strcmp(dev_attr->attr.name, "modalias")) { | ||
155 | print_alias_name(hv_dev, alias_name); | ||
156 | ret = sprintf(buf, "vmbus:%s\n", alias_name); | ||
157 | } else if (!strcmp(dev_attr->attr.name, "state")) { | ||
158 | ret = sprintf(buf, "%d\n", device_info->chn_state); | ||
159 | } else if (!strcmp(dev_attr->attr.name, "id")) { | ||
160 | ret = sprintf(buf, "%d\n", device_info->chn_id); | ||
161 | } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) { | ||
162 | ret = sprintf(buf, "%d\n", device_info->outbound.int_mask); | ||
163 | } else if (!strcmp(dev_attr->attr.name, "out_read_index")) { | ||
164 | ret = sprintf(buf, "%d\n", device_info->outbound.read_idx); | ||
165 | } else if (!strcmp(dev_attr->attr.name, "out_write_index")) { | ||
166 | ret = sprintf(buf, "%d\n", device_info->outbound.write_idx); | ||
167 | } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) { | ||
168 | ret = sprintf(buf, "%d\n", | ||
169 | device_info->outbound.bytes_avail_toread); | ||
170 | } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) { | ||
171 | ret = sprintf(buf, "%d\n", | ||
172 | device_info->outbound.bytes_avail_towrite); | ||
173 | } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) { | ||
174 | ret = sprintf(buf, "%d\n", device_info->inbound.int_mask); | ||
175 | } else if (!strcmp(dev_attr->attr.name, "in_read_index")) { | ||
176 | ret = sprintf(buf, "%d\n", device_info->inbound.read_idx); | ||
177 | } else if (!strcmp(dev_attr->attr.name, "in_write_index")) { | ||
178 | ret = sprintf(buf, "%d\n", device_info->inbound.write_idx); | ||
179 | } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) { | ||
180 | ret = sprintf(buf, "%d\n", | ||
181 | device_info->inbound.bytes_avail_toread); | ||
182 | } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) { | ||
183 | ret = sprintf(buf, "%d\n", | ||
184 | device_info->inbound.bytes_avail_towrite); | ||
185 | } else if (!strcmp(dev_attr->attr.name, "monitor_id")) { | ||
186 | ret = sprintf(buf, "%d\n", device_info->monitor_id); | ||
187 | } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) { | ||
188 | ret = sprintf(buf, "%d\n", device_info->server_monitor_pending); | ||
189 | } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) { | ||
190 | ret = sprintf(buf, "%d\n", device_info->server_monitor_latency); | ||
191 | } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) { | ||
192 | ret = sprintf(buf, "%d\n", | ||
193 | device_info->server_monitor_conn_id); | ||
194 | } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) { | ||
195 | ret = sprintf(buf, "%d\n", device_info->client_monitor_pending); | ||
196 | } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) { | ||
197 | ret = sprintf(buf, "%d\n", device_info->client_monitor_latency); | ||
198 | } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) { | ||
199 | ret = sprintf(buf, "%d\n", | ||
200 | device_info->client_monitor_conn_id); | ||
201 | } | ||
202 | 171 | ||
203 | kfree(device_info); | 172 | if (!hv_dev->channel) |
204 | return ret; | 173 | return -ENODEV; |
174 | return sprintf(buf, "%d\n", | ||
175 | channel_pending(hv_dev->channel, | ||
176 | vmbus_connection.monitor_pages[1])); | ||
177 | } | ||
178 | static DEVICE_ATTR_RO(server_monitor_pending); | ||
179 | |||
180 | static ssize_t client_monitor_pending_show(struct device *dev, | ||
181 | struct device_attribute *dev_attr, | ||
182 | char *buf) | ||
183 | { | ||
184 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
185 | |||
186 | if (!hv_dev->channel) | ||
187 | return -ENODEV; | ||
188 | return sprintf(buf, "%d\n", | ||
189 | channel_pending(hv_dev->channel, | ||
190 | vmbus_connection.monitor_pages[1])); | ||
191 | } | ||
192 | static DEVICE_ATTR_RO(client_monitor_pending); | ||
193 | |||
194 | static ssize_t server_monitor_latency_show(struct device *dev, | ||
195 | struct device_attribute *dev_attr, | ||
196 | char *buf) | ||
197 | { | ||
198 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
199 | |||
200 | if (!hv_dev->channel) | ||
201 | return -ENODEV; | ||
202 | return sprintf(buf, "%d\n", | ||
203 | channel_latency(hv_dev->channel, | ||
204 | vmbus_connection.monitor_pages[0])); | ||
205 | } | ||
206 | static DEVICE_ATTR_RO(server_monitor_latency); | ||
207 | |||
208 | static ssize_t client_monitor_latency_show(struct device *dev, | ||
209 | struct device_attribute *dev_attr, | ||
210 | char *buf) | ||
211 | { | ||
212 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
213 | |||
214 | if (!hv_dev->channel) | ||
215 | return -ENODEV; | ||
216 | return sprintf(buf, "%d\n", | ||
217 | channel_latency(hv_dev->channel, | ||
218 | vmbus_connection.monitor_pages[1])); | ||
219 | } | ||
220 | static DEVICE_ATTR_RO(client_monitor_latency); | ||
221 | |||
222 | static ssize_t server_monitor_conn_id_show(struct device *dev, | ||
223 | struct device_attribute *dev_attr, | ||
224 | char *buf) | ||
225 | { | ||
226 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
227 | |||
228 | if (!hv_dev->channel) | ||
229 | return -ENODEV; | ||
230 | return sprintf(buf, "%d\n", | ||
231 | channel_conn_id(hv_dev->channel, | ||
232 | vmbus_connection.monitor_pages[0])); | ||
233 | } | ||
234 | static DEVICE_ATTR_RO(server_monitor_conn_id); | ||
235 | |||
236 | static ssize_t client_monitor_conn_id_show(struct device *dev, | ||
237 | struct device_attribute *dev_attr, | ||
238 | char *buf) | ||
239 | { | ||
240 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
241 | |||
242 | if (!hv_dev->channel) | ||
243 | return -ENODEV; | ||
244 | return sprintf(buf, "%d\n", | ||
245 | channel_conn_id(hv_dev->channel, | ||
246 | vmbus_connection.monitor_pages[1])); | ||
247 | } | ||
248 | static DEVICE_ATTR_RO(client_monitor_conn_id); | ||
249 | |||
250 | static ssize_t out_intr_mask_show(struct device *dev, | ||
251 | struct device_attribute *dev_attr, char *buf) | ||
252 | { | ||
253 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
254 | struct hv_ring_buffer_debug_info outbound; | ||
255 | |||
256 | if (!hv_dev->channel) | ||
257 | return -ENODEV; | ||
258 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | ||
259 | return sprintf(buf, "%d\n", outbound.current_interrupt_mask); | ||
260 | } | ||
261 | static DEVICE_ATTR_RO(out_intr_mask); | ||
262 | |||
263 | static ssize_t out_read_index_show(struct device *dev, | ||
264 | struct device_attribute *dev_attr, char *buf) | ||
265 | { | ||
266 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
267 | struct hv_ring_buffer_debug_info outbound; | ||
268 | |||
269 | if (!hv_dev->channel) | ||
270 | return -ENODEV; | ||
271 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | ||
272 | return sprintf(buf, "%d\n", outbound.current_read_index); | ||
273 | } | ||
274 | static DEVICE_ATTR_RO(out_read_index); | ||
275 | |||
276 | static ssize_t out_write_index_show(struct device *dev, | ||
277 | struct device_attribute *dev_attr, | ||
278 | char *buf) | ||
279 | { | ||
280 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
281 | struct hv_ring_buffer_debug_info outbound; | ||
282 | |||
283 | if (!hv_dev->channel) | ||
284 | return -ENODEV; | ||
285 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | ||
286 | return sprintf(buf, "%d\n", outbound.current_write_index); | ||
287 | } | ||
288 | static DEVICE_ATTR_RO(out_write_index); | ||
289 | |||
290 | static ssize_t out_read_bytes_avail_show(struct device *dev, | ||
291 | struct device_attribute *dev_attr, | ||
292 | char *buf) | ||
293 | { | ||
294 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
295 | struct hv_ring_buffer_debug_info outbound; | ||
296 | |||
297 | if (!hv_dev->channel) | ||
298 | return -ENODEV; | ||
299 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | ||
300 | return sprintf(buf, "%d\n", outbound.bytes_avail_toread); | ||
205 | } | 301 | } |
302 | static DEVICE_ATTR_RO(out_read_bytes_avail); | ||
303 | |||
304 | static ssize_t out_write_bytes_avail_show(struct device *dev, | ||
305 | struct device_attribute *dev_attr, | ||
306 | char *buf) | ||
307 | { | ||
308 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
309 | struct hv_ring_buffer_debug_info outbound; | ||
310 | |||
311 | if (!hv_dev->channel) | ||
312 | return -ENODEV; | ||
313 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); | ||
314 | return sprintf(buf, "%d\n", outbound.bytes_avail_towrite); | ||
315 | } | ||
316 | static DEVICE_ATTR_RO(out_write_bytes_avail); | ||
317 | |||
318 | static ssize_t in_intr_mask_show(struct device *dev, | ||
319 | struct device_attribute *dev_attr, char *buf) | ||
320 | { | ||
321 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
322 | struct hv_ring_buffer_debug_info inbound; | ||
323 | |||
324 | if (!hv_dev->channel) | ||
325 | return -ENODEV; | ||
326 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | ||
327 | return sprintf(buf, "%d\n", inbound.current_interrupt_mask); | ||
328 | } | ||
329 | static DEVICE_ATTR_RO(in_intr_mask); | ||
330 | |||
331 | static ssize_t in_read_index_show(struct device *dev, | ||
332 | struct device_attribute *dev_attr, char *buf) | ||
333 | { | ||
334 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
335 | struct hv_ring_buffer_debug_info inbound; | ||
336 | |||
337 | if (!hv_dev->channel) | ||
338 | return -ENODEV; | ||
339 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | ||
340 | return sprintf(buf, "%d\n", inbound.current_read_index); | ||
341 | } | ||
342 | static DEVICE_ATTR_RO(in_read_index); | ||
343 | |||
344 | static ssize_t in_write_index_show(struct device *dev, | ||
345 | struct device_attribute *dev_attr, char *buf) | ||
346 | { | ||
347 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
348 | struct hv_ring_buffer_debug_info inbound; | ||
349 | |||
350 | if (!hv_dev->channel) | ||
351 | return -ENODEV; | ||
352 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | ||
353 | return sprintf(buf, "%d\n", inbound.current_write_index); | ||
354 | } | ||
355 | static DEVICE_ATTR_RO(in_write_index); | ||
356 | |||
357 | static ssize_t in_read_bytes_avail_show(struct device *dev, | ||
358 | struct device_attribute *dev_attr, | ||
359 | char *buf) | ||
360 | { | ||
361 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
362 | struct hv_ring_buffer_debug_info inbound; | ||
363 | |||
364 | if (!hv_dev->channel) | ||
365 | return -ENODEV; | ||
366 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | ||
367 | return sprintf(buf, "%d\n", inbound.bytes_avail_toread); | ||
368 | } | ||
369 | static DEVICE_ATTR_RO(in_read_bytes_avail); | ||
370 | |||
371 | static ssize_t in_write_bytes_avail_show(struct device *dev, | ||
372 | struct device_attribute *dev_attr, | ||
373 | char *buf) | ||
374 | { | ||
375 | struct hv_device *hv_dev = device_to_hv_device(dev); | ||
376 | struct hv_ring_buffer_debug_info inbound; | ||
377 | |||
378 | if (!hv_dev->channel) | ||
379 | return -ENODEV; | ||
380 | hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); | ||
381 | return sprintf(buf, "%d\n", inbound.bytes_avail_towrite); | ||
382 | } | ||
383 | static DEVICE_ATTR_RO(in_write_bytes_avail); | ||
206 | 384 | ||
207 | /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */ | 385 | /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */ |
208 | static struct device_attribute vmbus_device_attrs[] = { | 386 | static struct attribute *vmbus_attrs[] = { |
209 | __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL), | 387 | &dev_attr_id.attr, |
210 | __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL), | 388 | &dev_attr_state.attr, |
211 | __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL), | 389 | &dev_attr_monitor_id.attr, |
212 | __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL), | 390 | &dev_attr_class_id.attr, |
213 | __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL), | 391 | &dev_attr_device_id.attr, |
214 | __ATTR(modalias, S_IRUGO, vmbus_show_device_attr, NULL), | 392 | &dev_attr_modalias.attr, |
215 | 393 | &dev_attr_server_monitor_pending.attr, | |
216 | __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), | 394 | &dev_attr_client_monitor_pending.attr, |
217 | __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), | 395 | &dev_attr_server_monitor_latency.attr, |
218 | __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), | 396 | &dev_attr_client_monitor_latency.attr, |
219 | 397 | &dev_attr_server_monitor_conn_id.attr, | |
220 | __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), | 398 | &dev_attr_client_monitor_conn_id.attr, |
221 | __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), | 399 | &dev_attr_out_intr_mask.attr, |
222 | __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), | 400 | &dev_attr_out_read_index.attr, |
223 | 401 | &dev_attr_out_write_index.attr, | |
224 | __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), | 402 | &dev_attr_out_read_bytes_avail.attr, |
225 | __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL), | 403 | &dev_attr_out_write_bytes_avail.attr, |
226 | __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL), | 404 | &dev_attr_in_intr_mask.attr, |
227 | __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | 405 | &dev_attr_in_read_index.attr, |
228 | __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | 406 | &dev_attr_in_write_index.attr, |
229 | 407 | &dev_attr_in_read_bytes_avail.attr, | |
230 | __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), | 408 | &dev_attr_in_write_bytes_avail.attr, |
231 | __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL), | 409 | NULL, |
232 | __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL), | ||
233 | __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | ||
234 | __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | ||
235 | __ATTR_NULL | ||
236 | }; | 410 | }; |
237 | 411 | ATTRIBUTE_GROUPS(vmbus); | |
238 | 412 | ||
239 | /* | 413 | /* |
240 | * vmbus_uevent - add uevent for our device | 414 | * vmbus_uevent - add uevent for our device |
@@ -383,7 +557,7 @@ static struct bus_type hv_bus = { | |||
383 | .remove = vmbus_remove, | 557 | .remove = vmbus_remove, |
384 | .probe = vmbus_probe, | 558 | .probe = vmbus_probe, |
385 | .uevent = vmbus_uevent, | 559 | .uevent = vmbus_uevent, |
386 | .dev_attrs = vmbus_device_attrs, | 560 | .dev_groups = vmbus_groups, |
387 | }; | 561 | }; |
388 | 562 | ||
389 | static const char *driver_name = "hyperv"; | 563 | static const char *driver_name = "hyperv"; |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8dacd4c9ee87..e760715bd9cb 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -537,4 +537,5 @@ source "drivers/misc/carma/Kconfig" | |||
537 | source "drivers/misc/altera-stapl/Kconfig" | 537 | source "drivers/misc/altera-stapl/Kconfig" |
538 | source "drivers/misc/mei/Kconfig" | 538 | source "drivers/misc/mei/Kconfig" |
539 | source "drivers/misc/vmw_vmci/Kconfig" | 539 | source "drivers/misc/vmw_vmci/Kconfig" |
540 | source "drivers/misc/mic/Kconfig" | ||
540 | endmenu | 541 | endmenu |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c235d5b68311..0b7ea3ea8bb8 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -53,3 +53,4 @@ obj-$(CONFIG_INTEL_MEI) += mei/ | |||
53 | obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ | 53 | obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ |
54 | obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o | 54 | obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o |
55 | obj-$(CONFIG_SRAM) += sram.o | 55 | obj-$(CONFIG_SRAM) += sram.o |
56 | obj-y += mic/ | ||
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index 849e2fed4da2..2704d885a9b3 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c | |||
@@ -374,7 +374,7 @@ int bmp085_detect(struct device *dev) | |||
374 | } | 374 | } |
375 | EXPORT_SYMBOL_GPL(bmp085_detect); | 375 | EXPORT_SYMBOL_GPL(bmp085_detect); |
376 | 376 | ||
377 | static void __init bmp085_get_of_properties(struct bmp085_data *data) | 377 | static void bmp085_get_of_properties(struct bmp085_data *data) |
378 | { | 378 | { |
379 | #ifdef CONFIG_OF | 379 | #ifdef CONFIG_OF |
380 | struct device_node *np = data->dev->of_node; | 380 | struct device_node *np = data->dev->of_node; |
diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 2e50f811ff59..fb397e7d1cce 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c | |||
@@ -176,7 +176,7 @@ static int cb710_suspend(struct pci_dev *pdev, pm_message_t state) | |||
176 | { | 176 | { |
177 | struct cb710_chip *chip = pci_get_drvdata(pdev); | 177 | struct cb710_chip *chip = pci_get_drvdata(pdev); |
178 | 178 | ||
179 | free_irq(pdev->irq, chip); | 179 | devm_free_irq(&pdev->dev, pdev->irq, chip); |
180 | pci_save_state(pdev); | 180 | pci_save_state(pdev); |
181 | pci_disable_device(pdev); | 181 | pci_disable_device(pdev); |
182 | if (state.event & PM_EVENT_SLEEP) | 182 | if (state.event & PM_EVENT_SLEEP) |
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 04f2e1fa9dd1..9536852fd4c6 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig | |||
@@ -96,4 +96,17 @@ config EEPROM_DIGSY_MTC_CFG | |||
96 | 96 | ||
97 | If unsure, say N. | 97 | If unsure, say N. |
98 | 98 | ||
99 | config EEPROM_SUNXI_SID | ||
100 | tristate "Allwinner sunxi security ID support" | ||
101 | depends on ARCH_SUNXI && SYSFS | ||
102 | help | ||
103 | This is a driver for the 'security ID' available on various Allwinner | ||
104 | devices. | ||
105 | |||
106 | Due to the potential risks involved with changing e-fuses, | ||
107 | this driver is read-only. | ||
108 | |||
109 | This driver can also be built as a module. If so, the module | ||
110 | will be called sunxi_sid. | ||
111 | |||
99 | endmenu | 112 | endmenu |
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index fc1e81d29267..9507aec95e94 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile | |||
@@ -4,4 +4,5 @@ obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o | |||
4 | obj-$(CONFIG_EEPROM_MAX6875) += max6875.o | 4 | obj-$(CONFIG_EEPROM_MAX6875) += max6875.o |
5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o | 5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o |
6 | obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o | 6 | obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o |
7 | obj-$(CONFIG_EEPROM_SUNXI_SID) += sunxi_sid.o | ||
7 | obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o | 8 | obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o |
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c new file mode 100644 index 000000000000..9c34e5704304 --- /dev/null +++ b/drivers/misc/eeprom/sunxi_sid.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl> | ||
3 | * http://www.linux-sunxi.org | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * This driver exposes the Allwinner security ID, efuses exported in byte- | ||
16 | * sized chunks. | ||
17 | */ | ||
18 | |||
19 | #include <linux/compiler.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/export.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/kobject.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/of_device.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/random.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/stat.h> | ||
34 | #include <linux/sysfs.h> | ||
35 | #include <linux/types.h> | ||
36 | |||
37 | #define DRV_NAME "sunxi-sid" | ||
38 | |||
39 | struct sunxi_sid_data { | ||
40 | void __iomem *reg_base; | ||
41 | unsigned int keysize; | ||
42 | }; | ||
43 | |||
44 | /* We read the entire key, due to a 32 bit read alignment requirement. Since we | ||
45 | * want to return the requested byte, this results in somewhat slower code and | ||
46 | * uses 4 times more reads as needed but keeps code simpler. Since the SID is | ||
47 | * only very rarely probed, this is not really an issue. | ||
48 | */ | ||
49 | static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data, | ||
50 | const unsigned int offset) | ||
51 | { | ||
52 | u32 sid_key; | ||
53 | |||
54 | if (offset >= sid_data->keysize) | ||
55 | return 0; | ||
56 | |||
57 | sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4)); | ||
58 | sid_key >>= (offset % 4) * 8; | ||
59 | |||
60 | return sid_key; /* Only return the last byte */ | ||
61 | } | ||
62 | |||
63 | static ssize_t sid_read(struct file *fd, struct kobject *kobj, | ||
64 | struct bin_attribute *attr, char *buf, | ||
65 | loff_t pos, size_t size) | ||
66 | { | ||
67 | struct platform_device *pdev; | ||
68 | struct sunxi_sid_data *sid_data; | ||
69 | int i; | ||
70 | |||
71 | pdev = to_platform_device(kobj_to_dev(kobj)); | ||
72 | sid_data = platform_get_drvdata(pdev); | ||
73 | |||
74 | if (pos < 0 || pos >= sid_data->keysize) | ||
75 | return 0; | ||
76 | if (size > sid_data->keysize - pos) | ||
77 | size = sid_data->keysize - pos; | ||
78 | |||
79 | for (i = 0; i < size; i++) | ||
80 | buf[i] = sunxi_sid_read_byte(sid_data, pos + i); | ||
81 | |||
82 | return i; | ||
83 | } | ||
84 | |||
85 | static struct bin_attribute sid_bin_attr = { | ||
86 | .attr = { .name = "eeprom", .mode = S_IRUGO, }, | ||
87 | .read = sid_read, | ||
88 | }; | ||
89 | |||
90 | static int sunxi_sid_remove(struct platform_device *pdev) | ||
91 | { | ||
92 | device_remove_bin_file(&pdev->dev, &sid_bin_attr); | ||
93 | dev_dbg(&pdev->dev, "driver unloaded\n"); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static const struct of_device_id sunxi_sid_of_match[] = { | ||
99 | { .compatible = "allwinner,sun4i-sid", .data = (void *)16}, | ||
100 | { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512}, | ||
101 | {/* sentinel */}, | ||
102 | }; | ||
103 | MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); | ||
104 | |||
105 | static int sunxi_sid_probe(struct platform_device *pdev) | ||
106 | { | ||
107 | struct sunxi_sid_data *sid_data; | ||
108 | struct resource *res; | ||
109 | const struct of_device_id *of_dev_id; | ||
110 | u8 *entropy; | ||
111 | unsigned int i; | ||
112 | |||
113 | sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data), | ||
114 | GFP_KERNEL); | ||
115 | if (!sid_data) | ||
116 | return -ENOMEM; | ||
117 | |||
118 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
119 | sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
120 | if (IS_ERR(sid_data->reg_base)) | ||
121 | return PTR_ERR(sid_data->reg_base); | ||
122 | |||
123 | of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev); | ||
124 | if (!of_dev_id) | ||
125 | return -ENODEV; | ||
126 | sid_data->keysize = (int)of_dev_id->data; | ||
127 | |||
128 | platform_set_drvdata(pdev, sid_data); | ||
129 | |||
130 | sid_bin_attr.size = sid_data->keysize; | ||
131 | if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) | ||
132 | return -ENODEV; | ||
133 | |||
134 | entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL); | ||
135 | for (i = 0; i < sid_data->keysize; i++) | ||
136 | entropy[i] = sunxi_sid_read_byte(sid_data, i); | ||
137 | add_device_randomness(entropy, sid_data->keysize); | ||
138 | kfree(entropy); | ||
139 | |||
140 | dev_dbg(&pdev->dev, "loaded\n"); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static struct platform_driver sunxi_sid_driver = { | ||
146 | .probe = sunxi_sid_probe, | ||
147 | .remove = sunxi_sid_remove, | ||
148 | .driver = { | ||
149 | .name = DRV_NAME, | ||
150 | .owner = THIS_MODULE, | ||
151 | .of_match_table = sunxi_sid_of_match, | ||
152 | }, | ||
153 | }; | ||
154 | module_platform_driver(sunxi_sid_driver); | ||
155 | |||
156 | MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>"); | ||
157 | MODULE_DESCRIPTION("Allwinner sunxi security id driver"); | ||
158 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 0346d87c5fed..6b3bf9ab051d 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c | |||
@@ -153,7 +153,6 @@ error_ioremap: | |||
153 | error_heartbeat: | 153 | error_heartbeat: |
154 | ibmasm_event_buffer_exit(sp); | 154 | ibmasm_event_buffer_exit(sp); |
155 | error_eventbuffer: | 155 | error_eventbuffer: |
156 | pci_set_drvdata(pdev, NULL); | ||
157 | kfree(sp); | 156 | kfree(sp); |
158 | error_kmalloc: | 157 | error_kmalloc: |
159 | pci_release_regions(pdev); | 158 | pci_release_regions(pdev); |
@@ -165,7 +164,7 @@ error_resources: | |||
165 | 164 | ||
166 | static void ibmasm_remove_one(struct pci_dev *pdev) | 165 | static void ibmasm_remove_one(struct pci_dev *pdev) |
167 | { | 166 | { |
168 | struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev); | 167 | struct service_processor *sp = pci_get_drvdata(pdev); |
169 | 168 | ||
170 | dbg("Unregistering UART\n"); | 169 | dbg("Unregistering UART\n"); |
171 | ibmasm_unregister_uart(sp); | 170 | ibmasm_unregister_uart(sp); |
@@ -182,7 +181,6 @@ static void ibmasm_remove_one(struct pci_dev *pdev) | |||
182 | ibmasm_free_remote_input_dev(sp); | 181 | ibmasm_free_remote_input_dev(sp); |
183 | iounmap(sp->base_address); | 182 | iounmap(sp->base_address); |
184 | ibmasm_event_buffer_exit(sp); | 183 | ibmasm_event_buffer_exit(sp); |
185 | pci_set_drvdata(pdev, NULL); | ||
186 | kfree(sp); | 184 | kfree(sp); |
187 | pci_release_regions(pdev); | 185 | pci_release_regions(pdev); |
188 | pci_disable_device(pdev); | 186 | pci_disable_device(pdev); |
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index d0fdc134068a..04fd38567729 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -312,13 +312,13 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) | |||
312 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; | 312 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; |
313 | mei_hdr.reserved = 0; | 313 | mei_hdr.reserved = 0; |
314 | dev->iamthif_msg_buf_index += mei_hdr.length; | 314 | dev->iamthif_msg_buf_index += mei_hdr.length; |
315 | if (mei_write_message(dev, &mei_hdr, | 315 | ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf); |
316 | (unsigned char *)dev->iamthif_msg_buf)) | 316 | if (ret) |
317 | return -ENODEV; | 317 | return ret; |
318 | 318 | ||
319 | if (mei_hdr.msg_complete) { | 319 | if (mei_hdr.msg_complete) { |
320 | if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl)) | 320 | if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl)) |
321 | return -ENODEV; | 321 | return -EIO; |
322 | dev->iamthif_flow_control_pending = true; | 322 | dev->iamthif_flow_control_pending = true; |
323 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; | 323 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; |
324 | dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n"); | 324 | dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n"); |
@@ -458,6 +458,16 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
458 | struct mei_msg_hdr mei_hdr; | 458 | struct mei_msg_hdr mei_hdr; |
459 | size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; | 459 | size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; |
460 | u32 msg_slots = mei_data2slots(len); | 460 | u32 msg_slots = mei_data2slots(len); |
461 | int rets; | ||
462 | |||
463 | rets = mei_cl_flow_ctrl_creds(cl); | ||
464 | if (rets < 0) | ||
465 | return rets; | ||
466 | |||
467 | if (rets == 0) { | ||
468 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); | ||
469 | return 0; | ||
470 | } | ||
461 | 471 | ||
462 | mei_hdr.host_addr = cl->host_client_id; | 472 | mei_hdr.host_addr = cl->host_client_id; |
463 | mei_hdr.me_addr = cl->me_client_id; | 473 | mei_hdr.me_addr = cl->me_client_id; |
@@ -480,16 +490,17 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
480 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); | 490 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); |
481 | 491 | ||
482 | *slots -= msg_slots; | 492 | *slots -= msg_slots; |
483 | if (mei_write_message(dev, &mei_hdr, | 493 | rets = mei_write_message(dev, &mei_hdr, |
484 | dev->iamthif_msg_buf + dev->iamthif_msg_buf_index)) { | 494 | dev->iamthif_msg_buf + dev->iamthif_msg_buf_index); |
485 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 495 | if (rets) { |
486 | cl->status = -ENODEV; | 496 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
487 | list_del(&cb->list); | 497 | cl->status = rets; |
488 | return -ENODEV; | 498 | list_del(&cb->list); |
499 | return rets; | ||
489 | } | 500 | } |
490 | 501 | ||
491 | if (mei_cl_flow_ctrl_reduce(cl)) | 502 | if (mei_cl_flow_ctrl_reduce(cl)) |
492 | return -ENODEV; | 503 | return -EIO; |
493 | 504 | ||
494 | dev->iamthif_msg_buf_index += mei_hdr.length; | 505 | dev->iamthif_msg_buf_index += mei_hdr.length; |
495 | cl->status = 0; | 506 | cl->status = 0; |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e0684b4d9a08..fbd319c506e6 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -187,10 +187,14 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) | |||
187 | */ | 187 | */ |
188 | int mei_cl_flush_queues(struct mei_cl *cl) | 188 | int mei_cl_flush_queues(struct mei_cl *cl) |
189 | { | 189 | { |
190 | struct mei_device *dev; | ||
191 | |||
190 | if (WARN_ON(!cl || !cl->dev)) | 192 | if (WARN_ON(!cl || !cl->dev)) |
191 | return -EINVAL; | 193 | return -EINVAL; |
192 | 194 | ||
193 | dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); | 195 | dev = cl->dev; |
196 | |||
197 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); | ||
194 | mei_io_list_flush(&cl->dev->read_list, cl); | 198 | mei_io_list_flush(&cl->dev->read_list, cl); |
195 | mei_io_list_flush(&cl->dev->write_list, cl); | 199 | mei_io_list_flush(&cl->dev->write_list, cl); |
196 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); | 200 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); |
@@ -287,6 +291,12 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
287 | return -ENOENT; | 291 | return -ENOENT; |
288 | } | 292 | } |
289 | 293 | ||
294 | if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { | ||
295 | dev_err(&dev->pdev->dev, "open_handle_count exceded %d", | ||
296 | MEI_MAX_OPEN_HANDLE_COUNT); | ||
297 | return -ENOENT; | ||
298 | } | ||
299 | |||
290 | dev->open_handle_count++; | 300 | dev->open_handle_count++; |
291 | 301 | ||
292 | cl->host_client_id = id; | 302 | cl->host_client_id = id; |
@@ -296,7 +306,7 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
296 | 306 | ||
297 | cl->state = MEI_FILE_INITIALIZING; | 307 | cl->state = MEI_FILE_INITIALIZING; |
298 | 308 | ||
299 | dev_dbg(&dev->pdev->dev, "link cl host id = %d\n", cl->host_client_id); | 309 | cl_dbg(dev, cl, "link cl\n"); |
300 | return 0; | 310 | return 0; |
301 | } | 311 | } |
302 | 312 | ||
@@ -308,7 +318,6 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
308 | int mei_cl_unlink(struct mei_cl *cl) | 318 | int mei_cl_unlink(struct mei_cl *cl) |
309 | { | 319 | { |
310 | struct mei_device *dev; | 320 | struct mei_device *dev; |
311 | struct mei_cl *pos, *next; | ||
312 | 321 | ||
313 | /* don't shout on error exit path */ | 322 | /* don't shout on error exit path */ |
314 | if (!cl) | 323 | if (!cl) |
@@ -320,14 +329,10 @@ int mei_cl_unlink(struct mei_cl *cl) | |||
320 | 329 | ||
321 | dev = cl->dev; | 330 | dev = cl->dev; |
322 | 331 | ||
323 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { | 332 | cl_dbg(dev, cl, "unlink client"); |
324 | if (cl->host_client_id == pos->host_client_id) { | 333 | |
325 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", | 334 | list_del_init(&cl->link); |
326 | pos->host_client_id, pos->me_client_id); | 335 | |
327 | list_del_init(&pos->link); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | return 0; | 336 | return 0; |
332 | } | 337 | } |
333 | 338 | ||
@@ -390,6 +395,8 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
390 | 395 | ||
391 | dev = cl->dev; | 396 | dev = cl->dev; |
392 | 397 | ||
398 | cl_dbg(dev, cl, "disconnecting"); | ||
399 | |||
393 | if (cl->state != MEI_FILE_DISCONNECTING) | 400 | if (cl->state != MEI_FILE_DISCONNECTING) |
394 | return 0; | 401 | return 0; |
395 | 402 | ||
@@ -402,13 +409,13 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
402 | dev->hbuf_is_ready = false; | 409 | dev->hbuf_is_ready = false; |
403 | if (mei_hbm_cl_disconnect_req(dev, cl)) { | 410 | if (mei_hbm_cl_disconnect_req(dev, cl)) { |
404 | rets = -ENODEV; | 411 | rets = -ENODEV; |
405 | dev_err(&dev->pdev->dev, "failed to disconnect.\n"); | 412 | cl_err(dev, cl, "failed to disconnect.\n"); |
406 | goto free; | 413 | goto free; |
407 | } | 414 | } |
408 | mdelay(10); /* Wait for hardware disconnection ready */ | 415 | mdelay(10); /* Wait for hardware disconnection ready */ |
409 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | 416 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
410 | } else { | 417 | } else { |
411 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); | 418 | cl_dbg(dev, cl, "add disconnect cb to control write list\n"); |
412 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | 419 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
413 | 420 | ||
414 | } | 421 | } |
@@ -421,18 +428,17 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
421 | mutex_lock(&dev->device_lock); | 428 | mutex_lock(&dev->device_lock); |
422 | if (MEI_FILE_DISCONNECTED == cl->state) { | 429 | if (MEI_FILE_DISCONNECTED == cl->state) { |
423 | rets = 0; | 430 | rets = 0; |
424 | dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); | 431 | cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); |
425 | } else { | 432 | } else { |
426 | rets = -ENODEV; | 433 | rets = -ENODEV; |
427 | if (MEI_FILE_DISCONNECTED != cl->state) | 434 | if (MEI_FILE_DISCONNECTED != cl->state) |
428 | dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); | 435 | cl_err(dev, cl, "wrong status client disconnect.\n"); |
429 | 436 | ||
430 | if (err) | 437 | if (err) |
431 | dev_dbg(&dev->pdev->dev, | 438 | cl_dbg(dev, cl, "wait failed disconnect err=%08x\n", |
432 | "wait failed disconnect err=%08x\n", | ||
433 | err); | 439 | err); |
434 | 440 | ||
435 | dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); | 441 | cl_err(dev, cl, "failed to disconnect from FW client.\n"); |
436 | } | 442 | } |
437 | 443 | ||
438 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 444 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
@@ -639,13 +645,12 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
639 | return -ENODEV; | 645 | return -ENODEV; |
640 | 646 | ||
641 | if (cl->read_cb) { | 647 | if (cl->read_cb) { |
642 | dev_dbg(&dev->pdev->dev, "read is pending.\n"); | 648 | cl_dbg(dev, cl, "read is pending.\n"); |
643 | return -EBUSY; | 649 | return -EBUSY; |
644 | } | 650 | } |
645 | i = mei_me_cl_by_id(dev, cl->me_client_id); | 651 | i = mei_me_cl_by_id(dev, cl->me_client_id); |
646 | if (i < 0) { | 652 | if (i < 0) { |
647 | dev_err(&dev->pdev->dev, "no such me client %d\n", | 653 | cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); |
648 | cl->me_client_id); | ||
649 | return -ENODEV; | 654 | return -ENODEV; |
650 | } | 655 | } |
651 | 656 | ||
@@ -664,6 +669,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
664 | if (dev->hbuf_is_ready) { | 669 | if (dev->hbuf_is_ready) { |
665 | dev->hbuf_is_ready = false; | 670 | dev->hbuf_is_ready = false; |
666 | if (mei_hbm_cl_flow_control_req(dev, cl)) { | 671 | if (mei_hbm_cl_flow_control_req(dev, cl)) { |
672 | cl_err(dev, cl, "flow control send failed\n"); | ||
667 | rets = -ENODEV; | 673 | rets = -ENODEV; |
668 | goto err; | 674 | goto err; |
669 | } | 675 | } |
@@ -691,10 +697,32 @@ err: | |||
691 | int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | 697 | int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, |
692 | s32 *slots, struct mei_cl_cb *cmpl_list) | 698 | s32 *slots, struct mei_cl_cb *cmpl_list) |
693 | { | 699 | { |
694 | struct mei_device *dev = cl->dev; | 700 | struct mei_device *dev; |
701 | struct mei_msg_data *buf; | ||
695 | struct mei_msg_hdr mei_hdr; | 702 | struct mei_msg_hdr mei_hdr; |
696 | size_t len = cb->request_buffer.size - cb->buf_idx; | 703 | size_t len; |
697 | u32 msg_slots = mei_data2slots(len); | 704 | u32 msg_slots; |
705 | int rets; | ||
706 | |||
707 | |||
708 | if (WARN_ON(!cl || !cl->dev)) | ||
709 | return -ENODEV; | ||
710 | |||
711 | dev = cl->dev; | ||
712 | |||
713 | buf = &cb->request_buffer; | ||
714 | |||
715 | rets = mei_cl_flow_ctrl_creds(cl); | ||
716 | if (rets < 0) | ||
717 | return rets; | ||
718 | |||
719 | if (rets == 0) { | ||
720 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); | ||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | len = buf->size - cb->buf_idx; | ||
725 | msg_slots = mei_data2slots(len); | ||
698 | 726 | ||
699 | mei_hdr.host_addr = cl->host_client_id; | 727 | mei_hdr.host_addr = cl->host_client_id; |
700 | mei_hdr.me_addr = cl->me_client_id; | 728 | mei_hdr.me_addr = cl->me_client_id; |
@@ -714,16 +742,15 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
714 | return 0; | 742 | return 0; |
715 | } | 743 | } |
716 | 744 | ||
717 | dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", | 745 | cl_dbg(dev, cl, "buf: size = %d idx = %lu\n", |
718 | cb->request_buffer.size, cb->buf_idx); | 746 | cb->request_buffer.size, cb->buf_idx); |
719 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); | ||
720 | 747 | ||
721 | *slots -= msg_slots; | 748 | *slots -= msg_slots; |
722 | if (mei_write_message(dev, &mei_hdr, | 749 | rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); |
723 | cb->request_buffer.data + cb->buf_idx)) { | 750 | if (rets) { |
724 | cl->status = -ENODEV; | 751 | cl->status = rets; |
725 | list_move_tail(&cb->list, &cmpl_list->list); | 752 | list_move_tail(&cb->list, &cmpl_list->list); |
726 | return -ENODEV; | 753 | return rets; |
727 | } | 754 | } |
728 | 755 | ||
729 | cl->status = 0; | 756 | cl->status = 0; |
@@ -732,7 +759,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
732 | 759 | ||
733 | if (mei_hdr.msg_complete) { | 760 | if (mei_hdr.msg_complete) { |
734 | if (mei_cl_flow_ctrl_reduce(cl)) | 761 | if (mei_cl_flow_ctrl_reduce(cl)) |
735 | return -ENODEV; | 762 | return -EIO; |
736 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | 763 | list_move_tail(&cb->list, &dev->write_waiting_list.list); |
737 | } | 764 | } |
738 | 765 | ||
@@ -767,7 +794,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
767 | 794 | ||
768 | buf = &cb->request_buffer; | 795 | buf = &cb->request_buffer; |
769 | 796 | ||
770 | dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size); | 797 | cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); |
771 | 798 | ||
772 | 799 | ||
773 | cb->fop_type = MEI_FOP_WRITE; | 800 | cb->fop_type = MEI_FOP_WRITE; |
@@ -800,14 +827,10 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
800 | mei_hdr.me_addr = cl->me_client_id; | 827 | mei_hdr.me_addr = cl->me_client_id; |
801 | mei_hdr.reserved = 0; | 828 | mei_hdr.reserved = 0; |
802 | 829 | ||
803 | dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n", | ||
804 | MEI_HDR_PRM(&mei_hdr)); | ||
805 | |||
806 | 830 | ||
807 | if (mei_write_message(dev, &mei_hdr, buf->data)) { | 831 | rets = mei_write_message(dev, &mei_hdr, buf->data); |
808 | rets = -EIO; | 832 | if (rets) |
809 | goto err; | 833 | goto err; |
810 | } | ||
811 | 834 | ||
812 | cl->writing_state = MEI_WRITING; | 835 | cl->writing_state = MEI_WRITING; |
813 | cb->buf_idx = mei_hdr.length; | 836 | cb->buf_idx = mei_hdr.length; |
@@ -898,11 +921,11 @@ void mei_cl_all_wakeup(struct mei_device *dev) | |||
898 | struct mei_cl *cl, *next; | 921 | struct mei_cl *cl, *next; |
899 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { | 922 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { |
900 | if (waitqueue_active(&cl->rx_wait)) { | 923 | if (waitqueue_active(&cl->rx_wait)) { |
901 | dev_dbg(&dev->pdev->dev, "Waking up reading client!\n"); | 924 | cl_dbg(dev, cl, "Waking up reading client!\n"); |
902 | wake_up_interruptible(&cl->rx_wait); | 925 | wake_up_interruptible(&cl->rx_wait); |
903 | } | 926 | } |
904 | if (waitqueue_active(&cl->tx_wait)) { | 927 | if (waitqueue_active(&cl->tx_wait)) { |
905 | dev_dbg(&dev->pdev->dev, "Waking up writing client!\n"); | 928 | cl_dbg(dev, cl, "Waking up writing client!\n"); |
906 | wake_up_interruptible(&cl->tx_wait); | 929 | wake_up_interruptible(&cl->tx_wait); |
907 | } | 930 | } |
908 | } | 931 | } |
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 9eb031e92070..6374ed99e233 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h | |||
@@ -109,4 +109,13 @@ void mei_cl_all_disconnect(struct mei_device *dev); | |||
109 | void mei_cl_all_wakeup(struct mei_device *dev); | 109 | void mei_cl_all_wakeup(struct mei_device *dev); |
110 | void mei_cl_all_write_clear(struct mei_device *dev); | 110 | void mei_cl_all_write_clear(struct mei_device *dev); |
111 | 111 | ||
112 | #define MEI_CL_FMT "cl:host=%02d me=%02d " | ||
113 | #define MEI_CL_PRM(cl) (cl)->host_client_id, (cl)->me_client_id | ||
114 | |||
115 | #define cl_dbg(dev, cl, format, arg...) \ | ||
116 | dev_dbg(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) | ||
117 | |||
118 | #define cl_err(dev, cl, format, arg...) \ | ||
119 | dev_err(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) | ||
120 | |||
112 | #endif /* _MEI_CLIENT_H_ */ | 121 | #endif /* _MEI_CLIENT_H_ */ |
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 6127ab64bb39..f1c974a0bc0d 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c | |||
@@ -45,7 +45,7 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev) | |||
45 | kfree(dev->me_clients); | 45 | kfree(dev->me_clients); |
46 | dev->me_clients = NULL; | 46 | dev->me_clients = NULL; |
47 | 47 | ||
48 | dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n", | 48 | dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n", |
49 | dev->me_clients_num * sizeof(struct mei_me_client)); | 49 | dev->me_clients_num * sizeof(struct mei_me_client)); |
50 | /* allocate storage for ME clients representation */ | 50 | /* allocate storage for ME clients representation */ |
51 | clients = kcalloc(dev->me_clients_num, | 51 | clients = kcalloc(dev->me_clients_num, |
@@ -170,7 +170,7 @@ int mei_hbm_start_req(struct mei_device *dev) | |||
170 | dev_err(&dev->pdev->dev, "version message write failed\n"); | 170 | dev_err(&dev->pdev->dev, "version message write failed\n"); |
171 | dev->dev_state = MEI_DEV_RESETTING; | 171 | dev->dev_state = MEI_DEV_RESETTING; |
172 | mei_reset(dev, 1); | 172 | mei_reset(dev, 1); |
173 | return -ENODEV; | 173 | return -EIO; |
174 | } | 174 | } |
175 | dev->hbm_state = MEI_HBM_START; | 175 | dev->hbm_state = MEI_HBM_START; |
176 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 176 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
@@ -673,7 +673,10 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
673 | 673 | ||
674 | case HOST_ENUM_RES_CMD: | 674 | case HOST_ENUM_RES_CMD: |
675 | enum_res = (struct hbm_host_enum_response *) mei_msg; | 675 | enum_res = (struct hbm_host_enum_response *) mei_msg; |
676 | memcpy(dev->me_clients_map, enum_res->valid_addresses, 32); | 676 | BUILD_BUG_ON(sizeof(dev->me_clients_map) |
677 | < sizeof(enum_res->valid_addresses)); | ||
678 | memcpy(dev->me_clients_map, enum_res->valid_addresses, | ||
679 | sizeof(enum_res->valid_addresses)); | ||
677 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | 680 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && |
678 | dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { | 681 | dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { |
679 | dev->init_clients_timer = 0; | 682 | dev->init_clients_timer = 0; |
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 4b59cb742dee..7a95c07e59a6 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -113,13 +113,13 @@ static int mei_cl_irq_read_msg(struct mei_device *dev, | |||
113 | 113 | ||
114 | if (cb->response_buffer.size == 0 || | 114 | if (cb->response_buffer.size == 0 || |
115 | cb->response_buffer.data == NULL) { | 115 | cb->response_buffer.data == NULL) { |
116 | dev_err(&dev->pdev->dev, "response buffer is not allocated.\n"); | 116 | cl_err(dev, cl, "response buffer is not allocated.\n"); |
117 | list_del(&cb->list); | 117 | list_del(&cb->list); |
118 | return -ENOMEM; | 118 | return -ENOMEM; |
119 | } | 119 | } |
120 | 120 | ||
121 | if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { | 121 | if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { |
122 | dev_dbg(&dev->pdev->dev, "message overflow. size %d len %d idx %ld\n", | 122 | cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", |
123 | cb->response_buffer.size, | 123 | cb->response_buffer.size, |
124 | mei_hdr->length, cb->buf_idx); | 124 | mei_hdr->length, cb->buf_idx); |
125 | buffer = krealloc(cb->response_buffer.data, | 125 | buffer = krealloc(cb->response_buffer.data, |
@@ -127,7 +127,7 @@ static int mei_cl_irq_read_msg(struct mei_device *dev, | |||
127 | GFP_KERNEL); | 127 | GFP_KERNEL); |
128 | 128 | ||
129 | if (!buffer) { | 129 | if (!buffer) { |
130 | dev_err(&dev->pdev->dev, "allocation failed.\n"); | 130 | cl_err(dev, cl, "allocation failed.\n"); |
131 | list_del(&cb->list); | 131 | list_del(&cb->list); |
132 | return -ENOMEM; | 132 | return -ENOMEM; |
133 | } | 133 | } |
@@ -143,9 +143,7 @@ static int mei_cl_irq_read_msg(struct mei_device *dev, | |||
143 | if (mei_hdr->msg_complete) { | 143 | if (mei_hdr->msg_complete) { |
144 | cl->status = 0; | 144 | cl->status = 0; |
145 | list_del(&cb->list); | 145 | list_del(&cb->list); |
146 | dev_dbg(&dev->pdev->dev, "completed read H cl = %d, ME cl = %d, length = %lu\n", | 146 | cl_dbg(dev, cl, "completed read length = %lu\n", |
147 | cl->host_client_id, | ||
148 | cl->me_client_id, | ||
149 | cb->buf_idx); | 147 | cb->buf_idx); |
150 | list_add_tail(&cb->list, &complete_list->list); | 148 | list_add_tail(&cb->list, &complete_list->list); |
151 | } | 149 | } |
@@ -218,9 +216,11 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
218 | s32 *slots, struct mei_cl_cb *cmpl_list) | 216 | s32 *slots, struct mei_cl_cb *cmpl_list) |
219 | { | 217 | { |
220 | struct mei_device *dev = cl->dev; | 218 | struct mei_device *dev = cl->dev; |
221 | |||
222 | u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); | 219 | u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); |
223 | 220 | ||
221 | int ret; | ||
222 | |||
223 | |||
224 | if (*slots < msg_slots) { | 224 | if (*slots < msg_slots) { |
225 | /* return the cancel routine */ | 225 | /* return the cancel routine */ |
226 | list_del(&cb->list); | 226 | list_del(&cb->list); |
@@ -229,12 +229,14 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
229 | 229 | ||
230 | *slots -= msg_slots; | 230 | *slots -= msg_slots; |
231 | 231 | ||
232 | if (mei_hbm_cl_flow_control_req(dev, cl)) { | 232 | ret = mei_hbm_cl_flow_control_req(dev, cl); |
233 | cl->status = -ENODEV; | 233 | if (ret) { |
234 | cl->status = ret; | ||
234 | cb->buf_idx = 0; | 235 | cb->buf_idx = 0; |
235 | list_move_tail(&cb->list, &cmpl_list->list); | 236 | list_move_tail(&cb->list, &cmpl_list->list); |
236 | return -ENODEV; | 237 | return ret; |
237 | } | 238 | } |
239 | |||
238 | list_move_tail(&cb->list, &dev->read_list.list); | 240 | list_move_tail(&cb->list, &dev->read_list.list); |
239 | 241 | ||
240 | return 0; | 242 | return 0; |
@@ -256,6 +258,7 @@ static int mei_cl_irq_ioctl(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
256 | s32 *slots, struct mei_cl_cb *cmpl_list) | 258 | s32 *slots, struct mei_cl_cb *cmpl_list) |
257 | { | 259 | { |
258 | struct mei_device *dev = cl->dev; | 260 | struct mei_device *dev = cl->dev; |
261 | int ret; | ||
259 | 262 | ||
260 | u32 msg_slots = | 263 | u32 msg_slots = |
261 | mei_data2slots(sizeof(struct hbm_client_connect_request)); | 264 | mei_data2slots(sizeof(struct hbm_client_connect_request)); |
@@ -270,11 +273,12 @@ static int mei_cl_irq_ioctl(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
270 | 273 | ||
271 | cl->state = MEI_FILE_CONNECTING; | 274 | cl->state = MEI_FILE_CONNECTING; |
272 | 275 | ||
273 | if (mei_hbm_cl_connect_req(dev, cl)) { | 276 | ret = mei_hbm_cl_connect_req(dev, cl); |
274 | cl->status = -ENODEV; | 277 | if (ret) { |
278 | cl->status = ret; | ||
275 | cb->buf_idx = 0; | 279 | cb->buf_idx = 0; |
276 | list_del(&cb->list); | 280 | list_del(&cb->list); |
277 | return -ENODEV; | 281 | return ret; |
278 | } | 282 | } |
279 | 283 | ||
280 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 284 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); |
@@ -345,14 +349,14 @@ int mei_irq_read_handler(struct mei_device *dev, | |||
345 | 349 | ||
346 | /* decide where to read the message too */ | 350 | /* decide where to read the message too */ |
347 | if (!mei_hdr->host_addr) { | 351 | if (!mei_hdr->host_addr) { |
348 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n"); | 352 | dev_dbg(&dev->pdev->dev, "call mei_hbm_dispatch.\n"); |
349 | mei_hbm_dispatch(dev, mei_hdr); | 353 | mei_hbm_dispatch(dev, mei_hdr); |
350 | dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n"); | 354 | dev_dbg(&dev->pdev->dev, "end mei_hbm_dispatch.\n"); |
351 | } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && | 355 | } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && |
352 | (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && | 356 | (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && |
353 | (dev->iamthif_state == MEI_IAMTHIF_READING)) { | 357 | (dev->iamthif_state == MEI_IAMTHIF_READING)) { |
354 | 358 | ||
355 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); | 359 | dev_dbg(&dev->pdev->dev, "call mei_amthif_irq_read_msg.\n"); |
356 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); | 360 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); |
357 | 361 | ||
358 | ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); | 362 | ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); |
@@ -423,12 +427,12 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
423 | if (MEI_WRITING == cl->writing_state && | 427 | if (MEI_WRITING == cl->writing_state && |
424 | cb->fop_type == MEI_FOP_WRITE && | 428 | cb->fop_type == MEI_FOP_WRITE && |
425 | cl != &dev->iamthif_cl) { | 429 | cl != &dev->iamthif_cl) { |
426 | dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); | 430 | cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); |
427 | cl->writing_state = MEI_WRITE_COMPLETE; | 431 | cl->writing_state = MEI_WRITE_COMPLETE; |
428 | list_add_tail(&cb->list, &cmpl_list->list); | 432 | list_add_tail(&cb->list, &cmpl_list->list); |
429 | } | 433 | } |
430 | if (cl == &dev->iamthif_cl) { | 434 | if (cl == &dev->iamthif_cl) { |
431 | dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); | 435 | cl_dbg(dev, cl, "check iamthif flow control.\n"); |
432 | if (dev->iamthif_flow_control_pending) { | 436 | if (dev->iamthif_flow_control_pending) { |
433 | ret = mei_amthif_irq_read(dev, &slots); | 437 | ret = mei_amthif_irq_read(dev, &slots); |
434 | if (ret) | 438 | if (ret) |
@@ -509,13 +513,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
509 | cl = cb->cl; | 513 | cl = cb->cl; |
510 | if (cl == NULL) | 514 | if (cl == NULL) |
511 | continue; | 515 | continue; |
512 | if (mei_cl_flow_ctrl_creds(cl) <= 0) { | ||
513 | dev_dbg(&dev->pdev->dev, | ||
514 | "No flow control credentials for client %d, not sending.\n", | ||
515 | cl->host_client_id); | ||
516 | continue; | ||
517 | } | ||
518 | |||
519 | if (cl == &dev->iamthif_cl) | 516 | if (cl == &dev->iamthif_cl) |
520 | ret = mei_amthif_irq_write_complete(cl, cb, | 517 | ret = mei_amthif_irq_write_complete(cl, cb, |
521 | &slots, cmpl_list); | 518 | &slots, cmpl_list); |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 173ff095be0d..9aa3b78067d3 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -165,10 +165,7 @@ static int mei_release(struct inode *inode, struct file *file) | |||
165 | 165 | ||
166 | file->private_data = NULL; | 166 | file->private_data = NULL; |
167 | 167 | ||
168 | if (cb) { | 168 | mei_io_cb_free(cb); |
169 | mei_io_cb_free(cb); | ||
170 | cb = NULL; | ||
171 | } | ||
172 | 169 | ||
173 | kfree(cl); | 170 | kfree(cl); |
174 | out: | 171 | out: |
@@ -203,12 +200,18 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
203 | 200 | ||
204 | dev = cl->dev; | 201 | dev = cl->dev; |
205 | 202 | ||
203 | |||
206 | mutex_lock(&dev->device_lock); | 204 | mutex_lock(&dev->device_lock); |
207 | if (dev->dev_state != MEI_DEV_ENABLED) { | 205 | if (dev->dev_state != MEI_DEV_ENABLED) { |
208 | rets = -ENODEV; | 206 | rets = -ENODEV; |
209 | goto out; | 207 | goto out; |
210 | } | 208 | } |
211 | 209 | ||
210 | if (length == 0) { | ||
211 | rets = 0; | ||
212 | goto out; | ||
213 | } | ||
214 | |||
212 | if (cl == &dev->iamthif_cl) { | 215 | if (cl == &dev->iamthif_cl) { |
213 | rets = mei_amthif_read(dev, file, ubuf, length, offset); | 216 | rets = mei_amthif_read(dev, file, ubuf, length, offset); |
214 | goto out; | 217 | goto out; |
@@ -350,8 +353,14 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
350 | rets = -ENODEV; | 353 | rets = -ENODEV; |
351 | goto out; | 354 | goto out; |
352 | } | 355 | } |
353 | if (length > dev->me_clients[id].props.max_msg_length || length <= 0) { | 356 | |
354 | rets = -EMSGSIZE; | 357 | if (length == 0) { |
358 | rets = 0; | ||
359 | goto out; | ||
360 | } | ||
361 | |||
362 | if (length > dev->me_clients[id].props.max_msg_length) { | ||
363 | rets = -EFBIG; | ||
355 | goto out; | 364 | goto out; |
356 | } | 365 | } |
357 | 366 | ||
@@ -404,8 +413,11 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
404 | goto out; | 413 | goto out; |
405 | 414 | ||
406 | rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); | 415 | rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); |
407 | if (rets) | 416 | if (rets) { |
417 | dev_err(&dev->pdev->dev, "failed to copy data from userland\n"); | ||
418 | rets = -EFAULT; | ||
408 | goto out; | 419 | goto out; |
420 | } | ||
409 | 421 | ||
410 | if (cl == &dev->iamthif_cl) { | 422 | if (cl == &dev->iamthif_cl) { |
411 | rets = mei_amthif_write(dev, write_cb); | 423 | rets = mei_amthif_write(dev, write_cb); |
@@ -567,7 +579,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) | |||
567 | dev_dbg(&dev->pdev->dev, "copy connect data from user\n"); | 579 | dev_dbg(&dev->pdev->dev, "copy connect data from user\n"); |
568 | if (copy_from_user(connect_data, (char __user *)data, | 580 | if (copy_from_user(connect_data, (char __user *)data, |
569 | sizeof(struct mei_connect_client_data))) { | 581 | sizeof(struct mei_connect_client_data))) { |
570 | dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n"); | 582 | dev_err(&dev->pdev->dev, "failed to copy data from userland\n"); |
571 | rets = -EFAULT; | 583 | rets = -EFAULT; |
572 | goto out; | 584 | goto out; |
573 | } | 585 | } |
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 1b3844e82379..1b8a4c6d0cf8 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
@@ -239,7 +239,6 @@ static void mei_me_remove(struct pci_dev *pdev) | |||
239 | 239 | ||
240 | free_irq(pdev->irq, dev); | 240 | free_irq(pdev->irq, dev); |
241 | pci_disable_msi(pdev); | 241 | pci_disable_msi(pdev); |
242 | pci_set_drvdata(pdev, NULL); | ||
243 | 242 | ||
244 | if (hw->mem_addr) | 243 | if (hw->mem_addr) |
245 | pci_iounmap(pdev, hw->mem_addr); | 244 | pci_iounmap(pdev, hw->mem_addr); |
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig new file mode 100644 index 000000000000..d453768e9cee --- /dev/null +++ b/drivers/misc/mic/Kconfig | |||
@@ -0,0 +1,39 @@ | |||
1 | comment "Intel MIC Host Driver" | ||
2 | |||
3 | config INTEL_MIC_HOST | ||
4 | tristate "Intel MIC Host Driver" | ||
5 | depends on 64BIT && PCI | ||
6 | select VHOST_RING | ||
7 | default N | ||
8 | help | ||
9 | This enables Host Driver support for the Intel Many Integrated | ||
10 | Core (MIC) family of PCIe form factor coprocessor devices that | ||
11 | run a 64 bit Linux OS. The driver manages card OS state and | ||
12 | enables communication between host and card. Intel MIC X100 | ||
13 | devices are currently supported. | ||
14 | |||
15 | If you are building a host kernel with an Intel MIC device then | ||
16 | say M (recommended) or Y, else say N. If unsure say N. | ||
17 | |||
18 | More information about the Intel MIC family as well as the Linux | ||
19 | OS and tools for MIC to use with this driver are available from | ||
20 | <http://software.intel.com/en-us/mic-developer>. | ||
21 | |||
22 | comment "Intel MIC Card Driver" | ||
23 | |||
24 | config INTEL_MIC_CARD | ||
25 | tristate "Intel MIC Card Driver" | ||
26 | depends on 64BIT | ||
27 | select VIRTIO | ||
28 | default N | ||
29 | help | ||
30 | This enables card driver support for the Intel Many Integrated | ||
31 | Core (MIC) device family. The card driver communicates shutdown/ | ||
32 | crash events to the host and allows registration/configuration of | ||
33 | virtio devices. Intel MIC X100 devices are currently supported. | ||
34 | |||
35 | If you are building a card kernel for an Intel MIC device then | ||
36 | say M (recommended) or Y, else say N. If unsure say N. | ||
37 | |||
38 | For more information see | ||
39 | <http://software.intel.com/en-us/mic-developer>. | ||
diff --git a/drivers/misc/mic/Makefile b/drivers/misc/mic/Makefile new file mode 100644 index 000000000000..05b34d683a58 --- /dev/null +++ b/drivers/misc/mic/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile - Intel MIC Linux driver. | ||
3 | # Copyright(c) 2013, Intel Corporation. | ||
4 | # | ||
5 | obj-$(CONFIG_INTEL_MIC_HOST) += host/ | ||
6 | obj-$(CONFIG_INTEL_MIC_CARD) += card/ | ||
diff --git a/drivers/misc/mic/card/Makefile b/drivers/misc/mic/card/Makefile new file mode 100644 index 000000000000..69d58bef92ce --- /dev/null +++ b/drivers/misc/mic/card/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile - Intel MIC Linux driver. | ||
3 | # Copyright(c) 2013, Intel Corporation. | ||
4 | # | ||
5 | ccflags-y += -DINTEL_MIC_CARD | ||
6 | |||
7 | obj-$(CONFIG_INTEL_MIC_CARD) += mic_card.o | ||
8 | mic_card-y += mic_x100.o | ||
9 | mic_card-y += mic_device.o | ||
10 | mic_card-y += mic_debugfs.o | ||
11 | mic_card-y += mic_virtio.o | ||
diff --git a/drivers/misc/mic/card/mic_debugfs.c b/drivers/misc/mic/card/mic_debugfs.c new file mode 100644 index 000000000000..95cf186ff73a --- /dev/null +++ b/drivers/misc/mic/card/mic_debugfs.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Disclaimer: The codes contained in these modules may be specific to | ||
19 | * the Intel Software Development Platform codenamed: Knights Ferry, and | ||
20 | * the Intel product codenamed: Knights Corner, and are not backward | ||
21 | * compatible with other Intel products. Additionally, Intel will NOT | ||
22 | * support the codes or instruction set in future products. | ||
23 | * | ||
24 | * Intel MIC Card driver. | ||
25 | * | ||
26 | */ | ||
27 | #include <linux/debugfs.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/seq_file.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/device.h> | ||
32 | |||
33 | #include "../common/mic_device.h" | ||
34 | #include "mic_device.h" | ||
35 | |||
36 | /* Debugfs parent dir */ | ||
37 | static struct dentry *mic_dbg; | ||
38 | |||
39 | /** | ||
40 | * mic_intr_test - Send interrupts to host. | ||
41 | */ | ||
42 | static int mic_intr_test(struct seq_file *s, void *unused) | ||
43 | { | ||
44 | struct mic_driver *mdrv = s->private; | ||
45 | struct mic_device *mdev = &mdrv->mdev; | ||
46 | |||
47 | mic_send_intr(mdev, 0); | ||
48 | msleep(1000); | ||
49 | mic_send_intr(mdev, 1); | ||
50 | msleep(1000); | ||
51 | mic_send_intr(mdev, 2); | ||
52 | msleep(1000); | ||
53 | mic_send_intr(mdev, 3); | ||
54 | msleep(1000); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int mic_intr_test_open(struct inode *inode, struct file *file) | ||
60 | { | ||
61 | return single_open(file, mic_intr_test, inode->i_private); | ||
62 | } | ||
63 | |||
64 | static int mic_intr_test_release(struct inode *inode, struct file *file) | ||
65 | { | ||
66 | return single_release(inode, file); | ||
67 | } | ||
68 | |||
69 | static const struct file_operations intr_test_ops = { | ||
70 | .owner = THIS_MODULE, | ||
71 | .open = mic_intr_test_open, | ||
72 | .read = seq_read, | ||
73 | .llseek = seq_lseek, | ||
74 | .release = mic_intr_test_release | ||
75 | }; | ||
76 | |||
77 | /** | ||
78 | * mic_create_card_debug_dir - Initialize MIC debugfs entries. | ||
79 | */ | ||
80 | void __init mic_create_card_debug_dir(struct mic_driver *mdrv) | ||
81 | { | ||
82 | struct dentry *d; | ||
83 | |||
84 | if (!mic_dbg) | ||
85 | return; | ||
86 | |||
87 | mdrv->dbg_dir = debugfs_create_dir(mdrv->name, mic_dbg); | ||
88 | if (!mdrv->dbg_dir) { | ||
89 | dev_err(mdrv->dev, "Cant create dbg_dir %s\n", mdrv->name); | ||
90 | return; | ||
91 | } | ||
92 | |||
93 | d = debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, | ||
94 | mdrv, &intr_test_ops); | ||
95 | |||
96 | if (!d) { | ||
97 | dev_err(mdrv->dev, | ||
98 | "Cant create dbg intr_test %s\n", mdrv->name); | ||
99 | return; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * mic_delete_card_debug_dir - Uninitialize MIC debugfs entries. | ||
105 | */ | ||
106 | void mic_delete_card_debug_dir(struct mic_driver *mdrv) | ||
107 | { | ||
108 | if (!mdrv->dbg_dir) | ||
109 | return; | ||
110 | |||
111 | debugfs_remove_recursive(mdrv->dbg_dir); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * mic_init_card_debugfs - Initialize global debugfs entry. | ||
116 | */ | ||
117 | void __init mic_init_card_debugfs(void) | ||
118 | { | ||
119 | mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
120 | if (!mic_dbg) | ||
121 | pr_err("can't create debugfs dir\n"); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * mic_exit_card_debugfs - Uninitialize global debugfs entry | ||
126 | */ | ||
127 | void mic_exit_card_debugfs(void) | ||
128 | { | ||
129 | debugfs_remove(mic_dbg); | ||
130 | } | ||
diff --git a/drivers/misc/mic/card/mic_device.c b/drivers/misc/mic/card/mic_device.c new file mode 100644 index 000000000000..4125217579af --- /dev/null +++ b/drivers/misc/mic/card/mic_device.c | |||
@@ -0,0 +1,306 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Disclaimer: The codes contained in these modules may be specific to | ||
19 | * the Intel Software Development Platform codenamed: Knights Ferry, and | ||
20 | * the Intel product codenamed: Knights Corner, and are not backward | ||
21 | * compatible with other Intel products. Additionally, Intel will NOT | ||
22 | * support the codes or instruction set in future products. | ||
23 | * | ||
24 | * Intel MIC Card driver. | ||
25 | * | ||
26 | */ | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/reboot.h> | ||
31 | |||
32 | #include <linux/mic_common.h> | ||
33 | #include "../common/mic_device.h" | ||
34 | #include "mic_device.h" | ||
35 | #include "mic_virtio.h" | ||
36 | |||
37 | static struct mic_driver *g_drv; | ||
38 | static struct mic_irq *shutdown_cookie; | ||
39 | |||
40 | static void mic_notify_host(u8 state) | ||
41 | { | ||
42 | struct mic_driver *mdrv = g_drv; | ||
43 | struct mic_bootparam __iomem *bootparam = mdrv->dp; | ||
44 | |||
45 | iowrite8(state, &bootparam->shutdown_status); | ||
46 | dev_dbg(mdrv->dev, "%s %d system_state %d\n", | ||
47 | __func__, __LINE__, state); | ||
48 | mic_send_intr(&mdrv->mdev, ioread8(&bootparam->c2h_shutdown_db)); | ||
49 | } | ||
50 | |||
51 | static int mic_panic_event(struct notifier_block *this, unsigned long event, | ||
52 | void *ptr) | ||
53 | { | ||
54 | struct mic_driver *mdrv = g_drv; | ||
55 | struct mic_bootparam __iomem *bootparam = mdrv->dp; | ||
56 | |||
57 | iowrite8(-1, &bootparam->h2c_config_db); | ||
58 | iowrite8(-1, &bootparam->h2c_shutdown_db); | ||
59 | mic_notify_host(MIC_CRASHED); | ||
60 | return NOTIFY_DONE; | ||
61 | } | ||
62 | |||
63 | static struct notifier_block mic_panic = { | ||
64 | .notifier_call = mic_panic_event, | ||
65 | }; | ||
66 | |||
67 | static irqreturn_t mic_shutdown_isr(int irq, void *data) | ||
68 | { | ||
69 | struct mic_driver *mdrv = g_drv; | ||
70 | struct mic_bootparam __iomem *bootparam = mdrv->dp; | ||
71 | |||
72 | mic_ack_interrupt(&g_drv->mdev); | ||
73 | if (ioread8(&bootparam->shutdown_card)) | ||
74 | orderly_poweroff(true); | ||
75 | return IRQ_HANDLED; | ||
76 | } | ||
77 | |||
78 | static int mic_shutdown_init(void) | ||
79 | { | ||
80 | int rc = 0; | ||
81 | struct mic_driver *mdrv = g_drv; | ||
82 | struct mic_bootparam __iomem *bootparam = mdrv->dp; | ||
83 | int shutdown_db; | ||
84 | |||
85 | shutdown_db = mic_next_card_db(); | ||
86 | shutdown_cookie = mic_request_card_irq(mic_shutdown_isr, | ||
87 | "Shutdown", mdrv, shutdown_db); | ||
88 | if (IS_ERR(shutdown_cookie)) | ||
89 | rc = PTR_ERR(shutdown_cookie); | ||
90 | else | ||
91 | iowrite8(shutdown_db, &bootparam->h2c_shutdown_db); | ||
92 | return rc; | ||
93 | } | ||
94 | |||
95 | static void mic_shutdown_uninit(void) | ||
96 | { | ||
97 | struct mic_driver *mdrv = g_drv; | ||
98 | struct mic_bootparam __iomem *bootparam = mdrv->dp; | ||
99 | |||
100 | iowrite8(-1, &bootparam->h2c_shutdown_db); | ||
101 | mic_free_card_irq(shutdown_cookie, mdrv); | ||
102 | } | ||
103 | |||
104 | static int __init mic_dp_init(void) | ||
105 | { | ||
106 | struct mic_driver *mdrv = g_drv; | ||
107 | struct mic_device *mdev = &mdrv->mdev; | ||
108 | struct mic_bootparam __iomem *bootparam; | ||
109 | u64 lo, hi, dp_dma_addr; | ||
110 | u32 magic; | ||
111 | |||
112 | lo = mic_read_spad(&mdrv->mdev, MIC_DPLO_SPAD); | ||
113 | hi = mic_read_spad(&mdrv->mdev, MIC_DPHI_SPAD); | ||
114 | |||
115 | dp_dma_addr = lo | (hi << 32); | ||
116 | mdrv->dp = mic_card_map(mdev, dp_dma_addr, MIC_DP_SIZE); | ||
117 | if (!mdrv->dp) { | ||
118 | dev_err(mdrv->dev, "Cannot remap Aperture BAR\n"); | ||
119 | return -ENOMEM; | ||
120 | } | ||
121 | bootparam = mdrv->dp; | ||
122 | magic = ioread32(&bootparam->magic); | ||
123 | if (MIC_MAGIC != magic) { | ||
124 | dev_err(mdrv->dev, "bootparam magic mismatch 0x%x\n", magic); | ||
125 | return -EIO; | ||
126 | } | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* Uninitialize the device page */ | ||
131 | static void mic_dp_uninit(void) | ||
132 | { | ||
133 | mic_card_unmap(&g_drv->mdev, g_drv->dp); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * mic_request_card_irq - request an irq. | ||
138 | * | ||
139 | * @func: The callback function that handles the interrupt. | ||
140 | * @name: The ASCII name of the callee requesting the irq. | ||
141 | * @data: private data that is returned back when calling the | ||
142 | * function handler. | ||
143 | * @index: The doorbell index of the requester. | ||
144 | * | ||
145 | * returns: The cookie that is transparent to the caller. Passed | ||
146 | * back when calling mic_free_irq. An appropriate error code | ||
147 | * is returned on failure. Caller needs to use IS_ERR(return_val) | ||
148 | * to check for failure and PTR_ERR(return_val) to obtained the | ||
149 | * error code. | ||
150 | * | ||
151 | */ | ||
152 | struct mic_irq *mic_request_card_irq(irqreturn_t (*func)(int irq, void *data), | ||
153 | const char *name, void *data, int index) | ||
154 | { | ||
155 | int rc = 0; | ||
156 | unsigned long cookie; | ||
157 | struct mic_driver *mdrv = g_drv; | ||
158 | |||
159 | rc = request_irq(mic_db_to_irq(mdrv, index), func, | ||
160 | 0, name, data); | ||
161 | if (rc) { | ||
162 | dev_err(mdrv->dev, "request_irq failed rc = %d\n", rc); | ||
163 | goto err; | ||
164 | } | ||
165 | mdrv->irq_info.irq_usage_count[index]++; | ||
166 | cookie = index; | ||
167 | return (struct mic_irq *)cookie; | ||
168 | err: | ||
169 | return ERR_PTR(rc); | ||
170 | |||
171 | } | ||
172 | |||
173 | /** | ||
174 | * mic_free_card_irq - free irq. | ||
175 | * | ||
176 | * @cookie: cookie obtained during a successful call to mic_request_irq | ||
177 | * @data: private data specified by the calling function during the | ||
178 | * mic_request_irq | ||
179 | * | ||
180 | * returns: none. | ||
181 | */ | ||
182 | void mic_free_card_irq(struct mic_irq *cookie, void *data) | ||
183 | { | ||
184 | int index; | ||
185 | struct mic_driver *mdrv = g_drv; | ||
186 | |||
187 | index = (unsigned long)cookie & 0xFFFFU; | ||
188 | free_irq(mic_db_to_irq(mdrv, index), data); | ||
189 | mdrv->irq_info.irq_usage_count[index]--; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * mic_next_card_db - Get the doorbell with minimum usage count. | ||
194 | * | ||
195 | * Returns the irq index. | ||
196 | */ | ||
197 | int mic_next_card_db(void) | ||
198 | { | ||
199 | int i; | ||
200 | int index = 0; | ||
201 | struct mic_driver *mdrv = g_drv; | ||
202 | |||
203 | for (i = 0; i < mdrv->intr_info.num_intr; i++) { | ||
204 | if (mdrv->irq_info.irq_usage_count[i] < | ||
205 | mdrv->irq_info.irq_usage_count[index]) | ||
206 | index = i; | ||
207 | } | ||
208 | |||
209 | return index; | ||
210 | } | ||
211 | |||
212 | /** | ||
213 | * mic_init_irq - Initialize irq information. | ||
214 | * | ||
215 | * Returns 0 in success. Appropriate error code on failure. | ||
216 | */ | ||
217 | static int mic_init_irq(void) | ||
218 | { | ||
219 | struct mic_driver *mdrv = g_drv; | ||
220 | |||
221 | mdrv->irq_info.irq_usage_count = kzalloc((sizeof(u32) * | ||
222 | mdrv->intr_info.num_intr), | ||
223 | GFP_KERNEL); | ||
224 | if (!mdrv->irq_info.irq_usage_count) | ||
225 | return -ENOMEM; | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * mic_uninit_irq - Uninitialize irq information. | ||
231 | * | ||
232 | * None. | ||
233 | */ | ||
234 | static void mic_uninit_irq(void) | ||
235 | { | ||
236 | struct mic_driver *mdrv = g_drv; | ||
237 | |||
238 | kfree(mdrv->irq_info.irq_usage_count); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * mic_driver_init - MIC driver initialization tasks. | ||
243 | * | ||
244 | * Returns 0 in success. Appropriate error code on failure. | ||
245 | */ | ||
246 | int __init mic_driver_init(struct mic_driver *mdrv) | ||
247 | { | ||
248 | int rc; | ||
249 | |||
250 | g_drv = mdrv; | ||
251 | /* | ||
252 | * Unloading the card module is not supported. The MIC card module | ||
253 | * handles fundamental operations like host/card initiated shutdowns | ||
254 | * and informing the host about card crashes and cannot be unloaded. | ||
255 | */ | ||
256 | if (!try_module_get(mdrv->dev->driver->owner)) { | ||
257 | rc = -ENODEV; | ||
258 | goto done; | ||
259 | } | ||
260 | rc = mic_dp_init(); | ||
261 | if (rc) | ||
262 | goto put; | ||
263 | rc = mic_init_irq(); | ||
264 | if (rc) | ||
265 | goto dp_uninit; | ||
266 | rc = mic_shutdown_init(); | ||
267 | if (rc) | ||
268 | goto irq_uninit; | ||
269 | rc = mic_devices_init(mdrv); | ||
270 | if (rc) | ||
271 | goto shutdown_uninit; | ||
272 | mic_create_card_debug_dir(mdrv); | ||
273 | atomic_notifier_chain_register(&panic_notifier_list, &mic_panic); | ||
274 | done: | ||
275 | return rc; | ||
276 | shutdown_uninit: | ||
277 | mic_shutdown_uninit(); | ||
278 | irq_uninit: | ||
279 | mic_uninit_irq(); | ||
280 | dp_uninit: | ||
281 | mic_dp_uninit(); | ||
282 | put: | ||
283 | module_put(mdrv->dev->driver->owner); | ||
284 | return rc; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * mic_driver_uninit - MIC driver uninitialization tasks. | ||
289 | * | ||
290 | * Returns None | ||
291 | */ | ||
292 | void mic_driver_uninit(struct mic_driver *mdrv) | ||
293 | { | ||
294 | mic_delete_card_debug_dir(mdrv); | ||
295 | mic_devices_uninit(mdrv); | ||
296 | /* | ||
297 | * Inform the host about the shutdown status i.e. poweroff/restart etc. | ||
298 | * The module cannot be unloaded so the only code path to call | ||
299 | * mic_devices_uninit(..) is the shutdown callback. | ||
300 | */ | ||
301 | mic_notify_host(system_state); | ||
302 | mic_shutdown_uninit(); | ||
303 | mic_uninit_irq(); | ||
304 | mic_dp_uninit(); | ||
305 | module_put(mdrv->dev->driver->owner); | ||
306 | } | ||
diff --git a/drivers/misc/mic/card/mic_device.h b/drivers/misc/mic/card/mic_device.h new file mode 100644 index 000000000000..347b9b3b7916 --- /dev/null +++ b/drivers/misc/mic/card/mic_device.h | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Disclaimer: The codes contained in these modules may be specific to | ||
19 | * the Intel Software Development Platform codenamed: Knights Ferry, and | ||
20 | * the Intel product codenamed: Knights Corner, and are not backward | ||
21 | * compatible with other Intel products. Additionally, Intel will NOT | ||
22 | * support the codes or instruction set in future products. | ||
23 | * | ||
24 | * Intel MIC Card driver. | ||
25 | * | ||
26 | */ | ||
27 | #ifndef _MIC_CARD_DEVICE_H_ | ||
28 | #define _MIC_CARD_DEVICE_H_ | ||
29 | |||
30 | #include <linux/workqueue.h> | ||
31 | #include <linux/io.h> | ||
32 | |||
33 | /** | ||
34 | * struct mic_intr_info - Contains h/w specific interrupt sources info | ||
35 | * | ||
36 | * @num_intr: The number of irqs available | ||
37 | */ | ||
38 | struct mic_intr_info { | ||
39 | u32 num_intr; | ||
40 | }; | ||
41 | |||
42 | /** | ||
43 | * struct mic_irq_info - OS specific irq information | ||
44 | * | ||
45 | * @irq_usage_count: usage count array tracking the number of sources | ||
46 | * assigned for each irq. | ||
47 | */ | ||
48 | struct mic_irq_info { | ||
49 | int *irq_usage_count; | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * struct mic_device - MIC device information. | ||
54 | * | ||
55 | * @mmio: MMIO bar information. | ||
56 | */ | ||
57 | struct mic_device { | ||
58 | struct mic_mw mmio; | ||
59 | }; | ||
60 | |||
61 | /** | ||
62 | * struct mic_driver - MIC card driver information. | ||
63 | * | ||
64 | * @name: Name for MIC driver. | ||
65 | * @dbg_dir: debugfs directory of this MIC device. | ||
66 | * @dev: The device backing this MIC. | ||
67 | * @dp: The pointer to the virtio device page. | ||
68 | * @mdev: MIC device information for the host. | ||
69 | * @hotplug_work: Hot plug work for adding/removing virtio devices. | ||
70 | * @irq_info: The OS specific irq information | ||
71 | * @intr_info: H/W specific interrupt information. | ||
72 | */ | ||
73 | struct mic_driver { | ||
74 | char name[20]; | ||
75 | struct dentry *dbg_dir; | ||
76 | struct device *dev; | ||
77 | void __iomem *dp; | ||
78 | struct mic_device mdev; | ||
79 | struct work_struct hotplug_work; | ||
80 | struct mic_irq_info irq_info; | ||
81 | struct mic_intr_info intr_info; | ||
82 | }; | ||
83 | |||
84 | /** | ||
85 | * struct mic_irq - opaque pointer used as cookie | ||
86 | */ | ||
87 | struct mic_irq; | ||
88 | |||
89 | /** | ||
90 | * mic_mmio_read - read from an MMIO register. | ||
91 | * @mw: MMIO register base virtual address. | ||
92 | * @offset: register offset. | ||
93 | * | ||
94 | * RETURNS: register value. | ||
95 | */ | ||
96 | static inline u32 mic_mmio_read(struct mic_mw *mw, u32 offset) | ||
97 | { | ||
98 | return ioread32(mw->va + offset); | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * mic_mmio_write - write to an MMIO register. | ||
103 | * @mw: MMIO register base virtual address. | ||
104 | * @val: the data value to put into the register | ||
105 | * @offset: register offset. | ||
106 | * | ||
107 | * RETURNS: none. | ||
108 | */ | ||
109 | static inline void | ||
110 | mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) | ||
111 | { | ||
112 | iowrite32(val, mw->va + offset); | ||
113 | } | ||
114 | |||
115 | int mic_driver_init(struct mic_driver *mdrv); | ||
116 | void mic_driver_uninit(struct mic_driver *mdrv); | ||
117 | int mic_next_card_db(void); | ||
118 | struct mic_irq *mic_request_card_irq(irqreturn_t (*func)(int irq, void *data), | ||
119 | const char *name, void *data, int intr_src); | ||
120 | void mic_free_card_irq(struct mic_irq *cookie, void *data); | ||
121 | u32 mic_read_spad(struct mic_device *mdev, unsigned int idx); | ||
122 | void mic_send_intr(struct mic_device *mdev, int doorbell); | ||
123 | int mic_db_to_irq(struct mic_driver *mdrv, int db); | ||
124 | u32 mic_ack_interrupt(struct mic_device *mdev); | ||
125 | void mic_hw_intr_init(struct mic_driver *mdrv); | ||
126 | void __iomem * | ||
127 | mic_card_map(struct mic_device *mdev, dma_addr_t addr, size_t size); | ||
128 | void mic_card_unmap(struct mic_device *mdev, void __iomem *addr); | ||
129 | void __init mic_create_card_debug_dir(struct mic_driver *mdrv); | ||
130 | void mic_delete_card_debug_dir(struct mic_driver *mdrv); | ||
131 | void __init mic_init_card_debugfs(void); | ||
132 | void mic_exit_card_debugfs(void); | ||
133 | #endif | ||
diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c new file mode 100644 index 000000000000..38275c1b9e03 --- /dev/null +++ b/drivers/misc/mic/card/mic_virtio.c | |||
@@ -0,0 +1,631 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Disclaimer: The codes contained in these modules may be specific to | ||
19 | * the Intel Software Development Platform codenamed: Knights Ferry, and | ||
20 | * the Intel product codenamed: Knights Corner, and are not backward | ||
21 | * compatible with other Intel products. Additionally, Intel will NOT | ||
22 | * support the codes or instruction set in future products. | ||
23 | * | ||
24 | * Adapted from: | ||
25 | * | ||
26 | * virtio for kvm on s390 | ||
27 | * | ||
28 | * Copyright IBM Corp. 2008 | ||
29 | * | ||
30 | * This program is free software; you can redistribute it and/or modify | ||
31 | * it under the terms of the GNU General Public License (version 2 only) | ||
32 | * as published by the Free Software Foundation. | ||
33 | * | ||
34 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> | ||
35 | * | ||
36 | * Intel MIC Card driver. | ||
37 | * | ||
38 | */ | ||
39 | #include <linux/delay.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/virtio_config.h> | ||
42 | |||
43 | #include "../common/mic_device.h" | ||
44 | #include "mic_virtio.h" | ||
45 | |||
46 | #define VIRTIO_SUBCODE_64 0x0D00 | ||
47 | |||
48 | #define MIC_MAX_VRINGS 4 | ||
49 | struct mic_vdev { | ||
50 | struct virtio_device vdev; | ||
51 | struct mic_device_desc __iomem *desc; | ||
52 | struct mic_device_ctrl __iomem *dc; | ||
53 | struct mic_device *mdev; | ||
54 | void __iomem *vr[MIC_MAX_VRINGS]; | ||
55 | int used_size[MIC_MAX_VRINGS]; | ||
56 | struct completion reset_done; | ||
57 | struct mic_irq *virtio_cookie; | ||
58 | int c2h_vdev_db; | ||
59 | }; | ||
60 | |||
61 | static struct mic_irq *virtio_config_cookie; | ||
62 | #define to_micvdev(vd) container_of(vd, struct mic_vdev, vdev) | ||
63 | |||
64 | /* Helper API to obtain the parent of the virtio device */ | ||
65 | static inline struct device *mic_dev(struct mic_vdev *mvdev) | ||
66 | { | ||
67 | return mvdev->vdev.dev.parent; | ||
68 | } | ||
69 | |||
70 | /* This gets the device's feature bits. */ | ||
71 | static u32 mic_get_features(struct virtio_device *vdev) | ||
72 | { | ||
73 | unsigned int i, bits; | ||
74 | u32 features = 0; | ||
75 | struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc; | ||
76 | u8 __iomem *in_features = mic_vq_features(desc); | ||
77 | int feature_len = ioread8(&desc->feature_len); | ||
78 | |||
79 | bits = min_t(unsigned, feature_len, | ||
80 | sizeof(vdev->features)) * 8; | ||
81 | for (i = 0; i < bits; i++) | ||
82 | if (ioread8(&in_features[i / 8]) & (BIT(i % 8))) | ||
83 | features |= BIT(i); | ||
84 | |||
85 | return features; | ||
86 | } | ||
87 | |||
88 | static void mic_finalize_features(struct virtio_device *vdev) | ||
89 | { | ||
90 | unsigned int i, bits; | ||
91 | struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc; | ||
92 | u8 feature_len = ioread8(&desc->feature_len); | ||
93 | /* Second half of bitmap is features we accept. */ | ||
94 | u8 __iomem *out_features = | ||
95 | mic_vq_features(desc) + feature_len; | ||
96 | |||
97 | /* Give virtio_ring a chance to accept features. */ | ||
98 | vring_transport_features(vdev); | ||
99 | |||
100 | memset_io(out_features, 0, feature_len); | ||
101 | bits = min_t(unsigned, feature_len, | ||
102 | sizeof(vdev->features)) * 8; | ||
103 | for (i = 0; i < bits; i++) { | ||
104 | if (test_bit(i, vdev->features)) | ||
105 | iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)), | ||
106 | &out_features[i / 8]); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Reading and writing elements in config space | ||
112 | */ | ||
113 | static void mic_get(struct virtio_device *vdev, unsigned int offset, | ||
114 | void *buf, unsigned len) | ||
115 | { | ||
116 | struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc; | ||
117 | |||
118 | if (offset + len > ioread8(&desc->config_len)) | ||
119 | return; | ||
120 | memcpy_fromio(buf, mic_vq_configspace(desc) + offset, len); | ||
121 | } | ||
122 | |||
123 | static void mic_set(struct virtio_device *vdev, unsigned int offset, | ||
124 | const void *buf, unsigned len) | ||
125 | { | ||
126 | struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc; | ||
127 | |||
128 | if (offset + len > ioread8(&desc->config_len)) | ||
129 | return; | ||
130 | memcpy_toio(mic_vq_configspace(desc) + offset, buf, len); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * The operations to get and set the status word just access the status | ||
135 | * field of the device descriptor. set_status also interrupts the host | ||
136 | * to tell about status changes. | ||
137 | */ | ||
138 | static u8 mic_get_status(struct virtio_device *vdev) | ||
139 | { | ||
140 | return ioread8(&to_micvdev(vdev)->desc->status); | ||
141 | } | ||
142 | |||
143 | static void mic_set_status(struct virtio_device *vdev, u8 status) | ||
144 | { | ||
145 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
146 | if (!status) | ||
147 | return; | ||
148 | iowrite8(status, &mvdev->desc->status); | ||
149 | mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db); | ||
150 | } | ||
151 | |||
152 | /* Inform host on a virtio device reset and wait for ack from host */ | ||
153 | static void mic_reset_inform_host(struct virtio_device *vdev) | ||
154 | { | ||
155 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
156 | struct mic_device_ctrl __iomem *dc = mvdev->dc; | ||
157 | int retry = 100, i; | ||
158 | |||
159 | iowrite8(0, &dc->host_ack); | ||
160 | iowrite8(1, &dc->vdev_reset); | ||
161 | mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db); | ||
162 | |||
163 | /* Wait till host completes all card accesses and acks the reset */ | ||
164 | for (i = retry; i--;) { | ||
165 | if (ioread8(&dc->host_ack)) | ||
166 | break; | ||
167 | msleep(100); | ||
168 | }; | ||
169 | |||
170 | dev_dbg(mic_dev(mvdev), "%s: retry: %d\n", __func__, retry); | ||
171 | |||
172 | /* Reset status to 0 in case we timed out */ | ||
173 | iowrite8(0, &mvdev->desc->status); | ||
174 | } | ||
175 | |||
176 | static void mic_reset(struct virtio_device *vdev) | ||
177 | { | ||
178 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
179 | |||
180 | dev_dbg(mic_dev(mvdev), "%s: virtio id %d\n", | ||
181 | __func__, vdev->id.device); | ||
182 | |||
183 | mic_reset_inform_host(vdev); | ||
184 | complete_all(&mvdev->reset_done); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * The virtio_ring code calls this API when it wants to notify the Host. | ||
189 | */ | ||
190 | static void mic_notify(struct virtqueue *vq) | ||
191 | { | ||
192 | struct mic_vdev *mvdev = vq->priv; | ||
193 | |||
194 | mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db); | ||
195 | } | ||
196 | |||
197 | static void mic_del_vq(struct virtqueue *vq, int n) | ||
198 | { | ||
199 | struct mic_vdev *mvdev = to_micvdev(vq->vdev); | ||
200 | struct vring *vr = (struct vring *) (vq + 1); | ||
201 | |||
202 | free_pages((unsigned long) vr->used, | ||
203 | get_order(mvdev->used_size[n])); | ||
204 | vring_del_virtqueue(vq); | ||
205 | mic_card_unmap(mvdev->mdev, mvdev->vr[n]); | ||
206 | mvdev->vr[n] = NULL; | ||
207 | } | ||
208 | |||
209 | static void mic_del_vqs(struct virtio_device *vdev) | ||
210 | { | ||
211 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
212 | struct virtqueue *vq, *n; | ||
213 | int idx = 0; | ||
214 | |||
215 | dev_dbg(mic_dev(mvdev), "%s\n", __func__); | ||
216 | |||
217 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | ||
218 | mic_del_vq(vq, idx++); | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * This routine will assign vring's allocated in host/io memory. Code in | ||
223 | * virtio_ring.c however continues to access this io memory as if it were local | ||
224 | * memory without io accessors. | ||
225 | */ | ||
226 | static struct virtqueue *mic_find_vq(struct virtio_device *vdev, | ||
227 | unsigned index, | ||
228 | void (*callback)(struct virtqueue *vq), | ||
229 | const char *name) | ||
230 | { | ||
231 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
232 | struct mic_vqconfig __iomem *vqconfig; | ||
233 | struct mic_vqconfig config; | ||
234 | struct virtqueue *vq; | ||
235 | void __iomem *va; | ||
236 | struct _mic_vring_info __iomem *info; | ||
237 | void *used; | ||
238 | int vr_size, _vr_size, err, magic; | ||
239 | struct vring *vr; | ||
240 | u8 type = ioread8(&mvdev->desc->type); | ||
241 | |||
242 | if (index >= ioread8(&mvdev->desc->num_vq)) | ||
243 | return ERR_PTR(-ENOENT); | ||
244 | |||
245 | if (!name) | ||
246 | return ERR_PTR(-ENOENT); | ||
247 | |||
248 | /* First assign the vring's allocated in host memory */ | ||
249 | vqconfig = mic_vq_config(mvdev->desc) + index; | ||
250 | memcpy_fromio(&config, vqconfig, sizeof(config)); | ||
251 | _vr_size = vring_size(config.num, MIC_VIRTIO_RING_ALIGN); | ||
252 | vr_size = PAGE_ALIGN(_vr_size + sizeof(struct _mic_vring_info)); | ||
253 | va = mic_card_map(mvdev->mdev, config.address, vr_size); | ||
254 | if (!va) | ||
255 | return ERR_PTR(-ENOMEM); | ||
256 | mvdev->vr[index] = va; | ||
257 | memset_io(va, 0x0, _vr_size); | ||
258 | vq = vring_new_virtqueue(index, | ||
259 | config.num, MIC_VIRTIO_RING_ALIGN, vdev, | ||
260 | false, | ||
261 | va, mic_notify, callback, name); | ||
262 | if (!vq) { | ||
263 | err = -ENOMEM; | ||
264 | goto unmap; | ||
265 | } | ||
266 | info = va + _vr_size; | ||
267 | magic = ioread32(&info->magic); | ||
268 | |||
269 | if (WARN(magic != MIC_MAGIC + type + index, "magic mismatch")) { | ||
270 | err = -EIO; | ||
271 | goto unmap; | ||
272 | } | ||
273 | |||
274 | /* Allocate and reassign used ring now */ | ||
275 | mvdev->used_size[index] = PAGE_ALIGN(sizeof(__u16) * 3 + | ||
276 | sizeof(struct vring_used_elem) * config.num); | ||
277 | used = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
278 | get_order(mvdev->used_size[index])); | ||
279 | if (!used) { | ||
280 | err = -ENOMEM; | ||
281 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
282 | __func__, __LINE__, err); | ||
283 | goto del_vq; | ||
284 | } | ||
285 | iowrite64(virt_to_phys(used), &vqconfig->used_address); | ||
286 | |||
287 | /* | ||
288 | * To reassign the used ring here we are directly accessing | ||
289 | * struct vring_virtqueue which is a private data structure | ||
290 | * in virtio_ring.c. At the minimum, a BUILD_BUG_ON() in | ||
291 | * vring_new_virtqueue() would ensure that | ||
292 | * (&vq->vring == (struct vring *) (&vq->vq + 1)); | ||
293 | */ | ||
294 | vr = (struct vring *) (vq + 1); | ||
295 | vr->used = used; | ||
296 | |||
297 | vq->priv = mvdev; | ||
298 | return vq; | ||
299 | del_vq: | ||
300 | vring_del_virtqueue(vq); | ||
301 | unmap: | ||
302 | mic_card_unmap(mvdev->mdev, mvdev->vr[index]); | ||
303 | return ERR_PTR(err); | ||
304 | } | ||
305 | |||
306 | static int mic_find_vqs(struct virtio_device *vdev, unsigned nvqs, | ||
307 | struct virtqueue *vqs[], | ||
308 | vq_callback_t *callbacks[], | ||
309 | const char *names[]) | ||
310 | { | ||
311 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
312 | struct mic_device_ctrl __iomem *dc = mvdev->dc; | ||
313 | int i, err, retry = 100; | ||
314 | |||
315 | /* We must have this many virtqueues. */ | ||
316 | if (nvqs > ioread8(&mvdev->desc->num_vq)) | ||
317 | return -ENOENT; | ||
318 | |||
319 | for (i = 0; i < nvqs; ++i) { | ||
320 | dev_dbg(mic_dev(mvdev), "%s: %d: %s\n", | ||
321 | __func__, i, names[i]); | ||
322 | vqs[i] = mic_find_vq(vdev, i, callbacks[i], names[i]); | ||
323 | if (IS_ERR(vqs[i])) { | ||
324 | err = PTR_ERR(vqs[i]); | ||
325 | goto error; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | iowrite8(1, &dc->used_address_updated); | ||
330 | /* | ||
331 | * Send an interrupt to the host to inform it that used | ||
332 | * rings have been re-assigned. | ||
333 | */ | ||
334 | mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db); | ||
335 | for (i = retry; i--;) { | ||
336 | if (!ioread8(&dc->used_address_updated)) | ||
337 | break; | ||
338 | msleep(100); | ||
339 | }; | ||
340 | |||
341 | dev_dbg(mic_dev(mvdev), "%s: retry: %d\n", __func__, retry); | ||
342 | if (!retry) { | ||
343 | err = -ENODEV; | ||
344 | goto error; | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | error: | ||
349 | mic_del_vqs(vdev); | ||
350 | return err; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * The config ops structure as defined by virtio config | ||
355 | */ | ||
356 | static struct virtio_config_ops mic_vq_config_ops = { | ||
357 | .get_features = mic_get_features, | ||
358 | .finalize_features = mic_finalize_features, | ||
359 | .get = mic_get, | ||
360 | .set = mic_set, | ||
361 | .get_status = mic_get_status, | ||
362 | .set_status = mic_set_status, | ||
363 | .reset = mic_reset, | ||
364 | .find_vqs = mic_find_vqs, | ||
365 | .del_vqs = mic_del_vqs, | ||
366 | }; | ||
367 | |||
368 | static irqreturn_t | ||
369 | mic_virtio_intr_handler(int irq, void *data) | ||
370 | { | ||
371 | struct mic_vdev *mvdev = data; | ||
372 | struct virtqueue *vq; | ||
373 | |||
374 | mic_ack_interrupt(mvdev->mdev); | ||
375 | list_for_each_entry(vq, &mvdev->vdev.vqs, list) | ||
376 | vring_interrupt(0, vq); | ||
377 | |||
378 | return IRQ_HANDLED; | ||
379 | } | ||
380 | |||
381 | static void mic_virtio_release_dev(struct device *_d) | ||
382 | { | ||
383 | /* | ||
384 | * No need for a release method similar to virtio PCI. | ||
385 | * Provide an empty one to avoid getting a warning from core. | ||
386 | */ | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * adds a new device and register it with virtio | ||
391 | * appropriate drivers are loaded by the device model | ||
392 | */ | ||
393 | static int mic_add_device(struct mic_device_desc __iomem *d, | ||
394 | unsigned int offset, struct mic_driver *mdrv) | ||
395 | { | ||
396 | struct mic_vdev *mvdev; | ||
397 | int ret; | ||
398 | int virtio_db; | ||
399 | u8 type = ioread8(&d->type); | ||
400 | |||
401 | mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL); | ||
402 | if (!mvdev) { | ||
403 | dev_err(mdrv->dev, "Cannot allocate mic dev %u type %u\n", | ||
404 | offset, type); | ||
405 | return -ENOMEM; | ||
406 | } | ||
407 | |||
408 | mvdev->mdev = &mdrv->mdev; | ||
409 | mvdev->vdev.dev.parent = mdrv->dev; | ||
410 | mvdev->vdev.dev.release = mic_virtio_release_dev; | ||
411 | mvdev->vdev.id.device = type; | ||
412 | mvdev->vdev.config = &mic_vq_config_ops; | ||
413 | mvdev->desc = d; | ||
414 | mvdev->dc = (void __iomem *)d + mic_aligned_desc_size(d); | ||
415 | init_completion(&mvdev->reset_done); | ||
416 | |||
417 | virtio_db = mic_next_card_db(); | ||
418 | mvdev->virtio_cookie = mic_request_card_irq(mic_virtio_intr_handler, | ||
419 | "virtio intr", mvdev, virtio_db); | ||
420 | if (IS_ERR(mvdev->virtio_cookie)) { | ||
421 | ret = PTR_ERR(mvdev->virtio_cookie); | ||
422 | goto kfree; | ||
423 | } | ||
424 | iowrite8((u8)virtio_db, &mvdev->dc->h2c_vdev_db); | ||
425 | mvdev->c2h_vdev_db = ioread8(&mvdev->dc->c2h_vdev_db); | ||
426 | |||
427 | ret = register_virtio_device(&mvdev->vdev); | ||
428 | if (ret) { | ||
429 | dev_err(mic_dev(mvdev), | ||
430 | "Failed to register mic device %u type %u\n", | ||
431 | offset, type); | ||
432 | goto free_irq; | ||
433 | } | ||
434 | iowrite64((u64)mvdev, &mvdev->dc->vdev); | ||
435 | dev_dbg(mic_dev(mvdev), "%s: registered mic device %u type %u mvdev %p\n", | ||
436 | __func__, offset, type, mvdev); | ||
437 | |||
438 | return 0; | ||
439 | |||
440 | free_irq: | ||
441 | mic_free_card_irq(mvdev->virtio_cookie, mvdev); | ||
442 | kfree: | ||
443 | kfree(mvdev); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * match for a mic device with a specific desc pointer | ||
449 | */ | ||
450 | static int mic_match_desc(struct device *dev, void *data) | ||
451 | { | ||
452 | struct virtio_device *vdev = dev_to_virtio(dev); | ||
453 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
454 | |||
455 | return mvdev->desc == (void __iomem *)data; | ||
456 | } | ||
457 | |||
458 | static void mic_handle_config_change(struct mic_device_desc __iomem *d, | ||
459 | unsigned int offset, struct mic_driver *mdrv) | ||
460 | { | ||
461 | struct mic_device_ctrl __iomem *dc | ||
462 | = (void __iomem *)d + mic_aligned_desc_size(d); | ||
463 | struct mic_vdev *mvdev = (struct mic_vdev *)ioread64(&dc->vdev); | ||
464 | struct virtio_driver *drv; | ||
465 | |||
466 | if (ioread8(&dc->config_change) != MIC_VIRTIO_PARAM_CONFIG_CHANGED) | ||
467 | return; | ||
468 | |||
469 | dev_dbg(mdrv->dev, "%s %d\n", __func__, __LINE__); | ||
470 | drv = container_of(mvdev->vdev.dev.driver, | ||
471 | struct virtio_driver, driver); | ||
472 | if (drv->config_changed) | ||
473 | drv->config_changed(&mvdev->vdev); | ||
474 | iowrite8(1, &dc->guest_ack); | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * removes a virtio device if a hot remove event has been | ||
479 | * requested by the host. | ||
480 | */ | ||
481 | static int mic_remove_device(struct mic_device_desc __iomem *d, | ||
482 | unsigned int offset, struct mic_driver *mdrv) | ||
483 | { | ||
484 | struct mic_device_ctrl __iomem *dc | ||
485 | = (void __iomem *)d + mic_aligned_desc_size(d); | ||
486 | struct mic_vdev *mvdev = (struct mic_vdev *)ioread64(&dc->vdev); | ||
487 | u8 status; | ||
488 | int ret = -1; | ||
489 | |||
490 | if (ioread8(&dc->config_change) == MIC_VIRTIO_PARAM_DEV_REMOVE) { | ||
491 | dev_dbg(mdrv->dev, | ||
492 | "%s %d config_change %d type %d mvdev %p\n", | ||
493 | __func__, __LINE__, | ||
494 | ioread8(&dc->config_change), ioread8(&d->type), mvdev); | ||
495 | |||
496 | status = ioread8(&d->status); | ||
497 | INIT_COMPLETION(mvdev->reset_done); | ||
498 | unregister_virtio_device(&mvdev->vdev); | ||
499 | mic_free_card_irq(mvdev->virtio_cookie, mvdev); | ||
500 | if (status & VIRTIO_CONFIG_S_DRIVER_OK) | ||
501 | wait_for_completion(&mvdev->reset_done); | ||
502 | kfree(mvdev); | ||
503 | iowrite8(1, &dc->guest_ack); | ||
504 | dev_dbg(mdrv->dev, "%s %d guest_ack %d\n", | ||
505 | __func__, __LINE__, ioread8(&dc->guest_ack)); | ||
506 | ret = 0; | ||
507 | } | ||
508 | |||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | #define REMOVE_DEVICES true | ||
513 | |||
514 | static void mic_scan_devices(struct mic_driver *mdrv, bool remove) | ||
515 | { | ||
516 | s8 type; | ||
517 | unsigned int i; | ||
518 | struct mic_device_desc __iomem *d; | ||
519 | struct mic_device_ctrl __iomem *dc; | ||
520 | struct device *dev; | ||
521 | int ret; | ||
522 | |||
523 | for (i = mic_aligned_size(struct mic_bootparam); | ||
524 | i < MIC_DP_SIZE; i += mic_total_desc_size(d)) { | ||
525 | d = mdrv->dp + i; | ||
526 | dc = (void __iomem *)d + mic_aligned_desc_size(d); | ||
527 | /* | ||
528 | * This read barrier is paired with the corresponding write | ||
529 | * barrier on the host which is inserted before adding or | ||
530 | * removing a virtio device descriptor, by updating the type. | ||
531 | */ | ||
532 | rmb(); | ||
533 | type = ioread8(&d->type); | ||
534 | |||
535 | /* end of list */ | ||
536 | if (type == 0) | ||
537 | break; | ||
538 | |||
539 | if (type == -1) | ||
540 | continue; | ||
541 | |||
542 | /* device already exists */ | ||
543 | dev = device_find_child(mdrv->dev, d, mic_match_desc); | ||
544 | if (dev) { | ||
545 | if (remove) | ||
546 | iowrite8(MIC_VIRTIO_PARAM_DEV_REMOVE, | ||
547 | &dc->config_change); | ||
548 | put_device(dev); | ||
549 | mic_handle_config_change(d, i, mdrv); | ||
550 | ret = mic_remove_device(d, i, mdrv); | ||
551 | if (!ret && !remove) | ||
552 | iowrite8(-1, &d->type); | ||
553 | if (remove) { | ||
554 | iowrite8(0, &dc->config_change); | ||
555 | iowrite8(0, &dc->guest_ack); | ||
556 | } | ||
557 | continue; | ||
558 | } | ||
559 | |||
560 | /* new device */ | ||
561 | dev_dbg(mdrv->dev, "%s %d Adding new virtio device %p\n", | ||
562 | __func__, __LINE__, d); | ||
563 | if (!remove) | ||
564 | mic_add_device(d, i, mdrv); | ||
565 | } | ||
566 | } | ||
567 | |||
568 | /* | ||
569 | * mic_hotplug_device tries to find changes in the device page. | ||
570 | */ | ||
571 | static void mic_hotplug_devices(struct work_struct *work) | ||
572 | { | ||
573 | struct mic_driver *mdrv = container_of(work, | ||
574 | struct mic_driver, hotplug_work); | ||
575 | |||
576 | mic_scan_devices(mdrv, !REMOVE_DEVICES); | ||
577 | } | ||
578 | |||
579 | /* | ||
580 | * Interrupt handler for hot plug/config changes etc. | ||
581 | */ | ||
582 | static irqreturn_t | ||
583 | mic_extint_handler(int irq, void *data) | ||
584 | { | ||
585 | struct mic_driver *mdrv = (struct mic_driver *)data; | ||
586 | |||
587 | dev_dbg(mdrv->dev, "%s %d hotplug work\n", | ||
588 | __func__, __LINE__); | ||
589 | mic_ack_interrupt(&mdrv->mdev); | ||
590 | schedule_work(&mdrv->hotplug_work); | ||
591 | return IRQ_HANDLED; | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * Init function for virtio | ||
596 | */ | ||
597 | int mic_devices_init(struct mic_driver *mdrv) | ||
598 | { | ||
599 | int rc; | ||
600 | struct mic_bootparam __iomem *bootparam; | ||
601 | int config_db; | ||
602 | |||
603 | INIT_WORK(&mdrv->hotplug_work, mic_hotplug_devices); | ||
604 | mic_scan_devices(mdrv, !REMOVE_DEVICES); | ||
605 | |||
606 | config_db = mic_next_card_db(); | ||
607 | virtio_config_cookie = mic_request_card_irq(mic_extint_handler, | ||
608 | "virtio_config_intr", mdrv, config_db); | ||
609 | if (IS_ERR(virtio_config_cookie)) { | ||
610 | rc = PTR_ERR(virtio_config_cookie); | ||
611 | goto exit; | ||
612 | } | ||
613 | |||
614 | bootparam = mdrv->dp; | ||
615 | iowrite8(config_db, &bootparam->h2c_config_db); | ||
616 | return 0; | ||
617 | exit: | ||
618 | return rc; | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * Uninit function for virtio | ||
623 | */ | ||
624 | void mic_devices_uninit(struct mic_driver *mdrv) | ||
625 | { | ||
626 | struct mic_bootparam __iomem *bootparam = mdrv->dp; | ||
627 | iowrite8(-1, &bootparam->h2c_config_db); | ||
628 | mic_free_card_irq(virtio_config_cookie, mdrv); | ||
629 | flush_work(&mdrv->hotplug_work); | ||
630 | mic_scan_devices(mdrv, REMOVE_DEVICES); | ||
631 | } | ||
diff --git a/drivers/misc/mic/card/mic_virtio.h b/drivers/misc/mic/card/mic_virtio.h new file mode 100644 index 000000000000..2c5c22c93ba8 --- /dev/null +++ b/drivers/misc/mic/card/mic_virtio.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Disclaimer: The codes contained in these modules may be specific to | ||
19 | * the Intel Software Development Platform codenamed: Knights Ferry, and | ||
20 | * the Intel product codenamed: Knights Corner, and are not backward | ||
21 | * compatible with other Intel products. Additionally, Intel will NOT | ||
22 | * support the codes or instruction set in future products. | ||
23 | * | ||
24 | * Intel MIC Card driver. | ||
25 | * | ||
26 | */ | ||
27 | #ifndef __MIC_CARD_VIRTIO_H | ||
28 | #define __MIC_CARD_VIRTIO_H | ||
29 | |||
30 | #include <linux/mic_common.h> | ||
31 | #include "mic_device.h" | ||
32 | |||
33 | /* | ||
34 | * 64 bit I/O access | ||
35 | */ | ||
36 | #ifndef ioread64 | ||
37 | #define ioread64 readq | ||
38 | #endif | ||
39 | #ifndef iowrite64 | ||
40 | #define iowrite64 writeq | ||
41 | #endif | ||
42 | |||
43 | static inline unsigned mic_desc_size(struct mic_device_desc __iomem *desc) | ||
44 | { | ||
45 | return mic_aligned_size(*desc) | ||
46 | + ioread8(&desc->num_vq) * mic_aligned_size(struct mic_vqconfig) | ||
47 | + ioread8(&desc->feature_len) * 2 | ||
48 | + ioread8(&desc->config_len); | ||
49 | } | ||
50 | |||
51 | static inline struct mic_vqconfig __iomem * | ||
52 | mic_vq_config(struct mic_device_desc __iomem *desc) | ||
53 | { | ||
54 | return (struct mic_vqconfig __iomem *)(desc + 1); | ||
55 | } | ||
56 | |||
57 | static inline __u8 __iomem * | ||
58 | mic_vq_features(struct mic_device_desc __iomem *desc) | ||
59 | { | ||
60 | return (__u8 __iomem *)(mic_vq_config(desc) + ioread8(&desc->num_vq)); | ||
61 | } | ||
62 | |||
63 | static inline __u8 __iomem * | ||
64 | mic_vq_configspace(struct mic_device_desc __iomem *desc) | ||
65 | { | ||
66 | return mic_vq_features(desc) + ioread8(&desc->feature_len) * 2; | ||
67 | } | ||
68 | static inline unsigned mic_total_desc_size(struct mic_device_desc __iomem *desc) | ||
69 | { | ||
70 | return mic_aligned_desc_size(desc) + | ||
71 | mic_aligned_size(struct mic_device_ctrl); | ||
72 | } | ||
73 | |||
74 | int mic_devices_init(struct mic_driver *mdrv); | ||
75 | void mic_devices_uninit(struct mic_driver *mdrv); | ||
76 | |||
77 | #endif | ||
diff --git a/drivers/misc/mic/card/mic_x100.c b/drivers/misc/mic/card/mic_x100.c new file mode 100644 index 000000000000..7cb3469cf684 --- /dev/null +++ b/drivers/misc/mic/card/mic_x100.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Disclaimer: The codes contained in these modules may be specific to | ||
19 | * the Intel Software Development Platform codenamed: Knights Ferry, and | ||
20 | * the Intel product codenamed: Knights Corner, and are not backward | ||
21 | * compatible with other Intel products. Additionally, Intel will NOT | ||
22 | * support the codes or instruction set in future products. | ||
23 | * | ||
24 | * Intel MIC Card driver. | ||
25 | * | ||
26 | */ | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | |||
31 | #include "../common/mic_device.h" | ||
32 | #include "mic_device.h" | ||
33 | #include "mic_x100.h" | ||
34 | |||
35 | static const char mic_driver_name[] = "mic"; | ||
36 | |||
37 | static struct mic_driver g_drv; | ||
38 | |||
39 | /** | ||
40 | * mic_read_spad - read from the scratchpad register | ||
41 | * @mdev: pointer to mic_device instance | ||
42 | * @idx: index to scratchpad register, 0 based | ||
43 | * | ||
44 | * This function allows reading of the 32bit scratchpad register. | ||
45 | * | ||
46 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
47 | */ | ||
48 | u32 mic_read_spad(struct mic_device *mdev, unsigned int idx) | ||
49 | { | ||
50 | return mic_mmio_read(&mdev->mmio, | ||
51 | MIC_X100_SBOX_BASE_ADDRESS + | ||
52 | MIC_X100_SBOX_SPAD0 + idx * 4); | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * __mic_send_intr - Send interrupt to Host. | ||
57 | * @mdev: pointer to mic_device instance | ||
58 | * @doorbell: Doorbell number. | ||
59 | */ | ||
60 | void mic_send_intr(struct mic_device *mdev, int doorbell) | ||
61 | { | ||
62 | struct mic_mw *mw = &mdev->mmio; | ||
63 | |||
64 | if (doorbell > MIC_X100_MAX_DOORBELL_IDX) | ||
65 | return; | ||
66 | /* Ensure that the interrupt is ordered w.r.t previous stores. */ | ||
67 | wmb(); | ||
68 | mic_mmio_write(mw, MIC_X100_SBOX_SDBIC0_DBREQ_BIT, | ||
69 | MIC_X100_SBOX_BASE_ADDRESS + | ||
70 | (MIC_X100_SBOX_SDBIC0 + (4 * doorbell))); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * mic_ack_interrupt - Device specific interrupt handling. | ||
75 | * @mdev: pointer to mic_device instance | ||
76 | * | ||
77 | * Returns: bitmask of doorbell events triggered. | ||
78 | */ | ||
79 | u32 mic_ack_interrupt(struct mic_device *mdev) | ||
80 | { | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static inline int mic_get_sbox_irq(int db) | ||
85 | { | ||
86 | return MIC_X100_IRQ_BASE + db; | ||
87 | } | ||
88 | |||
89 | static inline int mic_get_rdmasr_irq(int index) | ||
90 | { | ||
91 | return MIC_X100_RDMASR_IRQ_BASE + index; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * mic_hw_intr_init - Initialize h/w specific interrupt | ||
96 | * information. | ||
97 | * @mdrv: pointer to mic_driver | ||
98 | */ | ||
99 | void mic_hw_intr_init(struct mic_driver *mdrv) | ||
100 | { | ||
101 | mdrv->intr_info.num_intr = MIC_X100_NUM_SBOX_IRQ + | ||
102 | MIC_X100_NUM_RDMASR_IRQ; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * mic_db_to_irq - Retrieve irq number corresponding to a doorbell. | ||
107 | * @mdrv: pointer to mic_driver | ||
108 | * @db: The doorbell obtained for which the irq is needed. Doorbell | ||
109 | * may correspond to an sbox doorbell or an rdmasr index. | ||
110 | * | ||
111 | * Returns the irq corresponding to the doorbell. | ||
112 | */ | ||
113 | int mic_db_to_irq(struct mic_driver *mdrv, int db) | ||
114 | { | ||
115 | int rdmasr_index; | ||
116 | if (db < MIC_X100_NUM_SBOX_IRQ) { | ||
117 | return mic_get_sbox_irq(db); | ||
118 | } else { | ||
119 | rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ + | ||
120 | MIC_X100_RDMASR_IRQ_BASE; | ||
121 | return mic_get_rdmasr_irq(rdmasr_index); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * mic_card_map - Allocate virtual address for a remote memory region. | ||
127 | * @mdev: pointer to mic_device instance. | ||
128 | * @addr: Remote DMA address. | ||
129 | * @size: Size of the region. | ||
130 | * | ||
131 | * Returns: Virtual address backing the remote memory region. | ||
132 | */ | ||
133 | void __iomem * | ||
134 | mic_card_map(struct mic_device *mdev, dma_addr_t addr, size_t size) | ||
135 | { | ||
136 | return ioremap(addr, size); | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * mic_card_unmap - Unmap the virtual address for a remote memory region. | ||
141 | * @mdev: pointer to mic_device instance. | ||
142 | * @addr: Virtual address for remote memory region. | ||
143 | * | ||
144 | * Returns: None. | ||
145 | */ | ||
146 | void mic_card_unmap(struct mic_device *mdev, void __iomem *addr) | ||
147 | { | ||
148 | iounmap(addr); | ||
149 | } | ||
150 | |||
151 | static int __init mic_probe(struct platform_device *pdev) | ||
152 | { | ||
153 | struct mic_driver *mdrv = &g_drv; | ||
154 | struct mic_device *mdev = &mdrv->mdev; | ||
155 | int rc = 0; | ||
156 | |||
157 | mdrv->dev = &pdev->dev; | ||
158 | snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name); | ||
159 | |||
160 | mdev->mmio.pa = MIC_X100_MMIO_BASE; | ||
161 | mdev->mmio.len = MIC_X100_MMIO_LEN; | ||
162 | mdev->mmio.va = ioremap(MIC_X100_MMIO_BASE, MIC_X100_MMIO_LEN); | ||
163 | if (!mdev->mmio.va) { | ||
164 | dev_err(&pdev->dev, "Cannot remap MMIO BAR\n"); | ||
165 | rc = -EIO; | ||
166 | goto done; | ||
167 | } | ||
168 | mic_hw_intr_init(mdrv); | ||
169 | rc = mic_driver_init(mdrv); | ||
170 | if (rc) { | ||
171 | dev_err(&pdev->dev, "mic_driver_init failed rc %d\n", rc); | ||
172 | goto iounmap; | ||
173 | } | ||
174 | done: | ||
175 | return rc; | ||
176 | iounmap: | ||
177 | iounmap(mdev->mmio.va); | ||
178 | return rc; | ||
179 | } | ||
180 | |||
181 | static int mic_remove(struct platform_device *pdev) | ||
182 | { | ||
183 | struct mic_driver *mdrv = &g_drv; | ||
184 | struct mic_device *mdev = &mdrv->mdev; | ||
185 | |||
186 | mic_driver_uninit(mdrv); | ||
187 | iounmap(mdev->mmio.va); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static void mic_platform_shutdown(struct platform_device *pdev) | ||
192 | { | ||
193 | mic_remove(pdev); | ||
194 | } | ||
195 | |||
196 | static struct platform_device mic_platform_dev = { | ||
197 | .name = mic_driver_name, | ||
198 | .id = 0, | ||
199 | .num_resources = 0, | ||
200 | }; | ||
201 | |||
202 | static struct platform_driver __refdata mic_platform_driver = { | ||
203 | .probe = mic_probe, | ||
204 | .remove = mic_remove, | ||
205 | .shutdown = mic_platform_shutdown, | ||
206 | .driver = { | ||
207 | .name = mic_driver_name, | ||
208 | .owner = THIS_MODULE, | ||
209 | }, | ||
210 | }; | ||
211 | |||
212 | static int __init mic_init(void) | ||
213 | { | ||
214 | int ret; | ||
215 | struct cpuinfo_x86 *c = &cpu_data(0); | ||
216 | |||
217 | if (!(c->x86 == 11 && c->x86_model == 1)) { | ||
218 | ret = -ENODEV; | ||
219 | pr_err("%s not running on X100 ret %d\n", __func__, ret); | ||
220 | goto done; | ||
221 | } | ||
222 | |||
223 | mic_init_card_debugfs(); | ||
224 | ret = platform_device_register(&mic_platform_dev); | ||
225 | if (ret) { | ||
226 | pr_err("platform_device_register ret %d\n", ret); | ||
227 | goto cleanup_debugfs; | ||
228 | } | ||
229 | ret = platform_driver_register(&mic_platform_driver); | ||
230 | if (ret) { | ||
231 | pr_err("platform_driver_register ret %d\n", ret); | ||
232 | goto device_unregister; | ||
233 | } | ||
234 | return ret; | ||
235 | |||
236 | device_unregister: | ||
237 | platform_device_unregister(&mic_platform_dev); | ||
238 | cleanup_debugfs: | ||
239 | mic_exit_card_debugfs(); | ||
240 | done: | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static void __exit mic_exit(void) | ||
245 | { | ||
246 | platform_driver_unregister(&mic_platform_driver); | ||
247 | platform_device_unregister(&mic_platform_dev); | ||
248 | mic_exit_card_debugfs(); | ||
249 | } | ||
250 | |||
251 | module_init(mic_init); | ||
252 | module_exit(mic_exit); | ||
253 | |||
254 | MODULE_AUTHOR("Intel Corporation"); | ||
255 | MODULE_DESCRIPTION("Intel(R) MIC X100 Card driver"); | ||
256 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/mic/card/mic_x100.h b/drivers/misc/mic/card/mic_x100.h new file mode 100644 index 000000000000..d66ea55639c3 --- /dev/null +++ b/drivers/misc/mic/card/mic_x100.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Disclaimer: The codes contained in these modules may be specific to | ||
19 | * the Intel Software Development Platform codenamed: Knights Ferry, and | ||
20 | * the Intel product codenamed: Knights Corner, and are not backward | ||
21 | * compatible with other Intel products. Additionally, Intel will NOT | ||
22 | * support the codes or instruction set in future products. | ||
23 | * | ||
24 | * Intel MIC Card driver. | ||
25 | * | ||
26 | */ | ||
27 | #ifndef _MIC_X100_CARD_H_ | ||
28 | #define _MIC_X100_CARD_H_ | ||
29 | |||
30 | #define MIC_X100_MMIO_BASE 0x08007C0000ULL | ||
31 | #define MIC_X100_MMIO_LEN 0x00020000ULL | ||
32 | #define MIC_X100_SBOX_BASE_ADDRESS 0x00010000ULL | ||
33 | |||
34 | #define MIC_X100_SBOX_SPAD0 0x0000AB20 | ||
35 | #define MIC_X100_SBOX_SDBIC0 0x0000CC90 | ||
36 | #define MIC_X100_SBOX_SDBIC0_DBREQ_BIT 0x80000000 | ||
37 | #define MIC_X100_SBOX_RDMASR0 0x0000B180 | ||
38 | |||
39 | #define MIC_X100_MAX_DOORBELL_IDX 8 | ||
40 | |||
41 | #define MIC_X100_NUM_SBOX_IRQ 8 | ||
42 | #define MIC_X100_NUM_RDMASR_IRQ 8 | ||
43 | #define MIC_X100_SBOX_IRQ_BASE 0 | ||
44 | #define MIC_X100_RDMASR_IRQ_BASE 17 | ||
45 | |||
46 | #define MIC_X100_IRQ_BASE 26 | ||
47 | |||
48 | #endif | ||
diff --git a/drivers/misc/mic/common/mic_device.h b/drivers/misc/mic/common/mic_device.h new file mode 100644 index 000000000000..01eb74faae6b --- /dev/null +++ b/drivers/misc/mic/common/mic_device.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC driver. | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __MIC_COMMON_DEVICE_H_ | ||
22 | #define __MIC_COMMON_DEVICE_H_ | ||
23 | |||
24 | /** | ||
25 | * struct mic_mw - MIC memory window | ||
26 | * | ||
27 | * @pa: Base physical address. | ||
28 | * @va: Base ioremap'd virtual address. | ||
29 | * @len: Size of the memory window. | ||
30 | */ | ||
31 | struct mic_mw { | ||
32 | phys_addr_t pa; | ||
33 | void __iomem *va; | ||
34 | resource_size_t len; | ||
35 | }; | ||
36 | |||
37 | /* | ||
38 | * Scratch pad register offsets used by the host to communicate | ||
39 | * device page DMA address to the card. | ||
40 | */ | ||
41 | #define MIC_DPLO_SPAD 14 | ||
42 | #define MIC_DPHI_SPAD 15 | ||
43 | |||
44 | /* | ||
45 | * These values are supposed to be in the config_change field of the | ||
46 | * device page when the host sends a config change interrupt to the card. | ||
47 | */ | ||
48 | #define MIC_VIRTIO_PARAM_DEV_REMOVE 0x1 | ||
49 | #define MIC_VIRTIO_PARAM_CONFIG_CHANGED 0x2 | ||
50 | |||
51 | #endif | ||
diff --git a/drivers/misc/mic/host/Makefile b/drivers/misc/mic/host/Makefile new file mode 100644 index 000000000000..c2197f999394 --- /dev/null +++ b/drivers/misc/mic/host/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | # | ||
2 | # Makefile - Intel MIC Linux driver. | ||
3 | # Copyright(c) 2013, Intel Corporation. | ||
4 | # | ||
5 | obj-$(CONFIG_INTEL_MIC_HOST) += mic_host.o | ||
6 | mic_host-objs := mic_main.o | ||
7 | mic_host-objs += mic_x100.o | ||
8 | mic_host-objs += mic_sysfs.o | ||
9 | mic_host-objs += mic_smpt.o | ||
10 | mic_host-objs += mic_intr.o | ||
11 | mic_host-objs += mic_boot.o | ||
12 | mic_host-objs += mic_debugfs.o | ||
13 | mic_host-objs += mic_fops.o | ||
14 | mic_host-objs += mic_virtio.o | ||
diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c new file mode 100644 index 000000000000..fd9ff6d3784e --- /dev/null +++ b/drivers/misc/mic/host/mic_boot.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/firmware.h> | ||
23 | |||
24 | #include <linux/mic_common.h> | ||
25 | #include "../common/mic_device.h" | ||
26 | #include "mic_device.h" | ||
27 | #include "mic_smpt.h" | ||
28 | #include "mic_virtio.h" | ||
29 | |||
30 | /** | ||
31 | * mic_reset - Reset the MIC device. | ||
32 | * @mdev: pointer to mic_device instance | ||
33 | */ | ||
34 | static void mic_reset(struct mic_device *mdev) | ||
35 | { | ||
36 | int i; | ||
37 | |||
38 | #define MIC_RESET_TO (45) | ||
39 | |||
40 | mdev->ops->reset_fw_ready(mdev); | ||
41 | mdev->ops->reset(mdev); | ||
42 | |||
43 | for (i = 0; i < MIC_RESET_TO; i++) { | ||
44 | if (mdev->ops->is_fw_ready(mdev)) | ||
45 | return; | ||
46 | /* | ||
47 | * Resets typically take 10s of seconds to complete. | ||
48 | * Since an MMIO read is required to check if the | ||
49 | * firmware is ready or not, a 1 second delay works nicely. | ||
50 | */ | ||
51 | msleep(1000); | ||
52 | } | ||
53 | mic_set_state(mdev, MIC_RESET_FAILED); | ||
54 | } | ||
55 | |||
56 | /* Initialize the MIC bootparams */ | ||
57 | void mic_bootparam_init(struct mic_device *mdev) | ||
58 | { | ||
59 | struct mic_bootparam *bootparam = mdev->dp; | ||
60 | |||
61 | bootparam->magic = MIC_MAGIC; | ||
62 | bootparam->c2h_shutdown_db = mdev->shutdown_db; | ||
63 | bootparam->h2c_shutdown_db = -1; | ||
64 | bootparam->h2c_config_db = -1; | ||
65 | bootparam->shutdown_status = 0; | ||
66 | bootparam->shutdown_card = 0; | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * mic_start - Start the MIC. | ||
71 | * @mdev: pointer to mic_device instance | ||
72 | * @buf: buffer containing boot string including firmware/ramdisk path. | ||
73 | * | ||
74 | * This function prepares an MIC for boot and initiates boot. | ||
75 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
76 | */ | ||
77 | int mic_start(struct mic_device *mdev, const char *buf) | ||
78 | { | ||
79 | int rc; | ||
80 | mutex_lock(&mdev->mic_mutex); | ||
81 | retry: | ||
82 | if (MIC_OFFLINE != mdev->state) { | ||
83 | rc = -EINVAL; | ||
84 | goto unlock_ret; | ||
85 | } | ||
86 | if (!mdev->ops->is_fw_ready(mdev)) { | ||
87 | mic_reset(mdev); | ||
88 | /* | ||
89 | * The state will either be MIC_OFFLINE if the reset succeeded | ||
90 | * or MIC_RESET_FAILED if the firmware reset failed. | ||
91 | */ | ||
92 | goto retry; | ||
93 | } | ||
94 | rc = mdev->ops->load_mic_fw(mdev, buf); | ||
95 | if (rc) | ||
96 | goto unlock_ret; | ||
97 | mic_smpt_restore(mdev); | ||
98 | mic_intr_restore(mdev); | ||
99 | mdev->intr_ops->enable_interrupts(mdev); | ||
100 | mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); | ||
101 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | ||
102 | mdev->ops->send_firmware_intr(mdev); | ||
103 | mic_set_state(mdev, MIC_ONLINE); | ||
104 | unlock_ret: | ||
105 | mutex_unlock(&mdev->mic_mutex); | ||
106 | return rc; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * mic_stop - Prepare the MIC for reset and trigger reset. | ||
111 | * @mdev: pointer to mic_device instance | ||
112 | * @force: force a MIC to reset even if it is already offline. | ||
113 | * | ||
114 | * RETURNS: None. | ||
115 | */ | ||
116 | void mic_stop(struct mic_device *mdev, bool force) | ||
117 | { | ||
118 | mutex_lock(&mdev->mic_mutex); | ||
119 | if (MIC_OFFLINE != mdev->state || force) { | ||
120 | mic_virtio_reset_devices(mdev); | ||
121 | mic_bootparam_init(mdev); | ||
122 | mic_reset(mdev); | ||
123 | if (MIC_RESET_FAILED == mdev->state) | ||
124 | goto unlock; | ||
125 | mic_set_shutdown_status(mdev, MIC_NOP); | ||
126 | mic_set_state(mdev, MIC_OFFLINE); | ||
127 | } | ||
128 | unlock: | ||
129 | mutex_unlock(&mdev->mic_mutex); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * mic_shutdown - Initiate MIC shutdown. | ||
134 | * @mdev: pointer to mic_device instance | ||
135 | * | ||
136 | * RETURNS: None. | ||
137 | */ | ||
138 | void mic_shutdown(struct mic_device *mdev) | ||
139 | { | ||
140 | struct mic_bootparam *bootparam = mdev->dp; | ||
141 | s8 db = bootparam->h2c_shutdown_db; | ||
142 | |||
143 | mutex_lock(&mdev->mic_mutex); | ||
144 | if (MIC_ONLINE == mdev->state && db != -1) { | ||
145 | bootparam->shutdown_card = 1; | ||
146 | mdev->ops->send_intr(mdev, db); | ||
147 | mic_set_state(mdev, MIC_SHUTTING_DOWN); | ||
148 | } | ||
149 | mutex_unlock(&mdev->mic_mutex); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * mic_shutdown_work - Handle shutdown interrupt from MIC. | ||
154 | * @work: The work structure. | ||
155 | * | ||
156 | * This work is scheduled whenever the host has received a shutdown | ||
157 | * interrupt from the MIC. | ||
158 | */ | ||
159 | void mic_shutdown_work(struct work_struct *work) | ||
160 | { | ||
161 | struct mic_device *mdev = container_of(work, struct mic_device, | ||
162 | shutdown_work); | ||
163 | struct mic_bootparam *bootparam = mdev->dp; | ||
164 | |||
165 | mutex_lock(&mdev->mic_mutex); | ||
166 | mic_set_shutdown_status(mdev, bootparam->shutdown_status); | ||
167 | bootparam->shutdown_status = 0; | ||
168 | if (MIC_SHUTTING_DOWN != mdev->state) | ||
169 | mic_set_state(mdev, MIC_SHUTTING_DOWN); | ||
170 | mutex_unlock(&mdev->mic_mutex); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * mic_reset_trigger_work - Trigger MIC reset. | ||
175 | * @work: The work structure. | ||
176 | * | ||
177 | * This work is scheduled whenever the host wants to reset the MIC. | ||
178 | */ | ||
179 | void mic_reset_trigger_work(struct work_struct *work) | ||
180 | { | ||
181 | struct mic_device *mdev = container_of(work, struct mic_device, | ||
182 | reset_trigger_work); | ||
183 | |||
184 | mic_stop(mdev, false); | ||
185 | } | ||
diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c new file mode 100644 index 000000000000..e22fb7bbbb98 --- /dev/null +++ b/drivers/misc/mic/host/mic_debugfs.c | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/debugfs.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/seq_file.h> | ||
24 | |||
25 | #include <linux/mic_common.h> | ||
26 | #include "../common/mic_device.h" | ||
27 | #include "mic_device.h" | ||
28 | #include "mic_smpt.h" | ||
29 | #include "mic_virtio.h" | ||
30 | |||
31 | /* Debugfs parent dir */ | ||
32 | static struct dentry *mic_dbg; | ||
33 | |||
34 | /** | ||
35 | * mic_log_buf_show - Display MIC kernel log buffer. | ||
36 | * | ||
37 | * log_buf addr/len is read from System.map by user space | ||
38 | * and populated in sysfs entries. | ||
39 | */ | ||
40 | static int mic_log_buf_show(struct seq_file *s, void *unused) | ||
41 | { | ||
42 | void __iomem *log_buf_va; | ||
43 | int __iomem *log_buf_len_va; | ||
44 | struct mic_device *mdev = s->private; | ||
45 | void *kva; | ||
46 | int size; | ||
47 | unsigned long aper_offset; | ||
48 | |||
49 | if (!mdev || !mdev->log_buf_addr || !mdev->log_buf_len) | ||
50 | goto done; | ||
51 | /* | ||
52 | * Card kernel will never be relocated and any kernel text/data mapping | ||
53 | * can be translated to phys address by subtracting __START_KERNEL_map. | ||
54 | */ | ||
55 | aper_offset = (unsigned long)mdev->log_buf_len - __START_KERNEL_map; | ||
56 | log_buf_len_va = mdev->aper.va + aper_offset; | ||
57 | aper_offset = (unsigned long)mdev->log_buf_addr - __START_KERNEL_map; | ||
58 | log_buf_va = mdev->aper.va + aper_offset; | ||
59 | size = ioread32(log_buf_len_va); | ||
60 | |||
61 | kva = kmalloc(size, GFP_KERNEL); | ||
62 | if (!kva) | ||
63 | goto done; | ||
64 | mutex_lock(&mdev->mic_mutex); | ||
65 | memcpy_fromio(kva, log_buf_va, size); | ||
66 | switch (mdev->state) { | ||
67 | case MIC_ONLINE: | ||
68 | /* Fall through */ | ||
69 | case MIC_SHUTTING_DOWN: | ||
70 | seq_write(s, kva, size); | ||
71 | break; | ||
72 | default: | ||
73 | break; | ||
74 | } | ||
75 | mutex_unlock(&mdev->mic_mutex); | ||
76 | kfree(kva); | ||
77 | done: | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int mic_log_buf_open(struct inode *inode, struct file *file) | ||
82 | { | ||
83 | return single_open(file, mic_log_buf_show, inode->i_private); | ||
84 | } | ||
85 | |||
86 | static int mic_log_buf_release(struct inode *inode, struct file *file) | ||
87 | { | ||
88 | return single_release(inode, file); | ||
89 | } | ||
90 | |||
91 | static const struct file_operations log_buf_ops = { | ||
92 | .owner = THIS_MODULE, | ||
93 | .open = mic_log_buf_open, | ||
94 | .read = seq_read, | ||
95 | .llseek = seq_lseek, | ||
96 | .release = mic_log_buf_release | ||
97 | }; | ||
98 | |||
99 | static int mic_smpt_show(struct seq_file *s, void *pos) | ||
100 | { | ||
101 | int i; | ||
102 | struct mic_device *mdev = s->private; | ||
103 | unsigned long flags; | ||
104 | |||
105 | seq_printf(s, "MIC %-2d |%-10s| %-14s %-10s\n", | ||
106 | mdev->id, "SMPT entry", "SW DMA addr", "RefCount"); | ||
107 | seq_puts(s, "====================================================\n"); | ||
108 | |||
109 | if (mdev->smpt) { | ||
110 | struct mic_smpt_info *smpt_info = mdev->smpt; | ||
111 | spin_lock_irqsave(&smpt_info->smpt_lock, flags); | ||
112 | for (i = 0; i < smpt_info->info.num_reg; i++) { | ||
113 | seq_printf(s, "%9s|%-10d| %-#14llx %-10lld\n", | ||
114 | " ", i, smpt_info->entry[i].dma_addr, | ||
115 | smpt_info->entry[i].ref_count); | ||
116 | } | ||
117 | spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); | ||
118 | } | ||
119 | seq_puts(s, "====================================================\n"); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int mic_smpt_debug_open(struct inode *inode, struct file *file) | ||
124 | { | ||
125 | return single_open(file, mic_smpt_show, inode->i_private); | ||
126 | } | ||
127 | |||
128 | static int mic_smpt_debug_release(struct inode *inode, struct file *file) | ||
129 | { | ||
130 | return single_release(inode, file); | ||
131 | } | ||
132 | |||
133 | static const struct file_operations smpt_file_ops = { | ||
134 | .owner = THIS_MODULE, | ||
135 | .open = mic_smpt_debug_open, | ||
136 | .read = seq_read, | ||
137 | .llseek = seq_lseek, | ||
138 | .release = mic_smpt_debug_release | ||
139 | }; | ||
140 | |||
141 | static int mic_soft_reset_show(struct seq_file *s, void *pos) | ||
142 | { | ||
143 | struct mic_device *mdev = s->private; | ||
144 | |||
145 | mic_stop(mdev, true); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int mic_soft_reset_debug_open(struct inode *inode, struct file *file) | ||
150 | { | ||
151 | return single_open(file, mic_soft_reset_show, inode->i_private); | ||
152 | } | ||
153 | |||
154 | static int mic_soft_reset_debug_release(struct inode *inode, struct file *file) | ||
155 | { | ||
156 | return single_release(inode, file); | ||
157 | } | ||
158 | |||
159 | static const struct file_operations soft_reset_ops = { | ||
160 | .owner = THIS_MODULE, | ||
161 | .open = mic_soft_reset_debug_open, | ||
162 | .read = seq_read, | ||
163 | .llseek = seq_lseek, | ||
164 | .release = mic_soft_reset_debug_release | ||
165 | }; | ||
166 | |||
167 | static int mic_post_code_show(struct seq_file *s, void *pos) | ||
168 | { | ||
169 | struct mic_device *mdev = s->private; | ||
170 | u32 reg = mdev->ops->get_postcode(mdev); | ||
171 | |||
172 | seq_printf(s, "%c%c", reg & 0xff, (reg >> 8) & 0xff); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int mic_post_code_debug_open(struct inode *inode, struct file *file) | ||
177 | { | ||
178 | return single_open(file, mic_post_code_show, inode->i_private); | ||
179 | } | ||
180 | |||
181 | static int mic_post_code_debug_release(struct inode *inode, struct file *file) | ||
182 | { | ||
183 | return single_release(inode, file); | ||
184 | } | ||
185 | |||
186 | static const struct file_operations post_code_ops = { | ||
187 | .owner = THIS_MODULE, | ||
188 | .open = mic_post_code_debug_open, | ||
189 | .read = seq_read, | ||
190 | .llseek = seq_lseek, | ||
191 | .release = mic_post_code_debug_release | ||
192 | }; | ||
193 | |||
194 | static int mic_dp_show(struct seq_file *s, void *pos) | ||
195 | { | ||
196 | struct mic_device *mdev = s->private; | ||
197 | struct mic_device_desc *d; | ||
198 | struct mic_device_ctrl *dc; | ||
199 | struct mic_vqconfig *vqconfig; | ||
200 | __u32 *features; | ||
201 | __u8 *config; | ||
202 | struct mic_bootparam *bootparam = mdev->dp; | ||
203 | int i, j; | ||
204 | |||
205 | seq_printf(s, "Bootparam: magic 0x%x\n", | ||
206 | bootparam->magic); | ||
207 | seq_printf(s, "Bootparam: h2c_shutdown_db %d\n", | ||
208 | bootparam->h2c_shutdown_db); | ||
209 | seq_printf(s, "Bootparam: h2c_config_db %d\n", | ||
210 | bootparam->h2c_config_db); | ||
211 | seq_printf(s, "Bootparam: c2h_shutdown_db %d\n", | ||
212 | bootparam->c2h_shutdown_db); | ||
213 | seq_printf(s, "Bootparam: shutdown_status %d\n", | ||
214 | bootparam->shutdown_status); | ||
215 | seq_printf(s, "Bootparam: shutdown_card %d\n", | ||
216 | bootparam->shutdown_card); | ||
217 | |||
218 | for (i = sizeof(*bootparam); i < MIC_DP_SIZE; | ||
219 | i += mic_total_desc_size(d)) { | ||
220 | d = mdev->dp + i; | ||
221 | dc = (void *)d + mic_aligned_desc_size(d); | ||
222 | |||
223 | /* end of list */ | ||
224 | if (d->type == 0) | ||
225 | break; | ||
226 | |||
227 | if (d->type == -1) | ||
228 | continue; | ||
229 | |||
230 | seq_printf(s, "Type %d ", d->type); | ||
231 | seq_printf(s, "Num VQ %d ", d->num_vq); | ||
232 | seq_printf(s, "Feature Len %d\n", d->feature_len); | ||
233 | seq_printf(s, "Config Len %d ", d->config_len); | ||
234 | seq_printf(s, "Shutdown Status %d\n", d->status); | ||
235 | |||
236 | for (j = 0; j < d->num_vq; j++) { | ||
237 | vqconfig = mic_vq_config(d) + j; | ||
238 | seq_printf(s, "vqconfig[%d]: ", j); | ||
239 | seq_printf(s, "address 0x%llx ", vqconfig->address); | ||
240 | seq_printf(s, "num %d ", vqconfig->num); | ||
241 | seq_printf(s, "used address 0x%llx\n", | ||
242 | vqconfig->used_address); | ||
243 | } | ||
244 | |||
245 | features = (__u32 *) mic_vq_features(d); | ||
246 | seq_printf(s, "Features: Host 0x%x ", features[0]); | ||
247 | seq_printf(s, "Guest 0x%x\n", features[1]); | ||
248 | |||
249 | config = mic_vq_configspace(d); | ||
250 | for (j = 0; j < d->config_len; j++) | ||
251 | seq_printf(s, "config[%d]=%d\n", j, config[j]); | ||
252 | |||
253 | seq_puts(s, "Device control:\n"); | ||
254 | seq_printf(s, "Config Change %d ", dc->config_change); | ||
255 | seq_printf(s, "Vdev reset %d\n", dc->vdev_reset); | ||
256 | seq_printf(s, "Guest Ack %d ", dc->guest_ack); | ||
257 | seq_printf(s, "Host ack %d\n", dc->host_ack); | ||
258 | seq_printf(s, "Used address updated %d ", | ||
259 | dc->used_address_updated); | ||
260 | seq_printf(s, "Vdev 0x%llx\n", dc->vdev); | ||
261 | seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db); | ||
262 | seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db); | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int mic_dp_debug_open(struct inode *inode, struct file *file) | ||
269 | { | ||
270 | return single_open(file, mic_dp_show, inode->i_private); | ||
271 | } | ||
272 | |||
273 | static int mic_dp_debug_release(struct inode *inode, struct file *file) | ||
274 | { | ||
275 | return single_release(inode, file); | ||
276 | } | ||
277 | |||
278 | static const struct file_operations dp_ops = { | ||
279 | .owner = THIS_MODULE, | ||
280 | .open = mic_dp_debug_open, | ||
281 | .read = seq_read, | ||
282 | .llseek = seq_lseek, | ||
283 | .release = mic_dp_debug_release | ||
284 | }; | ||
285 | |||
286 | static int mic_vdev_info_show(struct seq_file *s, void *unused) | ||
287 | { | ||
288 | struct mic_device *mdev = s->private; | ||
289 | struct list_head *pos, *tmp; | ||
290 | struct mic_vdev *mvdev; | ||
291 | int i, j; | ||
292 | |||
293 | mutex_lock(&mdev->mic_mutex); | ||
294 | list_for_each_safe(pos, tmp, &mdev->vdev_list) { | ||
295 | mvdev = list_entry(pos, struct mic_vdev, list); | ||
296 | seq_printf(s, "VDEV type %d state %s in %ld out %ld\n", | ||
297 | mvdev->virtio_id, | ||
298 | mic_vdevup(mvdev) ? "UP" : "DOWN", | ||
299 | mvdev->in_bytes, | ||
300 | mvdev->out_bytes); | ||
301 | for (i = 0; i < MIC_MAX_VRINGS; i++) { | ||
302 | struct vring_desc *desc; | ||
303 | struct vring_avail *avail; | ||
304 | struct vring_used *used; | ||
305 | struct mic_vringh *mvr = &mvdev->mvr[i]; | ||
306 | struct vringh *vrh = &mvr->vrh; | ||
307 | int num = vrh->vring.num; | ||
308 | if (!num) | ||
309 | continue; | ||
310 | desc = vrh->vring.desc; | ||
311 | seq_printf(s, "vring i %d avail_idx %d", | ||
312 | i, mvr->vring.info->avail_idx & (num - 1)); | ||
313 | seq_printf(s, " vring i %d avail_idx %d\n", | ||
314 | i, mvr->vring.info->avail_idx); | ||
315 | seq_printf(s, "vrh i %d weak_barriers %d", | ||
316 | i, vrh->weak_barriers); | ||
317 | seq_printf(s, " last_avail_idx %d last_used_idx %d", | ||
318 | vrh->last_avail_idx, vrh->last_used_idx); | ||
319 | seq_printf(s, " completed %d\n", vrh->completed); | ||
320 | for (j = 0; j < num; j++) { | ||
321 | seq_printf(s, "desc[%d] addr 0x%llx len %d", | ||
322 | j, desc->addr, desc->len); | ||
323 | seq_printf(s, " flags 0x%x next %d\n", | ||
324 | desc->flags, | ||
325 | desc->next); | ||
326 | desc++; | ||
327 | } | ||
328 | avail = vrh->vring.avail; | ||
329 | seq_printf(s, "avail flags 0x%x idx %d\n", | ||
330 | avail->flags, avail->idx & (num - 1)); | ||
331 | seq_printf(s, "avail flags 0x%x idx %d\n", | ||
332 | avail->flags, avail->idx); | ||
333 | for (j = 0; j < num; j++) | ||
334 | seq_printf(s, "avail ring[%d] %d\n", | ||
335 | j, avail->ring[j]); | ||
336 | used = vrh->vring.used; | ||
337 | seq_printf(s, "used flags 0x%x idx %d\n", | ||
338 | used->flags, used->idx & (num - 1)); | ||
339 | seq_printf(s, "used flags 0x%x idx %d\n", | ||
340 | used->flags, used->idx); | ||
341 | for (j = 0; j < num; j++) | ||
342 | seq_printf(s, "used ring[%d] id %d len %d\n", | ||
343 | j, used->ring[j].id, used->ring[j].len); | ||
344 | } | ||
345 | } | ||
346 | mutex_unlock(&mdev->mic_mutex); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int mic_vdev_info_debug_open(struct inode *inode, struct file *file) | ||
352 | { | ||
353 | return single_open(file, mic_vdev_info_show, inode->i_private); | ||
354 | } | ||
355 | |||
356 | static int mic_vdev_info_debug_release(struct inode *inode, struct file *file) | ||
357 | { | ||
358 | return single_release(inode, file); | ||
359 | } | ||
360 | |||
361 | static const struct file_operations vdev_info_ops = { | ||
362 | .owner = THIS_MODULE, | ||
363 | .open = mic_vdev_info_debug_open, | ||
364 | .read = seq_read, | ||
365 | .llseek = seq_lseek, | ||
366 | .release = mic_vdev_info_debug_release | ||
367 | }; | ||
368 | |||
369 | static int mic_msi_irq_info_show(struct seq_file *s, void *pos) | ||
370 | { | ||
371 | struct mic_device *mdev = s->private; | ||
372 | int reg; | ||
373 | int i, j; | ||
374 | u16 entry; | ||
375 | u16 vector; | ||
376 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
377 | struct pci_dev, dev); | ||
378 | |||
379 | if (pci_dev_msi_enabled(pdev)) { | ||
380 | for (i = 0; i < mdev->irq_info.num_vectors; i++) { | ||
381 | if (pdev->msix_enabled) { | ||
382 | entry = mdev->irq_info.msix_entries[i].entry; | ||
383 | vector = mdev->irq_info.msix_entries[i].vector; | ||
384 | } else { | ||
385 | entry = 0; | ||
386 | vector = pdev->irq; | ||
387 | } | ||
388 | |||
389 | reg = mdev->intr_ops->read_msi_to_src_map(mdev, entry); | ||
390 | |||
391 | seq_printf(s, "%s %-10d %s %-10d MXAR[%d]: %08X\n", | ||
392 | "IRQ:", vector, "Entry:", entry, i, reg); | ||
393 | |||
394 | seq_printf(s, "%-10s", "offset:"); | ||
395 | for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--) | ||
396 | seq_printf(s, "%4d ", j); | ||
397 | seq_puts(s, "\n"); | ||
398 | |||
399 | |||
400 | seq_printf(s, "%-10s", "count:"); | ||
401 | for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--) | ||
402 | seq_printf(s, "%4d ", | ||
403 | (mdev->irq_info.mic_msi_map[i] & BIT(j)) ? | ||
404 | 1 : 0); | ||
405 | seq_puts(s, "\n\n"); | ||
406 | } | ||
407 | } else { | ||
408 | seq_puts(s, "MSI/MSIx interrupts not enabled\n"); | ||
409 | } | ||
410 | |||
411 | return 0; | ||
412 | |||
413 | } | ||
414 | |||
415 | static int mic_msi_irq_info_debug_open(struct inode *inode, struct file *file) | ||
416 | { | ||
417 | return single_open(file, mic_msi_irq_info_show, inode->i_private); | ||
418 | } | ||
419 | |||
420 | static int | ||
421 | mic_msi_irq_info_debug_release(struct inode *inode, struct file *file) | ||
422 | { | ||
423 | return single_release(inode, file); | ||
424 | } | ||
425 | |||
426 | static const struct file_operations msi_irq_info_ops = { | ||
427 | .owner = THIS_MODULE, | ||
428 | .open = mic_msi_irq_info_debug_open, | ||
429 | .read = seq_read, | ||
430 | .llseek = seq_lseek, | ||
431 | .release = mic_msi_irq_info_debug_release | ||
432 | }; | ||
433 | |||
434 | /** | ||
435 | * mic_create_debug_dir - Initialize MIC debugfs entries. | ||
436 | */ | ||
437 | void mic_create_debug_dir(struct mic_device *mdev) | ||
438 | { | ||
439 | if (!mic_dbg) | ||
440 | return; | ||
441 | |||
442 | mdev->dbg_dir = debugfs_create_dir(dev_name(mdev->sdev), mic_dbg); | ||
443 | if (!mdev->dbg_dir) | ||
444 | return; | ||
445 | |||
446 | debugfs_create_file("log_buf", 0444, mdev->dbg_dir, | ||
447 | mdev, &log_buf_ops); | ||
448 | |||
449 | debugfs_create_file("smpt", 0444, mdev->dbg_dir, | ||
450 | mdev, &smpt_file_ops); | ||
451 | |||
452 | debugfs_create_file("soft_reset", 0444, mdev->dbg_dir, | ||
453 | mdev, &soft_reset_ops); | ||
454 | |||
455 | debugfs_create_file("post_code", 0444, mdev->dbg_dir, | ||
456 | mdev, &post_code_ops); | ||
457 | |||
458 | debugfs_create_file("dp", 0444, mdev->dbg_dir, | ||
459 | mdev, &dp_ops); | ||
460 | |||
461 | debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, | ||
462 | mdev, &vdev_info_ops); | ||
463 | |||
464 | debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, | ||
465 | mdev, &msi_irq_info_ops); | ||
466 | } | ||
467 | |||
468 | /** | ||
469 | * mic_delete_debug_dir - Uninitialize MIC debugfs entries. | ||
470 | */ | ||
471 | void mic_delete_debug_dir(struct mic_device *mdev) | ||
472 | { | ||
473 | if (!mdev->dbg_dir) | ||
474 | return; | ||
475 | |||
476 | debugfs_remove_recursive(mdev->dbg_dir); | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * mic_init_debugfs - Initialize global debugfs entry. | ||
481 | */ | ||
482 | void __init mic_init_debugfs(void) | ||
483 | { | ||
484 | mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
485 | if (!mic_dbg) | ||
486 | pr_err("can't create debugfs dir\n"); | ||
487 | } | ||
488 | |||
489 | /** | ||
490 | * mic_exit_debugfs - Uninitialize global debugfs entry | ||
491 | */ | ||
492 | void mic_exit_debugfs(void) | ||
493 | { | ||
494 | debugfs_remove(mic_dbg); | ||
495 | } | ||
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h new file mode 100644 index 000000000000..dcba2a59e77f --- /dev/null +++ b/drivers/misc/mic/host/mic_device.h | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #ifndef _MIC_DEVICE_H_ | ||
22 | #define _MIC_DEVICE_H_ | ||
23 | |||
24 | #include <linux/cdev.h> | ||
25 | #include <linux/idr.h> | ||
26 | |||
27 | #include "mic_intr.h" | ||
28 | |||
29 | /* The maximum number of MIC devices supported in a single host system. */ | ||
30 | #define MIC_MAX_NUM_DEVS 256 | ||
31 | |||
32 | /** | ||
33 | * enum mic_hw_family - The hardware family to which a device belongs. | ||
34 | */ | ||
35 | enum mic_hw_family { | ||
36 | MIC_FAMILY_X100 = 0, | ||
37 | MIC_FAMILY_UNKNOWN | ||
38 | }; | ||
39 | |||
40 | /** | ||
41 | * enum mic_stepping - MIC stepping ids. | ||
42 | */ | ||
43 | enum mic_stepping { | ||
44 | MIC_A0_STEP = 0x0, | ||
45 | MIC_B0_STEP = 0x10, | ||
46 | MIC_B1_STEP = 0x11, | ||
47 | MIC_C0_STEP = 0x20, | ||
48 | }; | ||
49 | |||
50 | /** | ||
51 | * struct mic_device - MIC device information for each card. | ||
52 | * | ||
53 | * @mmio: MMIO bar information. | ||
54 | * @aper: Aperture bar information. | ||
55 | * @family: The MIC family to which this device belongs. | ||
56 | * @ops: MIC HW specific operations. | ||
57 | * @id: The unique device id for this MIC device. | ||
58 | * @stepping: Stepping ID. | ||
59 | * @attr_group: Pointer to list of sysfs attribute groups. | ||
60 | * @sdev: Device for sysfs entries. | ||
61 | * @mic_mutex: Mutex for synchronizing access to mic_device. | ||
62 | * @intr_ops: HW specific interrupt operations. | ||
63 | * @smpt_ops: Hardware specific SMPT operations. | ||
64 | * @smpt: MIC SMPT information. | ||
65 | * @intr_info: H/W specific interrupt information. | ||
66 | * @irq_info: The OS specific irq information | ||
67 | * @dbg_dir: debugfs directory of this MIC device. | ||
68 | * @cmdline: Kernel command line. | ||
69 | * @firmware: Firmware file name. | ||
70 | * @ramdisk: Ramdisk file name. | ||
71 | * @bootmode: Boot mode i.e. "linux" or "elf" for flash updates. | ||
72 | * @bootaddr: MIC boot address. | ||
73 | * @reset_trigger_work: Work for triggering reset requests. | ||
74 | * @shutdown_work: Work for handling shutdown interrupts. | ||
75 | * @state: MIC state. | ||
76 | * @shutdown_status: MIC status reported by card for shutdown/crashes. | ||
77 | * @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes. | ||
78 | * @log_buf_addr: Log buffer address for MIC. | ||
79 | * @log_buf_len: Log buffer length address for MIC. | ||
80 | * @dp: virtio device page | ||
81 | * @dp_dma_addr: virtio device page DMA address. | ||
82 | * @shutdown_db: shutdown doorbell. | ||
83 | * @shutdown_cookie: shutdown cookie. | ||
84 | * @cdev: Character device for MIC. | ||
85 | * @vdev_list: list of virtio devices. | ||
86 | */ | ||
87 | struct mic_device { | ||
88 | struct mic_mw mmio; | ||
89 | struct mic_mw aper; | ||
90 | enum mic_hw_family family; | ||
91 | struct mic_hw_ops *ops; | ||
92 | int id; | ||
93 | enum mic_stepping stepping; | ||
94 | const struct attribute_group **attr_group; | ||
95 | struct device *sdev; | ||
96 | struct mutex mic_mutex; | ||
97 | struct mic_hw_intr_ops *intr_ops; | ||
98 | struct mic_smpt_ops *smpt_ops; | ||
99 | struct mic_smpt_info *smpt; | ||
100 | struct mic_intr_info *intr_info; | ||
101 | struct mic_irq_info irq_info; | ||
102 | struct dentry *dbg_dir; | ||
103 | char *cmdline; | ||
104 | char *firmware; | ||
105 | char *ramdisk; | ||
106 | char *bootmode; | ||
107 | u32 bootaddr; | ||
108 | struct work_struct reset_trigger_work; | ||
109 | struct work_struct shutdown_work; | ||
110 | u8 state; | ||
111 | u8 shutdown_status; | ||
112 | struct sysfs_dirent *state_sysfs; | ||
113 | void *log_buf_addr; | ||
114 | int *log_buf_len; | ||
115 | void *dp; | ||
116 | dma_addr_t dp_dma_addr; | ||
117 | int shutdown_db; | ||
118 | struct mic_irq *shutdown_cookie; | ||
119 | struct cdev cdev; | ||
120 | struct list_head vdev_list; | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * struct mic_hw_ops - MIC HW specific operations. | ||
125 | * @aper_bar: Aperture bar resource number. | ||
126 | * @mmio_bar: MMIO bar resource number. | ||
127 | * @read_spad: Read from scratch pad register. | ||
128 | * @write_spad: Write to scratch pad register. | ||
129 | * @send_intr: Send an interrupt for a particular doorbell on the card. | ||
130 | * @ack_interrupt: Hardware specific operations to ack the h/w on | ||
131 | * receipt of an interrupt. | ||
132 | * @reset: Reset the remote processor. | ||
133 | * @reset_fw_ready: Reset firmware ready field. | ||
134 | * @is_fw_ready: Check if firmware is ready for OS download. | ||
135 | * @send_firmware_intr: Send an interrupt to the card firmware. | ||
136 | * @load_mic_fw: Load firmware segments required to boot the card | ||
137 | * into card memory. This includes the kernel, command line, ramdisk etc. | ||
138 | * @get_postcode: Get post code status from firmware. | ||
139 | */ | ||
140 | struct mic_hw_ops { | ||
141 | u8 aper_bar; | ||
142 | u8 mmio_bar; | ||
143 | u32 (*read_spad)(struct mic_device *mdev, unsigned int idx); | ||
144 | void (*write_spad)(struct mic_device *mdev, unsigned int idx, u32 val); | ||
145 | void (*send_intr)(struct mic_device *mdev, int doorbell); | ||
146 | u32 (*ack_interrupt)(struct mic_device *mdev); | ||
147 | void (*reset)(struct mic_device *mdev); | ||
148 | void (*reset_fw_ready)(struct mic_device *mdev); | ||
149 | bool (*is_fw_ready)(struct mic_device *mdev); | ||
150 | void (*send_firmware_intr)(struct mic_device *mdev); | ||
151 | int (*load_mic_fw)(struct mic_device *mdev, const char *buf); | ||
152 | u32 (*get_postcode)(struct mic_device *mdev); | ||
153 | }; | ||
154 | |||
155 | /** | ||
156 | * mic_mmio_read - read from an MMIO register. | ||
157 | * @mw: MMIO register base virtual address. | ||
158 | * @offset: register offset. | ||
159 | * | ||
160 | * RETURNS: register value. | ||
161 | */ | ||
162 | static inline u32 mic_mmio_read(struct mic_mw *mw, u32 offset) | ||
163 | { | ||
164 | return ioread32(mw->va + offset); | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * mic_mmio_write - write to an MMIO register. | ||
169 | * @mw: MMIO register base virtual address. | ||
170 | * @val: the data value to put into the register | ||
171 | * @offset: register offset. | ||
172 | * | ||
173 | * RETURNS: none. | ||
174 | */ | ||
175 | static inline void | ||
176 | mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) | ||
177 | { | ||
178 | iowrite32(val, mw->va + offset); | ||
179 | } | ||
180 | |||
181 | void mic_sysfs_init(struct mic_device *mdev); | ||
182 | int mic_start(struct mic_device *mdev, const char *buf); | ||
183 | void mic_stop(struct mic_device *mdev, bool force); | ||
184 | void mic_shutdown(struct mic_device *mdev); | ||
185 | void mic_reset_delayed_work(struct work_struct *work); | ||
186 | void mic_reset_trigger_work(struct work_struct *work); | ||
187 | void mic_shutdown_work(struct work_struct *work); | ||
188 | void mic_bootparam_init(struct mic_device *mdev); | ||
189 | void mic_set_state(struct mic_device *mdev, u8 state); | ||
190 | void mic_set_shutdown_status(struct mic_device *mdev, u8 status); | ||
191 | void mic_create_debug_dir(struct mic_device *dev); | ||
192 | void mic_delete_debug_dir(struct mic_device *dev); | ||
193 | void __init mic_init_debugfs(void); | ||
194 | void mic_exit_debugfs(void); | ||
195 | #endif | ||
diff --git a/drivers/misc/mic/host/mic_fops.c b/drivers/misc/mic/host/mic_fops.c new file mode 100644 index 000000000000..661469ad339d --- /dev/null +++ b/drivers/misc/mic/host/mic_fops.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/poll.h> | ||
22 | |||
23 | #include <linux/mic_common.h> | ||
24 | #include "../common/mic_device.h" | ||
25 | #include "mic_device.h" | ||
26 | #include "mic_fops.h" | ||
27 | #include "mic_virtio.h" | ||
28 | |||
29 | int mic_open(struct inode *inode, struct file *f) | ||
30 | { | ||
31 | struct mic_vdev *mvdev; | ||
32 | struct mic_device *mdev = container_of(inode->i_cdev, | ||
33 | struct mic_device, cdev); | ||
34 | |||
35 | mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL); | ||
36 | if (!mvdev) | ||
37 | return -ENOMEM; | ||
38 | |||
39 | init_waitqueue_head(&mvdev->waitq); | ||
40 | INIT_LIST_HEAD(&mvdev->list); | ||
41 | mvdev->mdev = mdev; | ||
42 | mvdev->virtio_id = -1; | ||
43 | |||
44 | f->private_data = mvdev; | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | int mic_release(struct inode *inode, struct file *f) | ||
49 | { | ||
50 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
51 | |||
52 | if (-1 != mvdev->virtio_id) | ||
53 | mic_virtio_del_device(mvdev); | ||
54 | f->private_data = NULL; | ||
55 | kfree(mvdev); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | long mic_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | ||
60 | { | ||
61 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
62 | void __user *argp = (void __user *)arg; | ||
63 | int ret; | ||
64 | |||
65 | switch (cmd) { | ||
66 | case MIC_VIRTIO_ADD_DEVICE: | ||
67 | { | ||
68 | ret = mic_virtio_add_device(mvdev, argp); | ||
69 | if (ret < 0) { | ||
70 | dev_err(mic_dev(mvdev), | ||
71 | "%s %d errno ret %d\n", | ||
72 | __func__, __LINE__, ret); | ||
73 | return ret; | ||
74 | } | ||
75 | break; | ||
76 | } | ||
77 | case MIC_VIRTIO_COPY_DESC: | ||
78 | { | ||
79 | struct mic_copy_desc copy; | ||
80 | |||
81 | ret = mic_vdev_inited(mvdev); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | |||
85 | if (copy_from_user(©, argp, sizeof(copy))) | ||
86 | return -EFAULT; | ||
87 | |||
88 | dev_dbg(mic_dev(mvdev), | ||
89 | "%s %d === iovcnt 0x%x vr_idx 0x%x update_used %d\n", | ||
90 | __func__, __LINE__, copy.iovcnt, copy.vr_idx, | ||
91 | copy.update_used); | ||
92 | |||
93 | ret = mic_virtio_copy_desc(mvdev, ©); | ||
94 | if (ret < 0) { | ||
95 | dev_err(mic_dev(mvdev), | ||
96 | "%s %d errno ret %d\n", | ||
97 | __func__, __LINE__, ret); | ||
98 | return ret; | ||
99 | } | ||
100 | if (copy_to_user( | ||
101 | &((struct mic_copy_desc __user *)argp)->out_len, | ||
102 | ©.out_len, sizeof(copy.out_len))) { | ||
103 | dev_err(mic_dev(mvdev), "%s %d errno ret %d\n", | ||
104 | __func__, __LINE__, -EFAULT); | ||
105 | return -EFAULT; | ||
106 | } | ||
107 | break; | ||
108 | } | ||
109 | case MIC_VIRTIO_CONFIG_CHANGE: | ||
110 | { | ||
111 | ret = mic_vdev_inited(mvdev); | ||
112 | if (ret) | ||
113 | return ret; | ||
114 | |||
115 | ret = mic_virtio_config_change(mvdev, argp); | ||
116 | if (ret < 0) { | ||
117 | dev_err(mic_dev(mvdev), | ||
118 | "%s %d errno ret %d\n", | ||
119 | __func__, __LINE__, ret); | ||
120 | return ret; | ||
121 | } | ||
122 | break; | ||
123 | } | ||
124 | default: | ||
125 | return -ENOIOCTLCMD; | ||
126 | }; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and | ||
132 | * not when previously enqueued buffers may be available. This means that | ||
133 | * in the card->host (TX) path, when userspace is unblocked by poll it | ||
134 | * must drain all available descriptors or it can stall. | ||
135 | */ | ||
136 | unsigned int mic_poll(struct file *f, poll_table *wait) | ||
137 | { | ||
138 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
139 | int mask = 0; | ||
140 | |||
141 | poll_wait(f, &mvdev->waitq, wait); | ||
142 | |||
143 | if (mic_vdev_inited(mvdev)) | ||
144 | mask = POLLERR; | ||
145 | else if (mvdev->poll_wake) { | ||
146 | mvdev->poll_wake = 0; | ||
147 | mask = POLLIN | POLLOUT; | ||
148 | } | ||
149 | |||
150 | return mask; | ||
151 | } | ||
152 | |||
153 | static inline int | ||
154 | mic_query_offset(struct mic_vdev *mvdev, unsigned long offset, | ||
155 | unsigned long *size, unsigned long *pa) | ||
156 | { | ||
157 | struct mic_device *mdev = mvdev->mdev; | ||
158 | unsigned long start = MIC_DP_SIZE; | ||
159 | int i; | ||
160 | |||
161 | /* | ||
162 | * MMAP interface is as follows: | ||
163 | * offset region | ||
164 | * 0x0 virtio device_page | ||
165 | * 0x1000 first vring | ||
166 | * 0x1000 + size of 1st vring second vring | ||
167 | * .... | ||
168 | */ | ||
169 | if (!offset) { | ||
170 | *pa = virt_to_phys(mdev->dp); | ||
171 | *size = MIC_DP_SIZE; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
176 | struct mic_vringh *mvr = &mvdev->mvr[i]; | ||
177 | if (offset == start) { | ||
178 | *pa = virt_to_phys(mvr->vring.va); | ||
179 | *size = mvr->vring.len; | ||
180 | return 0; | ||
181 | } | ||
182 | start += mvr->vring.len; | ||
183 | } | ||
184 | return -1; | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * Maps the device page and virtio rings to user space for readonly access. | ||
189 | */ | ||
190 | int | ||
191 | mic_mmap(struct file *f, struct vm_area_struct *vma) | ||
192 | { | ||
193 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
194 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | ||
195 | unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size; | ||
196 | int i, err; | ||
197 | |||
198 | err = mic_vdev_inited(mvdev); | ||
199 | if (err) | ||
200 | return err; | ||
201 | |||
202 | if (vma->vm_flags & VM_WRITE) | ||
203 | return -EACCES; | ||
204 | |||
205 | while (size_rem) { | ||
206 | i = mic_query_offset(mvdev, offset, &size, &pa); | ||
207 | if (i < 0) | ||
208 | return -EINVAL; | ||
209 | err = remap_pfn_range(vma, vma->vm_start + offset, | ||
210 | pa >> PAGE_SHIFT, size, vma->vm_page_prot); | ||
211 | if (err) | ||
212 | return err; | ||
213 | dev_dbg(mic_dev(mvdev), | ||
214 | "%s %d type %d size 0x%lx off 0x%lx pa 0x%lx vma 0x%lx\n", | ||
215 | __func__, __LINE__, mvdev->virtio_id, size, offset, | ||
216 | pa, vma->vm_start + offset); | ||
217 | size_rem -= size; | ||
218 | offset += size; | ||
219 | } | ||
220 | return 0; | ||
221 | } | ||
diff --git a/drivers/misc/mic/host/mic_fops.h b/drivers/misc/mic/host/mic_fops.h new file mode 100644 index 000000000000..dc3893dff667 --- /dev/null +++ b/drivers/misc/mic/host/mic_fops.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #ifndef _MIC_FOPS_H_ | ||
22 | #define _MIC_FOPS_H_ | ||
23 | |||
24 | int mic_open(struct inode *inode, struct file *filp); | ||
25 | int mic_release(struct inode *inode, struct file *filp); | ||
26 | ssize_t mic_read(struct file *filp, char __user *buf, | ||
27 | size_t count, loff_t *pos); | ||
28 | long mic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | ||
29 | int mic_mmap(struct file *f, struct vm_area_struct *vma); | ||
30 | unsigned int mic_poll(struct file *f, poll_table *wait); | ||
31 | |||
32 | #endif | ||
diff --git a/drivers/misc/mic/host/mic_intr.c b/drivers/misc/mic/host/mic_intr.c new file mode 100644 index 000000000000..cdae3141dbb9 --- /dev/null +++ b/drivers/misc/mic/host/mic_intr.c | |||
@@ -0,0 +1,628 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | |||
24 | #include "../common/mic_device.h" | ||
25 | #include "mic_device.h" | ||
26 | |||
27 | /* | ||
28 | * mic_invoke_callback - Invoke callback functions registered for | ||
29 | * the corresponding source id. | ||
30 | * | ||
31 | * @mdev: pointer to the mic_device instance | ||
32 | * @idx: The interrupt source id. | ||
33 | * | ||
34 | * Returns none. | ||
35 | */ | ||
36 | static inline void mic_invoke_callback(struct mic_device *mdev, int idx) | ||
37 | { | ||
38 | struct mic_intr_cb *intr_cb; | ||
39 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
40 | struct pci_dev, dev); | ||
41 | |||
42 | spin_lock(&mdev->irq_info.mic_intr_lock); | ||
43 | list_for_each_entry(intr_cb, &mdev->irq_info.cb_list[idx], list) | ||
44 | if (intr_cb->func) | ||
45 | intr_cb->func(pdev->irq, intr_cb->data); | ||
46 | spin_unlock(&mdev->irq_info.mic_intr_lock); | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * mic_interrupt - Generic interrupt handler for | ||
51 | * MSI and INTx based interrupts. | ||
52 | */ | ||
53 | static irqreturn_t mic_interrupt(int irq, void *dev) | ||
54 | { | ||
55 | struct mic_device *mdev = dev; | ||
56 | struct mic_intr_info *info = mdev->intr_info; | ||
57 | u32 mask; | ||
58 | int i; | ||
59 | |||
60 | mask = mdev->ops->ack_interrupt(mdev); | ||
61 | if (!mask) | ||
62 | return IRQ_NONE; | ||
63 | |||
64 | for (i = info->intr_start_idx[MIC_INTR_DB]; | ||
65 | i < info->intr_len[MIC_INTR_DB]; i++) | ||
66 | if (mask & BIT(i)) | ||
67 | mic_invoke_callback(mdev, i); | ||
68 | |||
69 | return IRQ_HANDLED; | ||
70 | } | ||
71 | |||
72 | /* Return the interrupt offset from the index. Index is 0 based. */ | ||
73 | static u16 mic_map_src_to_offset(struct mic_device *mdev, | ||
74 | int intr_src, enum mic_intr_type type) { | ||
75 | |||
76 | if (type >= MIC_NUM_INTR_TYPES) | ||
77 | return MIC_NUM_OFFSETS; | ||
78 | if (intr_src >= mdev->intr_info->intr_len[type]) | ||
79 | return MIC_NUM_OFFSETS; | ||
80 | |||
81 | return mdev->intr_info->intr_start_idx[type] + intr_src; | ||
82 | } | ||
83 | |||
84 | /* Return next available msix_entry. */ | ||
85 | static struct msix_entry *mic_get_available_vector(struct mic_device *mdev) | ||
86 | { | ||
87 | int i; | ||
88 | struct mic_irq_info *info = &mdev->irq_info; | ||
89 | |||
90 | for (i = 0; i < info->num_vectors; i++) | ||
91 | if (!info->mic_msi_map[i]) | ||
92 | return &info->msix_entries[i]; | ||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * mic_register_intr_callback - Register a callback handler for the | ||
98 | * given source id. | ||
99 | * | ||
100 | * @mdev: pointer to the mic_device instance | ||
101 | * @idx: The source id to be registered. | ||
102 | * @func: The function to be called when the source id receives | ||
103 | * the interrupt. | ||
104 | * @data: Private data of the requester. | ||
105 | * Return the callback structure that was registered or an | ||
106 | * appropriate error on failure. | ||
107 | */ | ||
108 | static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, | ||
109 | u8 idx, irqreturn_t (*func) (int irq, void *dev), | ||
110 | void *data) | ||
111 | { | ||
112 | struct mic_intr_cb *intr_cb; | ||
113 | unsigned long flags; | ||
114 | int rc; | ||
115 | intr_cb = kmalloc(sizeof(struct mic_intr_cb), GFP_KERNEL); | ||
116 | |||
117 | if (!intr_cb) | ||
118 | return ERR_PTR(-ENOMEM); | ||
119 | |||
120 | intr_cb->func = func; | ||
121 | intr_cb->data = data; | ||
122 | intr_cb->cb_id = ida_simple_get(&mdev->irq_info.cb_ida, | ||
123 | 0, 0, GFP_KERNEL); | ||
124 | if (intr_cb->cb_id < 0) { | ||
125 | rc = intr_cb->cb_id; | ||
126 | goto ida_fail; | ||
127 | } | ||
128 | |||
129 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
130 | list_add_tail(&intr_cb->list, &mdev->irq_info.cb_list[idx]); | ||
131 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
132 | |||
133 | return intr_cb; | ||
134 | ida_fail: | ||
135 | kfree(intr_cb); | ||
136 | return ERR_PTR(rc); | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * mic_unregister_intr_callback - Unregister the callback handler | ||
141 | * identified by its callback id. | ||
142 | * | ||
143 | * @mdev: pointer to the mic_device instance | ||
144 | * @idx: The callback structure id to be unregistered. | ||
145 | * Return the source id that was unregistered or MIC_NUM_OFFSETS if no | ||
146 | * such callback handler was found. | ||
147 | */ | ||
148 | static u8 mic_unregister_intr_callback(struct mic_device *mdev, u32 idx) | ||
149 | { | ||
150 | struct list_head *pos, *tmp; | ||
151 | struct mic_intr_cb *intr_cb; | ||
152 | unsigned long flags; | ||
153 | int i; | ||
154 | |||
155 | for (i = 0; i < MIC_NUM_OFFSETS; i++) { | ||
156 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
157 | list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { | ||
158 | intr_cb = list_entry(pos, struct mic_intr_cb, list); | ||
159 | if (intr_cb->cb_id == idx) { | ||
160 | list_del(pos); | ||
161 | ida_simple_remove(&mdev->irq_info.cb_ida, | ||
162 | intr_cb->cb_id); | ||
163 | kfree(intr_cb); | ||
164 | spin_unlock_irqrestore( | ||
165 | &mdev->irq_info.mic_intr_lock, flags); | ||
166 | return i; | ||
167 | } | ||
168 | } | ||
169 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
170 | } | ||
171 | return MIC_NUM_OFFSETS; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * mic_setup_msix - Initializes MSIx interrupts. | ||
176 | * | ||
177 | * @mdev: pointer to mic_device instance | ||
178 | * | ||
179 | * | ||
180 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
181 | */ | ||
182 | static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev) | ||
183 | { | ||
184 | int rc, i; | ||
185 | |||
186 | mdev->irq_info.msix_entries = kmalloc(sizeof(struct msix_entry) * | ||
187 | MIC_MIN_MSIX, GFP_KERNEL); | ||
188 | if (!mdev->irq_info.msix_entries) { | ||
189 | rc = -ENOMEM; | ||
190 | goto err_nomem1; | ||
191 | } | ||
192 | |||
193 | for (i = 0; i < MIC_MIN_MSIX; i++) | ||
194 | mdev->irq_info.msix_entries[i].entry = i; | ||
195 | |||
196 | rc = pci_enable_msix(pdev, mdev->irq_info.msix_entries, | ||
197 | MIC_MIN_MSIX); | ||
198 | if (rc) { | ||
199 | dev_dbg(&pdev->dev, "Error enabling MSIx. rc = %d\n", rc); | ||
200 | goto err_enable_msix; | ||
201 | } | ||
202 | |||
203 | mdev->irq_info.num_vectors = MIC_MIN_MSIX; | ||
204 | mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) * | ||
205 | mdev->irq_info.num_vectors), GFP_KERNEL); | ||
206 | |||
207 | if (!mdev->irq_info.mic_msi_map) { | ||
208 | rc = -ENOMEM; | ||
209 | goto err_nomem2; | ||
210 | } | ||
211 | |||
212 | dev_dbg(mdev->sdev->parent, | ||
213 | "%d MSIx irqs setup\n", mdev->irq_info.num_vectors); | ||
214 | return 0; | ||
215 | err_nomem2: | ||
216 | pci_disable_msix(pdev); | ||
217 | err_enable_msix: | ||
218 | kfree(mdev->irq_info.msix_entries); | ||
219 | err_nomem1: | ||
220 | mdev->irq_info.num_vectors = 0; | ||
221 | return rc; | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * mic_setup_callbacks - Initialize data structures needed | ||
226 | * to handle callbacks. | ||
227 | * | ||
228 | * @mdev: pointer to mic_device instance | ||
229 | */ | ||
230 | static int mic_setup_callbacks(struct mic_device *mdev) | ||
231 | { | ||
232 | int i; | ||
233 | |||
234 | mdev->irq_info.cb_list = kmalloc(sizeof(struct list_head) * | ||
235 | MIC_NUM_OFFSETS, GFP_KERNEL); | ||
236 | if (!mdev->irq_info.cb_list) | ||
237 | return -ENOMEM; | ||
238 | |||
239 | for (i = 0; i < MIC_NUM_OFFSETS; i++) | ||
240 | INIT_LIST_HEAD(&mdev->irq_info.cb_list[i]); | ||
241 | ida_init(&mdev->irq_info.cb_ida); | ||
242 | spin_lock_init(&mdev->irq_info.mic_intr_lock); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * mic_release_callbacks - Uninitialize data structures needed | ||
248 | * to handle callbacks. | ||
249 | * | ||
250 | * @mdev: pointer to mic_device instance | ||
251 | */ | ||
252 | static void mic_release_callbacks(struct mic_device *mdev) | ||
253 | { | ||
254 | unsigned long flags; | ||
255 | struct list_head *pos, *tmp; | ||
256 | struct mic_intr_cb *intr_cb; | ||
257 | int i; | ||
258 | |||
259 | for (i = 0; i < MIC_NUM_OFFSETS; i++) { | ||
260 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
261 | |||
262 | if (list_empty(&mdev->irq_info.cb_list[i])) { | ||
263 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, | ||
264 | flags); | ||
265 | break; | ||
266 | } | ||
267 | |||
268 | list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { | ||
269 | intr_cb = list_entry(pos, struct mic_intr_cb, list); | ||
270 | list_del(pos); | ||
271 | ida_simple_remove(&mdev->irq_info.cb_ida, | ||
272 | intr_cb->cb_id); | ||
273 | kfree(intr_cb); | ||
274 | } | ||
275 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
276 | } | ||
277 | ida_destroy(&mdev->irq_info.cb_ida); | ||
278 | kfree(mdev->irq_info.cb_list); | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * mic_setup_msi - Initializes MSI interrupts. | ||
283 | * | ||
284 | * @mdev: pointer to mic_device instance | ||
285 | * @pdev: PCI device structure | ||
286 | * | ||
287 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
288 | */ | ||
289 | static int mic_setup_msi(struct mic_device *mdev, struct pci_dev *pdev) | ||
290 | { | ||
291 | int rc; | ||
292 | |||
293 | rc = pci_enable_msi(pdev); | ||
294 | if (rc) { | ||
295 | dev_dbg(&pdev->dev, "Error enabling MSI. rc = %d\n", rc); | ||
296 | return rc; | ||
297 | } | ||
298 | |||
299 | mdev->irq_info.num_vectors = 1; | ||
300 | mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) * | ||
301 | mdev->irq_info.num_vectors), GFP_KERNEL); | ||
302 | |||
303 | if (!mdev->irq_info.mic_msi_map) { | ||
304 | rc = -ENOMEM; | ||
305 | goto err_nomem1; | ||
306 | } | ||
307 | |||
308 | rc = mic_setup_callbacks(mdev); | ||
309 | if (rc) { | ||
310 | dev_err(&pdev->dev, "Error setting up callbacks\n"); | ||
311 | goto err_nomem2; | ||
312 | } | ||
313 | |||
314 | rc = request_irq(pdev->irq, mic_interrupt, 0 , "mic-msi", mdev); | ||
315 | if (rc) { | ||
316 | dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); | ||
317 | goto err_irq_req_fail; | ||
318 | } | ||
319 | |||
320 | dev_dbg(&pdev->dev, "%d MSI irqs setup\n", mdev->irq_info.num_vectors); | ||
321 | return 0; | ||
322 | err_irq_req_fail: | ||
323 | mic_release_callbacks(mdev); | ||
324 | err_nomem2: | ||
325 | kfree(mdev->irq_info.mic_msi_map); | ||
326 | err_nomem1: | ||
327 | pci_disable_msi(pdev); | ||
328 | mdev->irq_info.num_vectors = 0; | ||
329 | return rc; | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * mic_setup_intx - Initializes legacy interrupts. | ||
334 | * | ||
335 | * @mdev: pointer to mic_device instance | ||
336 | * @pdev: PCI device structure | ||
337 | * | ||
338 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
339 | */ | ||
340 | static int mic_setup_intx(struct mic_device *mdev, struct pci_dev *pdev) | ||
341 | { | ||
342 | int rc; | ||
343 | |||
344 | pci_msi_off(pdev); | ||
345 | |||
346 | /* Enable intx */ | ||
347 | pci_intx(pdev, 1); | ||
348 | rc = mic_setup_callbacks(mdev); | ||
349 | if (rc) { | ||
350 | dev_err(&pdev->dev, "Error setting up callbacks\n"); | ||
351 | goto err_nomem; | ||
352 | } | ||
353 | |||
354 | rc = request_irq(pdev->irq, mic_interrupt, | ||
355 | IRQF_SHARED, "mic-intx", mdev); | ||
356 | if (rc) | ||
357 | goto err; | ||
358 | |||
359 | dev_dbg(&pdev->dev, "intx irq setup\n"); | ||
360 | return 0; | ||
361 | err: | ||
362 | mic_release_callbacks(mdev); | ||
363 | err_nomem: | ||
364 | return rc; | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * mic_next_db - Retrieve the next doorbell interrupt source id. | ||
369 | * The id is picked sequentially from the available pool of | ||
370 | * doorlbell ids. | ||
371 | * | ||
372 | * @mdev: pointer to the mic_device instance. | ||
373 | * | ||
374 | * Returns the next doorbell interrupt source. | ||
375 | */ | ||
376 | int mic_next_db(struct mic_device *mdev) | ||
377 | { | ||
378 | int next_db; | ||
379 | |||
380 | next_db = mdev->irq_info.next_avail_src % | ||
381 | mdev->intr_info->intr_len[MIC_INTR_DB]; | ||
382 | mdev->irq_info.next_avail_src++; | ||
383 | return next_db; | ||
384 | } | ||
385 | |||
386 | #define COOKIE_ID_SHIFT 16 | ||
387 | #define GET_ENTRY(cookie) ((cookie) & 0xFFFF) | ||
388 | #define GET_OFFSET(cookie) ((cookie) >> COOKIE_ID_SHIFT) | ||
389 | #define MK_COOKIE(x, y) ((x) | (y) << COOKIE_ID_SHIFT) | ||
390 | |||
391 | /** | ||
392 | * mic_request_irq - request an irq. mic_mutex needs | ||
393 | * to be held before calling this function. | ||
394 | * | ||
395 | * @mdev: pointer to mic_device instance | ||
396 | * @func: The callback function that handles the interrupt. | ||
397 | * The function needs to call ack_interrupts | ||
398 | * (mdev->ops->ack_interrupt(mdev)) when handling the interrupts. | ||
399 | * @name: The ASCII name of the callee requesting the irq. | ||
400 | * @data: private data that is returned back when calling the | ||
401 | * function handler. | ||
402 | * @intr_src: The source id of the requester. Its the doorbell id | ||
403 | * for Doorbell interrupts and DMA channel id for DMA interrupts. | ||
404 | * @type: The type of interrupt. Values defined in mic_intr_type | ||
405 | * | ||
406 | * returns: The cookie that is transparent to the caller. Passed | ||
407 | * back when calling mic_free_irq. An appropriate error code | ||
408 | * is returned on failure. Caller needs to use IS_ERR(return_val) | ||
409 | * to check for failure and PTR_ERR(return_val) to obtained the | ||
410 | * error code. | ||
411 | * | ||
412 | */ | ||
413 | struct mic_irq *mic_request_irq(struct mic_device *mdev, | ||
414 | irqreturn_t (*func)(int irq, void *dev), | ||
415 | const char *name, void *data, int intr_src, | ||
416 | enum mic_intr_type type) | ||
417 | { | ||
418 | u16 offset; | ||
419 | int rc = 0; | ||
420 | struct msix_entry *msix = NULL; | ||
421 | unsigned long cookie = 0; | ||
422 | u16 entry; | ||
423 | struct mic_intr_cb *intr_cb; | ||
424 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
425 | struct pci_dev, dev); | ||
426 | |||
427 | offset = mic_map_src_to_offset(mdev, intr_src, type); | ||
428 | if (offset >= MIC_NUM_OFFSETS) { | ||
429 | dev_err(mdev->sdev->parent, | ||
430 | "Error mapping index %d to a valid source id.\n", | ||
431 | intr_src); | ||
432 | rc = -EINVAL; | ||
433 | goto err; | ||
434 | } | ||
435 | |||
436 | if (mdev->irq_info.num_vectors > 1) { | ||
437 | msix = mic_get_available_vector(mdev); | ||
438 | if (!msix) { | ||
439 | dev_err(mdev->sdev->parent, | ||
440 | "No MSIx vectors available for use.\n"); | ||
441 | rc = -ENOSPC; | ||
442 | goto err; | ||
443 | } | ||
444 | |||
445 | rc = request_irq(msix->vector, func, 0, name, data); | ||
446 | if (rc) { | ||
447 | dev_dbg(mdev->sdev->parent, | ||
448 | "request irq failed rc = %d\n", rc); | ||
449 | goto err; | ||
450 | } | ||
451 | entry = msix->entry; | ||
452 | mdev->irq_info.mic_msi_map[entry] |= BIT(offset); | ||
453 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
454 | entry, offset, true); | ||
455 | cookie = MK_COOKIE(entry, offset); | ||
456 | dev_dbg(mdev->sdev->parent, "irq: %d assigned for src: %d\n", | ||
457 | msix->vector, intr_src); | ||
458 | } else { | ||
459 | intr_cb = mic_register_intr_callback(mdev, | ||
460 | offset, func, data); | ||
461 | if (IS_ERR(intr_cb)) { | ||
462 | dev_err(mdev->sdev->parent, | ||
463 | "No available callback entries for use\n"); | ||
464 | rc = PTR_ERR(intr_cb); | ||
465 | goto err; | ||
466 | } | ||
467 | |||
468 | entry = 0; | ||
469 | if (pci_dev_msi_enabled(pdev)) { | ||
470 | mdev->irq_info.mic_msi_map[entry] |= (1 << offset); | ||
471 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
472 | entry, offset, true); | ||
473 | } | ||
474 | cookie = MK_COOKIE(entry, intr_cb->cb_id); | ||
475 | dev_dbg(mdev->sdev->parent, "callback %d registered for src: %d\n", | ||
476 | intr_cb->cb_id, intr_src); | ||
477 | } | ||
478 | return (struct mic_irq *)cookie; | ||
479 | err: | ||
480 | return ERR_PTR(rc); | ||
481 | } | ||
482 | |||
483 | /** | ||
484 | * mic_free_irq - free irq. mic_mutex | ||
485 | * needs to be held before calling this function. | ||
486 | * | ||
487 | * @mdev: pointer to mic_device instance | ||
488 | * @cookie: cookie obtained during a successful call to mic_request_irq | ||
489 | * @data: private data specified by the calling function during the | ||
490 | * mic_request_irq | ||
491 | * | ||
492 | * returns: none. | ||
493 | */ | ||
494 | void mic_free_irq(struct mic_device *mdev, | ||
495 | struct mic_irq *cookie, void *data) | ||
496 | { | ||
497 | u32 offset; | ||
498 | u32 entry; | ||
499 | u8 src_id; | ||
500 | unsigned int irq; | ||
501 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
502 | struct pci_dev, dev); | ||
503 | |||
504 | entry = GET_ENTRY((unsigned long)cookie); | ||
505 | offset = GET_OFFSET((unsigned long)cookie); | ||
506 | if (mdev->irq_info.num_vectors > 1) { | ||
507 | if (entry >= mdev->irq_info.num_vectors) { | ||
508 | dev_warn(mdev->sdev->parent, | ||
509 | "entry %d should be < num_irq %d\n", | ||
510 | entry, mdev->irq_info.num_vectors); | ||
511 | return; | ||
512 | } | ||
513 | irq = mdev->irq_info.msix_entries[entry].vector; | ||
514 | free_irq(irq, data); | ||
515 | mdev->irq_info.mic_msi_map[entry] &= ~(BIT(offset)); | ||
516 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
517 | entry, offset, false); | ||
518 | |||
519 | dev_dbg(mdev->sdev->parent, "irq: %d freed\n", irq); | ||
520 | } else { | ||
521 | irq = pdev->irq; | ||
522 | src_id = mic_unregister_intr_callback(mdev, offset); | ||
523 | if (src_id >= MIC_NUM_OFFSETS) { | ||
524 | dev_warn(mdev->sdev->parent, "Error unregistering callback\n"); | ||
525 | return; | ||
526 | } | ||
527 | if (pci_dev_msi_enabled(pdev)) { | ||
528 | mdev->irq_info.mic_msi_map[entry] &= ~(BIT(src_id)); | ||
529 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
530 | entry, src_id, false); | ||
531 | } | ||
532 | dev_dbg(mdev->sdev->parent, "callback %d unregistered for src: %d\n", | ||
533 | offset, src_id); | ||
534 | } | ||
535 | } | ||
536 | |||
537 | /** | ||
538 | * mic_setup_interrupts - Initializes interrupts. | ||
539 | * | ||
540 | * @mdev: pointer to mic_device instance | ||
541 | * @pdev: PCI device structure | ||
542 | * | ||
543 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
544 | */ | ||
545 | int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev) | ||
546 | { | ||
547 | int rc; | ||
548 | |||
549 | rc = mic_setup_msix(mdev, pdev); | ||
550 | if (!rc) | ||
551 | goto done; | ||
552 | |||
553 | rc = mic_setup_msi(mdev, pdev); | ||
554 | if (!rc) | ||
555 | goto done; | ||
556 | |||
557 | rc = mic_setup_intx(mdev, pdev); | ||
558 | if (rc) { | ||
559 | dev_err(mdev->sdev->parent, "no usable interrupts\n"); | ||
560 | return rc; | ||
561 | } | ||
562 | done: | ||
563 | mdev->intr_ops->enable_interrupts(mdev); | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * mic_free_interrupts - Frees interrupts setup by mic_setup_interrupts | ||
569 | * | ||
570 | * @mdev: pointer to mic_device instance | ||
571 | * @pdev: PCI device structure | ||
572 | * | ||
573 | * returns none. | ||
574 | */ | ||
575 | void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev) | ||
576 | { | ||
577 | int i; | ||
578 | |||
579 | mdev->intr_ops->disable_interrupts(mdev); | ||
580 | if (mdev->irq_info.num_vectors > 1) { | ||
581 | for (i = 0; i < mdev->irq_info.num_vectors; i++) { | ||
582 | if (mdev->irq_info.mic_msi_map[i]) | ||
583 | dev_warn(&pdev->dev, "irq %d may still be in use.\n", | ||
584 | mdev->irq_info.msix_entries[i].vector); | ||
585 | } | ||
586 | kfree(mdev->irq_info.mic_msi_map); | ||
587 | kfree(mdev->irq_info.msix_entries); | ||
588 | pci_disable_msix(pdev); | ||
589 | } else { | ||
590 | if (pci_dev_msi_enabled(pdev)) { | ||
591 | free_irq(pdev->irq, mdev); | ||
592 | kfree(mdev->irq_info.mic_msi_map); | ||
593 | pci_disable_msi(pdev); | ||
594 | } else { | ||
595 | free_irq(pdev->irq, mdev); | ||
596 | } | ||
597 | mic_release_callbacks(mdev); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * mic_intr_restore - Restore MIC interrupt registers. | ||
603 | * | ||
604 | * @mdev: pointer to mic_device instance. | ||
605 | * | ||
606 | * Restore the interrupt registers to values previously | ||
607 | * stored in the SW data structures. mic_mutex needs to | ||
608 | * be held before calling this function. | ||
609 | * | ||
610 | * returns None. | ||
611 | */ | ||
612 | void mic_intr_restore(struct mic_device *mdev) | ||
613 | { | ||
614 | int entry, offset; | ||
615 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
616 | struct pci_dev, dev); | ||
617 | |||
618 | if (!pci_dev_msi_enabled(pdev)) | ||
619 | return; | ||
620 | |||
621 | for (entry = 0; entry < mdev->irq_info.num_vectors; entry++) { | ||
622 | for (offset = 0; offset < MIC_NUM_OFFSETS; offset++) { | ||
623 | if (mdev->irq_info.mic_msi_map[entry] & BIT(offset)) | ||
624 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
625 | entry, offset, true); | ||
626 | } | ||
627 | } | ||
628 | } | ||
diff --git a/drivers/misc/mic/host/mic_intr.h b/drivers/misc/mic/host/mic_intr.h new file mode 100644 index 000000000000..6091aa97e116 --- /dev/null +++ b/drivers/misc/mic/host/mic_intr.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #ifndef _MIC_INTR_H_ | ||
22 | #define _MIC_INTR_H_ | ||
23 | |||
24 | /* | ||
25 | * The minimum number of msix vectors required for normal operation. | ||
26 | * 3 for virtio network, console and block devices. | ||
27 | * 1 for card shutdown notifications. | ||
28 | */ | ||
29 | #define MIC_MIN_MSIX 4 | ||
30 | #define MIC_NUM_OFFSETS 32 | ||
31 | |||
32 | /** | ||
33 | * mic_intr_source - The type of source that will generate | ||
34 | * the interrupt.The number of types needs to be in sync with | ||
35 | * MIC_NUM_INTR_TYPES | ||
36 | * | ||
37 | * MIC_INTR_DB: The source is a doorbell | ||
38 | * MIC_INTR_DMA: The source is a DMA channel | ||
39 | * MIC_INTR_ERR: The source is an error interrupt e.g. SBOX ERR | ||
40 | * MIC_NUM_INTR_TYPES: Total number of interrupt sources. | ||
41 | */ | ||
42 | enum mic_intr_type { | ||
43 | MIC_INTR_DB = 0, | ||
44 | MIC_INTR_DMA, | ||
45 | MIC_INTR_ERR, | ||
46 | MIC_NUM_INTR_TYPES | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * struct mic_intr_info - Contains h/w specific interrupt sources | ||
51 | * information. | ||
52 | * | ||
53 | * @intr_start_idx: Contains the starting indexes of the | ||
54 | * interrupt types. | ||
55 | * @intr_len: Contains the length of the interrupt types. | ||
56 | */ | ||
57 | struct mic_intr_info { | ||
58 | u16 intr_start_idx[MIC_NUM_INTR_TYPES]; | ||
59 | u16 intr_len[MIC_NUM_INTR_TYPES]; | ||
60 | }; | ||
61 | |||
62 | /** | ||
63 | * struct mic_irq_info - OS specific irq information | ||
64 | * | ||
65 | * @next_avail_src: next available doorbell that can be assigned. | ||
66 | * @msix_entries: msix entries allocated while setting up MSI-x | ||
67 | * @mic_msi_map: The MSI/MSI-x mapping information. | ||
68 | * @num_vectors: The number of MSI/MSI-x vectors that have been allocated. | ||
69 | * @cb_ida: callback ID allocator to track the callbacks registered. | ||
70 | * @mic_intr_lock: spinlock to protect the interrupt callback list. | ||
71 | * @cb_list: Array of callback lists one for each source. | ||
72 | */ | ||
73 | struct mic_irq_info { | ||
74 | int next_avail_src; | ||
75 | struct msix_entry *msix_entries; | ||
76 | u32 *mic_msi_map; | ||
77 | u16 num_vectors; | ||
78 | struct ida cb_ida; | ||
79 | spinlock_t mic_intr_lock; | ||
80 | struct list_head *cb_list; | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * struct mic_intr_cb - Interrupt callback structure. | ||
85 | * | ||
86 | * @func: The callback function | ||
87 | * @data: Private data of the requester. | ||
88 | * @cb_id: The callback id. Identifies this callback. | ||
89 | * @list: list head pointing to the next callback structure. | ||
90 | */ | ||
91 | struct mic_intr_cb { | ||
92 | irqreturn_t (*func) (int irq, void *data); | ||
93 | void *data; | ||
94 | int cb_id; | ||
95 | struct list_head list; | ||
96 | }; | ||
97 | |||
98 | /** | ||
99 | * struct mic_irq - opaque pointer used as cookie | ||
100 | */ | ||
101 | struct mic_irq; | ||
102 | |||
103 | /* Forward declaration */ | ||
104 | struct mic_device; | ||
105 | |||
106 | /** | ||
107 | * struct mic_hw_intr_ops: MIC HW specific interrupt operations | ||
108 | * @intr_init: Initialize H/W specific interrupt information. | ||
109 | * @enable_interrupts: Enable interrupts from the hardware. | ||
110 | * @disable_interrupts: Disable interrupts from the hardware. | ||
111 | * @program_msi_to_src_map: Update MSI mapping registers with | ||
112 | * irq information. | ||
113 | * @read_msi_to_src_map: Read MSI mapping registers containing | ||
114 | * irq information. | ||
115 | */ | ||
116 | struct mic_hw_intr_ops { | ||
117 | void (*intr_init)(struct mic_device *mdev); | ||
118 | void (*enable_interrupts)(struct mic_device *mdev); | ||
119 | void (*disable_interrupts)(struct mic_device *mdev); | ||
120 | void (*program_msi_to_src_map) (struct mic_device *mdev, | ||
121 | int idx, int intr_src, bool set); | ||
122 | u32 (*read_msi_to_src_map) (struct mic_device *mdev, | ||
123 | int idx); | ||
124 | }; | ||
125 | |||
126 | int mic_next_db(struct mic_device *mdev); | ||
127 | struct mic_irq *mic_request_irq(struct mic_device *mdev, | ||
128 | irqreturn_t (*func)(int irq, void *data), | ||
129 | const char *name, void *data, int intr_src, | ||
130 | enum mic_intr_type type); | ||
131 | |||
132 | void mic_free_irq(struct mic_device *mdev, | ||
133 | struct mic_irq *cookie, void *data); | ||
134 | int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev); | ||
135 | void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev); | ||
136 | void mic_intr_restore(struct mic_device *mdev); | ||
137 | #endif | ||
diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c new file mode 100644 index 000000000000..a8965d496e84 --- /dev/null +++ b/drivers/misc/mic/host/mic_main.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | * Global TODO's across the driver to be added after initial base | ||
21 | * patches are accepted upstream: | ||
22 | * 1) Enable DMA support. | ||
23 | * 2) Enable per vring interrupt support. | ||
24 | */ | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/poll.h> | ||
29 | |||
30 | #include <linux/mic_common.h> | ||
31 | #include "../common/mic_device.h" | ||
32 | #include "mic_device.h" | ||
33 | #include "mic_x100.h" | ||
34 | #include "mic_smpt.h" | ||
35 | #include "mic_fops.h" | ||
36 | #include "mic_virtio.h" | ||
37 | |||
38 | static const char mic_driver_name[] = "mic"; | ||
39 | |||
40 | static DEFINE_PCI_DEVICE_TABLE(mic_pci_tbl) = { | ||
41 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2250)}, | ||
42 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2251)}, | ||
43 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2252)}, | ||
44 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2253)}, | ||
45 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2254)}, | ||
46 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2255)}, | ||
47 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2256)}, | ||
48 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2257)}, | ||
49 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2258)}, | ||
50 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2259)}, | ||
51 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225a)}, | ||
52 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225b)}, | ||
53 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225c)}, | ||
54 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225d)}, | ||
55 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225e)}, | ||
56 | |||
57 | /* required last entry */ | ||
58 | { 0, } | ||
59 | }; | ||
60 | |||
61 | MODULE_DEVICE_TABLE(pci, mic_pci_tbl); | ||
62 | |||
63 | /* ID allocator for MIC devices */ | ||
64 | static struct ida g_mic_ida; | ||
65 | /* Class of MIC devices for sysfs accessibility. */ | ||
66 | static struct class *g_mic_class; | ||
67 | /* Base device node number for MIC devices */ | ||
68 | static dev_t g_mic_devno; | ||
69 | |||
70 | static const struct file_operations mic_fops = { | ||
71 | .open = mic_open, | ||
72 | .release = mic_release, | ||
73 | .unlocked_ioctl = mic_ioctl, | ||
74 | .poll = mic_poll, | ||
75 | .mmap = mic_mmap, | ||
76 | .owner = THIS_MODULE, | ||
77 | }; | ||
78 | |||
79 | /* Initialize the device page */ | ||
80 | static int mic_dp_init(struct mic_device *mdev) | ||
81 | { | ||
82 | mdev->dp = kzalloc(MIC_DP_SIZE, GFP_KERNEL); | ||
83 | if (!mdev->dp) { | ||
84 | dev_err(mdev->sdev->parent, "%s %d err %d\n", | ||
85 | __func__, __LINE__, -ENOMEM); | ||
86 | return -ENOMEM; | ||
87 | } | ||
88 | |||
89 | mdev->dp_dma_addr = mic_map_single(mdev, | ||
90 | mdev->dp, MIC_DP_SIZE); | ||
91 | if (mic_map_error(mdev->dp_dma_addr)) { | ||
92 | kfree(mdev->dp); | ||
93 | dev_err(mdev->sdev->parent, "%s %d err %d\n", | ||
94 | __func__, __LINE__, -ENOMEM); | ||
95 | return -ENOMEM; | ||
96 | } | ||
97 | mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); | ||
98 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | /* Uninitialize the device page */ | ||
103 | static void mic_dp_uninit(struct mic_device *mdev) | ||
104 | { | ||
105 | mic_unmap_single(mdev, mdev->dp_dma_addr, MIC_DP_SIZE); | ||
106 | kfree(mdev->dp); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * mic_shutdown_db - Shutdown doorbell interrupt handler. | ||
111 | */ | ||
112 | static irqreturn_t mic_shutdown_db(int irq, void *data) | ||
113 | { | ||
114 | struct mic_device *mdev = data; | ||
115 | struct mic_bootparam *bootparam = mdev->dp; | ||
116 | |||
117 | mdev->ops->ack_interrupt(mdev); | ||
118 | |||
119 | switch (bootparam->shutdown_status) { | ||
120 | case MIC_HALTED: | ||
121 | case MIC_POWER_OFF: | ||
122 | case MIC_RESTART: | ||
123 | /* Fall through */ | ||
124 | case MIC_CRASHED: | ||
125 | schedule_work(&mdev->shutdown_work); | ||
126 | break; | ||
127 | default: | ||
128 | break; | ||
129 | }; | ||
130 | return IRQ_HANDLED; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * mic_ops_init: Initialize HW specific operation tables. | ||
135 | * | ||
136 | * @mdev: pointer to mic_device instance | ||
137 | * | ||
138 | * returns none. | ||
139 | */ | ||
140 | static void mic_ops_init(struct mic_device *mdev) | ||
141 | { | ||
142 | switch (mdev->family) { | ||
143 | case MIC_FAMILY_X100: | ||
144 | mdev->ops = &mic_x100_ops; | ||
145 | mdev->intr_ops = &mic_x100_intr_ops; | ||
146 | mdev->smpt_ops = &mic_x100_smpt_ops; | ||
147 | break; | ||
148 | default: | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * mic_get_family - Determine hardware family to which this MIC belongs. | ||
155 | * | ||
156 | * @pdev: The pci device structure | ||
157 | * | ||
158 | * returns family. | ||
159 | */ | ||
160 | static enum mic_hw_family mic_get_family(struct pci_dev *pdev) | ||
161 | { | ||
162 | enum mic_hw_family family; | ||
163 | |||
164 | switch (pdev->device) { | ||
165 | case MIC_X100_PCI_DEVICE_2250: | ||
166 | case MIC_X100_PCI_DEVICE_2251: | ||
167 | case MIC_X100_PCI_DEVICE_2252: | ||
168 | case MIC_X100_PCI_DEVICE_2253: | ||
169 | case MIC_X100_PCI_DEVICE_2254: | ||
170 | case MIC_X100_PCI_DEVICE_2255: | ||
171 | case MIC_X100_PCI_DEVICE_2256: | ||
172 | case MIC_X100_PCI_DEVICE_2257: | ||
173 | case MIC_X100_PCI_DEVICE_2258: | ||
174 | case MIC_X100_PCI_DEVICE_2259: | ||
175 | case MIC_X100_PCI_DEVICE_225a: | ||
176 | case MIC_X100_PCI_DEVICE_225b: | ||
177 | case MIC_X100_PCI_DEVICE_225c: | ||
178 | case MIC_X100_PCI_DEVICE_225d: | ||
179 | case MIC_X100_PCI_DEVICE_225e: | ||
180 | family = MIC_FAMILY_X100; | ||
181 | break; | ||
182 | default: | ||
183 | family = MIC_FAMILY_UNKNOWN; | ||
184 | break; | ||
185 | } | ||
186 | return family; | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * mic_device_init - Allocates and initializes the MIC device structure | ||
191 | * | ||
192 | * @mdev: pointer to mic_device instance | ||
193 | * @pdev: The pci device structure | ||
194 | * | ||
195 | * returns none. | ||
196 | */ | ||
197 | static void | ||
198 | mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) | ||
199 | { | ||
200 | mdev->family = mic_get_family(pdev); | ||
201 | mdev->stepping = pdev->revision; | ||
202 | mic_ops_init(mdev); | ||
203 | mic_sysfs_init(mdev); | ||
204 | mutex_init(&mdev->mic_mutex); | ||
205 | mdev->irq_info.next_avail_src = 0; | ||
206 | INIT_WORK(&mdev->reset_trigger_work, mic_reset_trigger_work); | ||
207 | INIT_WORK(&mdev->shutdown_work, mic_shutdown_work); | ||
208 | INIT_LIST_HEAD(&mdev->vdev_list); | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * mic_device_uninit - Frees resources allocated during mic_device_init(..) | ||
213 | * | ||
214 | * @mdev: pointer to mic_device instance | ||
215 | * | ||
216 | * returns none | ||
217 | */ | ||
218 | static void mic_device_uninit(struct mic_device *mdev) | ||
219 | { | ||
220 | /* The cmdline sysfs entry might have allocated cmdline */ | ||
221 | kfree(mdev->cmdline); | ||
222 | kfree(mdev->firmware); | ||
223 | kfree(mdev->ramdisk); | ||
224 | kfree(mdev->bootmode); | ||
225 | flush_work(&mdev->reset_trigger_work); | ||
226 | flush_work(&mdev->shutdown_work); | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * mic_probe - Device Initialization Routine | ||
231 | * | ||
232 | * @pdev: PCI device structure | ||
233 | * @ent: entry in mic_pci_tbl | ||
234 | * | ||
235 | * returns 0 on success, < 0 on failure. | ||
236 | */ | ||
237 | static int mic_probe(struct pci_dev *pdev, | ||
238 | const struct pci_device_id *ent) | ||
239 | { | ||
240 | int rc; | ||
241 | struct mic_device *mdev; | ||
242 | |||
243 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); | ||
244 | if (!mdev) { | ||
245 | rc = -ENOMEM; | ||
246 | dev_err(&pdev->dev, "mdev kmalloc failed rc %d\n", rc); | ||
247 | goto mdev_alloc_fail; | ||
248 | } | ||
249 | mdev->id = ida_simple_get(&g_mic_ida, 0, MIC_MAX_NUM_DEVS, GFP_KERNEL); | ||
250 | if (mdev->id < 0) { | ||
251 | rc = mdev->id; | ||
252 | dev_err(&pdev->dev, "ida_simple_get failed rc %d\n", rc); | ||
253 | goto ida_fail; | ||
254 | } | ||
255 | |||
256 | mic_device_init(mdev, pdev); | ||
257 | |||
258 | rc = pci_enable_device(pdev); | ||
259 | if (rc) { | ||
260 | dev_err(&pdev->dev, "failed to enable pci device.\n"); | ||
261 | goto uninit_device; | ||
262 | } | ||
263 | |||
264 | pci_set_master(pdev); | ||
265 | |||
266 | rc = pci_request_regions(pdev, mic_driver_name); | ||
267 | if (rc) { | ||
268 | dev_err(&pdev->dev, "failed to get pci regions.\n"); | ||
269 | goto disable_device; | ||
270 | } | ||
271 | |||
272 | rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | ||
273 | if (rc) { | ||
274 | dev_err(&pdev->dev, "Cannot set DMA mask\n"); | ||
275 | goto release_regions; | ||
276 | } | ||
277 | |||
278 | mdev->mmio.pa = pci_resource_start(pdev, mdev->ops->mmio_bar); | ||
279 | mdev->mmio.len = pci_resource_len(pdev, mdev->ops->mmio_bar); | ||
280 | mdev->mmio.va = pci_ioremap_bar(pdev, mdev->ops->mmio_bar); | ||
281 | if (!mdev->mmio.va) { | ||
282 | dev_err(&pdev->dev, "Cannot remap MMIO BAR\n"); | ||
283 | rc = -EIO; | ||
284 | goto release_regions; | ||
285 | } | ||
286 | |||
287 | mdev->aper.pa = pci_resource_start(pdev, mdev->ops->aper_bar); | ||
288 | mdev->aper.len = pci_resource_len(pdev, mdev->ops->aper_bar); | ||
289 | mdev->aper.va = ioremap_wc(mdev->aper.pa, mdev->aper.len); | ||
290 | if (!mdev->aper.va) { | ||
291 | dev_err(&pdev->dev, "Cannot remap Aperture BAR\n"); | ||
292 | rc = -EIO; | ||
293 | goto unmap_mmio; | ||
294 | } | ||
295 | |||
296 | mdev->intr_ops->intr_init(mdev); | ||
297 | rc = mic_setup_interrupts(mdev, pdev); | ||
298 | if (rc) { | ||
299 | dev_err(&pdev->dev, "mic_setup_interrupts failed %d\n", rc); | ||
300 | goto unmap_aper; | ||
301 | } | ||
302 | rc = mic_smpt_init(mdev); | ||
303 | if (rc) { | ||
304 | dev_err(&pdev->dev, "smpt_init failed %d\n", rc); | ||
305 | goto free_interrupts; | ||
306 | } | ||
307 | |||
308 | pci_set_drvdata(pdev, mdev); | ||
309 | |||
310 | mdev->sdev = device_create_with_groups(g_mic_class, &pdev->dev, | ||
311 | MKDEV(MAJOR(g_mic_devno), mdev->id), NULL, | ||
312 | mdev->attr_group, "mic%d", mdev->id); | ||
313 | if (IS_ERR(mdev->sdev)) { | ||
314 | rc = PTR_ERR(mdev->sdev); | ||
315 | dev_err(&pdev->dev, | ||
316 | "device_create_with_groups failed rc %d\n", rc); | ||
317 | goto smpt_uninit; | ||
318 | } | ||
319 | mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd, | ||
320 | NULL, "state"); | ||
321 | if (!mdev->state_sysfs) { | ||
322 | rc = -ENODEV; | ||
323 | dev_err(&pdev->dev, "sysfs_get_dirent failed rc %d\n", rc); | ||
324 | goto destroy_device; | ||
325 | } | ||
326 | |||
327 | rc = mic_dp_init(mdev); | ||
328 | if (rc) { | ||
329 | dev_err(&pdev->dev, "mic_dp_init failed rc %d\n", rc); | ||
330 | goto sysfs_put; | ||
331 | } | ||
332 | mutex_lock(&mdev->mic_mutex); | ||
333 | |||
334 | mdev->shutdown_db = mic_next_db(mdev); | ||
335 | mdev->shutdown_cookie = mic_request_irq(mdev, mic_shutdown_db, | ||
336 | "shutdown-interrupt", mdev, mdev->shutdown_db, MIC_INTR_DB); | ||
337 | if (IS_ERR(mdev->shutdown_cookie)) { | ||
338 | rc = PTR_ERR(mdev->shutdown_cookie); | ||
339 | mutex_unlock(&mdev->mic_mutex); | ||
340 | goto dp_uninit; | ||
341 | } | ||
342 | mutex_unlock(&mdev->mic_mutex); | ||
343 | mic_bootparam_init(mdev); | ||
344 | |||
345 | mic_create_debug_dir(mdev); | ||
346 | cdev_init(&mdev->cdev, &mic_fops); | ||
347 | mdev->cdev.owner = THIS_MODULE; | ||
348 | rc = cdev_add(&mdev->cdev, MKDEV(MAJOR(g_mic_devno), mdev->id), 1); | ||
349 | if (rc) { | ||
350 | dev_err(&pdev->dev, "cdev_add err id %d rc %d\n", mdev->id, rc); | ||
351 | goto cleanup_debug_dir; | ||
352 | } | ||
353 | return 0; | ||
354 | cleanup_debug_dir: | ||
355 | mic_delete_debug_dir(mdev); | ||
356 | mutex_lock(&mdev->mic_mutex); | ||
357 | mic_free_irq(mdev, mdev->shutdown_cookie, mdev); | ||
358 | mutex_unlock(&mdev->mic_mutex); | ||
359 | dp_uninit: | ||
360 | mic_dp_uninit(mdev); | ||
361 | sysfs_put: | ||
362 | sysfs_put(mdev->state_sysfs); | ||
363 | destroy_device: | ||
364 | device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id)); | ||
365 | smpt_uninit: | ||
366 | mic_smpt_uninit(mdev); | ||
367 | free_interrupts: | ||
368 | mic_free_interrupts(mdev, pdev); | ||
369 | unmap_aper: | ||
370 | iounmap(mdev->aper.va); | ||
371 | unmap_mmio: | ||
372 | iounmap(mdev->mmio.va); | ||
373 | release_regions: | ||
374 | pci_release_regions(pdev); | ||
375 | disable_device: | ||
376 | pci_disable_device(pdev); | ||
377 | uninit_device: | ||
378 | mic_device_uninit(mdev); | ||
379 | ida_simple_remove(&g_mic_ida, mdev->id); | ||
380 | ida_fail: | ||
381 | kfree(mdev); | ||
382 | mdev_alloc_fail: | ||
383 | dev_err(&pdev->dev, "Probe failed rc %d\n", rc); | ||
384 | return rc; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * mic_remove - Device Removal Routine | ||
389 | * mic_remove is called by the PCI subsystem to alert the driver | ||
390 | * that it should release a PCI device. | ||
391 | * | ||
392 | * @pdev: PCI device structure | ||
393 | */ | ||
394 | static void mic_remove(struct pci_dev *pdev) | ||
395 | { | ||
396 | struct mic_device *mdev; | ||
397 | |||
398 | mdev = pci_get_drvdata(pdev); | ||
399 | if (!mdev) | ||
400 | return; | ||
401 | |||
402 | mic_stop(mdev, false); | ||
403 | cdev_del(&mdev->cdev); | ||
404 | mic_delete_debug_dir(mdev); | ||
405 | mutex_lock(&mdev->mic_mutex); | ||
406 | mic_free_irq(mdev, mdev->shutdown_cookie, mdev); | ||
407 | mutex_unlock(&mdev->mic_mutex); | ||
408 | flush_work(&mdev->shutdown_work); | ||
409 | mic_dp_uninit(mdev); | ||
410 | sysfs_put(mdev->state_sysfs); | ||
411 | device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id)); | ||
412 | mic_smpt_uninit(mdev); | ||
413 | mic_free_interrupts(mdev, pdev); | ||
414 | iounmap(mdev->mmio.va); | ||
415 | iounmap(mdev->aper.va); | ||
416 | mic_device_uninit(mdev); | ||
417 | pci_release_regions(pdev); | ||
418 | pci_disable_device(pdev); | ||
419 | ida_simple_remove(&g_mic_ida, mdev->id); | ||
420 | kfree(mdev); | ||
421 | } | ||
422 | static struct pci_driver mic_driver = { | ||
423 | .name = mic_driver_name, | ||
424 | .id_table = mic_pci_tbl, | ||
425 | .probe = mic_probe, | ||
426 | .remove = mic_remove | ||
427 | }; | ||
428 | |||
429 | static int __init mic_init(void) | ||
430 | { | ||
431 | int ret; | ||
432 | |||
433 | ret = alloc_chrdev_region(&g_mic_devno, 0, | ||
434 | MIC_MAX_NUM_DEVS, mic_driver_name); | ||
435 | if (ret) { | ||
436 | pr_err("alloc_chrdev_region failed ret %d\n", ret); | ||
437 | goto error; | ||
438 | } | ||
439 | |||
440 | g_mic_class = class_create(THIS_MODULE, mic_driver_name); | ||
441 | if (IS_ERR(g_mic_class)) { | ||
442 | ret = PTR_ERR(g_mic_class); | ||
443 | pr_err("class_create failed ret %d\n", ret); | ||
444 | goto cleanup_chrdev; | ||
445 | } | ||
446 | |||
447 | mic_init_debugfs(); | ||
448 | ida_init(&g_mic_ida); | ||
449 | ret = pci_register_driver(&mic_driver); | ||
450 | if (ret) { | ||
451 | pr_err("pci_register_driver failed ret %d\n", ret); | ||
452 | goto cleanup_debugfs; | ||
453 | } | ||
454 | return ret; | ||
455 | cleanup_debugfs: | ||
456 | mic_exit_debugfs(); | ||
457 | class_destroy(g_mic_class); | ||
458 | cleanup_chrdev: | ||
459 | unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); | ||
460 | error: | ||
461 | return ret; | ||
462 | } | ||
463 | |||
464 | static void __exit mic_exit(void) | ||
465 | { | ||
466 | pci_unregister_driver(&mic_driver); | ||
467 | ida_destroy(&g_mic_ida); | ||
468 | mic_exit_debugfs(); | ||
469 | class_destroy(g_mic_class); | ||
470 | unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); | ||
471 | } | ||
472 | |||
473 | module_init(mic_init); | ||
474 | module_exit(mic_exit); | ||
475 | |||
476 | MODULE_AUTHOR("Intel Corporation"); | ||
477 | MODULE_DESCRIPTION("Intel(R) MIC X100 Host driver"); | ||
478 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/mic/host/mic_smpt.c b/drivers/misc/mic/host/mic_smpt.c new file mode 100644 index 000000000000..a3462076bc57 --- /dev/null +++ b/drivers/misc/mic/host/mic_smpt.c | |||
@@ -0,0 +1,442 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/pci.h> | ||
22 | |||
23 | #include "../common/mic_device.h" | ||
24 | #include "mic_device.h" | ||
25 | #include "mic_smpt.h" | ||
26 | |||
27 | static inline u64 mic_system_page_mask(struct mic_device *mdev) | ||
28 | { | ||
29 | return (1ULL << mdev->smpt->info.page_shift) - 1ULL; | ||
30 | } | ||
31 | |||
32 | static inline u8 mic_sys_addr_to_smpt(struct mic_device *mdev, dma_addr_t pa) | ||
33 | { | ||
34 | return (pa - mdev->smpt->info.base) >> mdev->smpt->info.page_shift; | ||
35 | } | ||
36 | |||
37 | static inline u64 mic_smpt_to_pa(struct mic_device *mdev, u8 index) | ||
38 | { | ||
39 | return mdev->smpt->info.base + (index * mdev->smpt->info.page_size); | ||
40 | } | ||
41 | |||
42 | static inline u64 mic_smpt_offset(struct mic_device *mdev, dma_addr_t pa) | ||
43 | { | ||
44 | return pa & mic_system_page_mask(mdev); | ||
45 | } | ||
46 | |||
47 | static inline u64 mic_smpt_align_low(struct mic_device *mdev, dma_addr_t pa) | ||
48 | { | ||
49 | return ALIGN(pa - mic_system_page_mask(mdev), | ||
50 | mdev->smpt->info.page_size); | ||
51 | } | ||
52 | |||
53 | static inline u64 mic_smpt_align_high(struct mic_device *mdev, dma_addr_t pa) | ||
54 | { | ||
55 | return ALIGN(pa, mdev->smpt->info.page_size); | ||
56 | } | ||
57 | |||
58 | /* Total Cumulative system memory accessible by MIC across all SMPT entries */ | ||
59 | static inline u64 mic_max_system_memory(struct mic_device *mdev) | ||
60 | { | ||
61 | return mdev->smpt->info.num_reg * mdev->smpt->info.page_size; | ||
62 | } | ||
63 | |||
64 | /* Maximum system memory address accessible by MIC */ | ||
65 | static inline u64 mic_max_system_addr(struct mic_device *mdev) | ||
66 | { | ||
67 | return mdev->smpt->info.base + mic_max_system_memory(mdev) - 1ULL; | ||
68 | } | ||
69 | |||
70 | /* Check if the DMA address is a MIC system memory address */ | ||
71 | static inline bool | ||
72 | mic_is_system_addr(struct mic_device *mdev, dma_addr_t pa) | ||
73 | { | ||
74 | return pa >= mdev->smpt->info.base && pa <= mic_max_system_addr(mdev); | ||
75 | } | ||
76 | |||
77 | /* Populate an SMPT entry and update the reference counts. */ | ||
78 | static void mic_add_smpt_entry(int spt, s64 *ref, u64 addr, | ||
79 | int entries, struct mic_device *mdev) | ||
80 | { | ||
81 | struct mic_smpt_info *smpt_info = mdev->smpt; | ||
82 | int i; | ||
83 | |||
84 | for (i = spt; i < spt + entries; i++, | ||
85 | addr += smpt_info->info.page_size) { | ||
86 | if (!smpt_info->entry[i].ref_count && | ||
87 | (smpt_info->entry[i].dma_addr != addr)) { | ||
88 | mdev->smpt_ops->set(mdev, addr, i); | ||
89 | smpt_info->entry[i].dma_addr = addr; | ||
90 | } | ||
91 | smpt_info->entry[i].ref_count += ref[i - spt]; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Find an available MIC address in MIC SMPT address space | ||
97 | * for a given DMA address and size. | ||
98 | */ | ||
99 | static dma_addr_t mic_smpt_op(struct mic_device *mdev, u64 dma_addr, | ||
100 | int entries, s64 *ref, size_t size) | ||
101 | { | ||
102 | int spt; | ||
103 | int ae = 0; | ||
104 | int i; | ||
105 | unsigned long flags; | ||
106 | dma_addr_t mic_addr = 0; | ||
107 | dma_addr_t addr = dma_addr; | ||
108 | struct mic_smpt_info *smpt_info = mdev->smpt; | ||
109 | |||
110 | spin_lock_irqsave(&smpt_info->smpt_lock, flags); | ||
111 | |||
112 | /* find existing entries */ | ||
113 | for (i = 0; i < smpt_info->info.num_reg; i++) { | ||
114 | if (smpt_info->entry[i].dma_addr == addr) { | ||
115 | ae++; | ||
116 | addr += smpt_info->info.page_size; | ||
117 | } else if (ae) /* cannot find contiguous entries */ | ||
118 | goto not_found; | ||
119 | |||
120 | if (ae == entries) | ||
121 | goto found; | ||
122 | } | ||
123 | |||
124 | /* find free entry */ | ||
125 | for (ae = 0, i = 0; i < smpt_info->info.num_reg; i++) { | ||
126 | ae = (smpt_info->entry[i].ref_count == 0) ? ae + 1 : 0; | ||
127 | if (ae == entries) | ||
128 | goto found; | ||
129 | } | ||
130 | |||
131 | not_found: | ||
132 | spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); | ||
133 | return mic_addr; | ||
134 | |||
135 | found: | ||
136 | spt = i - entries + 1; | ||
137 | mic_addr = mic_smpt_to_pa(mdev, spt); | ||
138 | mic_add_smpt_entry(spt, ref, dma_addr, entries, mdev); | ||
139 | smpt_info->map_count++; | ||
140 | smpt_info->ref_count += (s64)size; | ||
141 | spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); | ||
142 | return mic_addr; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Returns number of smpt entries needed for dma_addr to dma_addr + size | ||
147 | * also returns the reference count array for each of those entries | ||
148 | * and the starting smpt address | ||
149 | */ | ||
150 | static int mic_get_smpt_ref_count(struct mic_device *mdev, dma_addr_t dma_addr, | ||
151 | size_t size, s64 *ref, u64 *smpt_start) | ||
152 | { | ||
153 | u64 start = dma_addr; | ||
154 | u64 end = dma_addr + size; | ||
155 | int i = 0; | ||
156 | |||
157 | while (start < end) { | ||
158 | ref[i++] = min(mic_smpt_align_high(mdev, start + 1), | ||
159 | end) - start; | ||
160 | start = mic_smpt_align_high(mdev, start + 1); | ||
161 | } | ||
162 | |||
163 | if (smpt_start) | ||
164 | *smpt_start = mic_smpt_align_low(mdev, dma_addr); | ||
165 | |||
166 | return i; | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * mic_to_dma_addr - Converts a MIC address to a DMA address. | ||
171 | * | ||
172 | * @mdev: pointer to mic_device instance. | ||
173 | * @mic_addr: MIC address. | ||
174 | * | ||
175 | * returns a DMA address. | ||
176 | */ | ||
177 | static dma_addr_t | ||
178 | mic_to_dma_addr(struct mic_device *mdev, dma_addr_t mic_addr) | ||
179 | { | ||
180 | struct mic_smpt_info *smpt_info = mdev->smpt; | ||
181 | int spt; | ||
182 | dma_addr_t dma_addr; | ||
183 | |||
184 | if (!mic_is_system_addr(mdev, mic_addr)) { | ||
185 | dev_err(mdev->sdev->parent, | ||
186 | "mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr); | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | spt = mic_sys_addr_to_smpt(mdev, mic_addr); | ||
190 | dma_addr = smpt_info->entry[spt].dma_addr + | ||
191 | mic_smpt_offset(mdev, mic_addr); | ||
192 | return dma_addr; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * mic_map - Maps a DMA address to a MIC physical address. | ||
197 | * | ||
198 | * @mdev: pointer to mic_device instance. | ||
199 | * @dma_addr: DMA address. | ||
200 | * @size: Size of the region to be mapped. | ||
201 | * | ||
202 | * This API converts the DMA address provided to a DMA address understood | ||
203 | * by MIC. Caller should check for errors by calling mic_map_error(..). | ||
204 | * | ||
205 | * returns DMA address as required by MIC. | ||
206 | */ | ||
207 | dma_addr_t mic_map(struct mic_device *mdev, dma_addr_t dma_addr, size_t size) | ||
208 | { | ||
209 | dma_addr_t mic_addr = 0; | ||
210 | int num_entries; | ||
211 | s64 *ref; | ||
212 | u64 smpt_start; | ||
213 | |||
214 | if (!size || size > mic_max_system_memory(mdev)) | ||
215 | return mic_addr; | ||
216 | |||
217 | ref = kmalloc(mdev->smpt->info.num_reg * sizeof(s64), GFP_KERNEL); | ||
218 | if (!ref) | ||
219 | return mic_addr; | ||
220 | |||
221 | num_entries = mic_get_smpt_ref_count(mdev, dma_addr, size, | ||
222 | ref, &smpt_start); | ||
223 | |||
224 | /* Set the smpt table appropriately and get 16G aligned mic address */ | ||
225 | mic_addr = mic_smpt_op(mdev, smpt_start, num_entries, ref, size); | ||
226 | |||
227 | kfree(ref); | ||
228 | |||
229 | /* | ||
230 | * If mic_addr is zero then its an error case | ||
231 | * since mic_addr can never be zero. | ||
232 | * else generate mic_addr by adding the 16G offset in dma_addr | ||
233 | */ | ||
234 | if (!mic_addr && MIC_FAMILY_X100 == mdev->family) { | ||
235 | dev_err(mdev->sdev->parent, | ||
236 | "mic_map failed dma_addr 0x%llx size 0x%lx\n", | ||
237 | dma_addr, size); | ||
238 | return mic_addr; | ||
239 | } else { | ||
240 | return mic_addr + mic_smpt_offset(mdev, dma_addr); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * mic_unmap - Unmaps a MIC physical address. | ||
246 | * | ||
247 | * @mdev: pointer to mic_device instance. | ||
248 | * @mic_addr: MIC physical address. | ||
249 | * @size: Size of the region to be unmapped. | ||
250 | * | ||
251 | * This API unmaps the mappings created by mic_map(..). | ||
252 | * | ||
253 | * returns None. | ||
254 | */ | ||
255 | void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) | ||
256 | { | ||
257 | struct mic_smpt_info *smpt_info = mdev->smpt; | ||
258 | s64 *ref; | ||
259 | int num_smpt; | ||
260 | int spt; | ||
261 | int i; | ||
262 | unsigned long flags; | ||
263 | |||
264 | if (!size) | ||
265 | return; | ||
266 | |||
267 | if (!mic_is_system_addr(mdev, mic_addr)) { | ||
268 | dev_err(mdev->sdev->parent, | ||
269 | "invalid address: 0x%llx\n", mic_addr); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | spt = mic_sys_addr_to_smpt(mdev, mic_addr); | ||
274 | ref = kmalloc(mdev->smpt->info.num_reg * sizeof(s64), GFP_KERNEL); | ||
275 | if (!ref) | ||
276 | return; | ||
277 | |||
278 | /* Get number of smpt entries to be mapped, ref count array */ | ||
279 | num_smpt = mic_get_smpt_ref_count(mdev, mic_addr, size, ref, NULL); | ||
280 | |||
281 | spin_lock_irqsave(&smpt_info->smpt_lock, flags); | ||
282 | smpt_info->unmap_count++; | ||
283 | smpt_info->ref_count -= (s64)size; | ||
284 | |||
285 | for (i = spt; i < spt + num_smpt; i++) { | ||
286 | smpt_info->entry[i].ref_count -= ref[i - spt]; | ||
287 | if (smpt_info->entry[i].ref_count < 0) | ||
288 | dev_warn(mdev->sdev->parent, | ||
289 | "ref count for entry %d is negative\n", i); | ||
290 | } | ||
291 | spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); | ||
292 | kfree(ref); | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * mic_map_single - Maps a virtual address to a MIC physical address. | ||
297 | * | ||
298 | * @mdev: pointer to mic_device instance. | ||
299 | * @va: Kernel direct mapped virtual address. | ||
300 | * @size: Size of the region to be mapped. | ||
301 | * | ||
302 | * This API calls pci_map_single(..) for the direct mapped virtual address | ||
303 | * and then converts the DMA address provided to a DMA address understood | ||
304 | * by MIC. Caller should check for errors by calling mic_map_error(..). | ||
305 | * | ||
306 | * returns DMA address as required by MIC. | ||
307 | */ | ||
308 | dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size) | ||
309 | { | ||
310 | dma_addr_t mic_addr = 0; | ||
311 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
312 | struct pci_dev, dev); | ||
313 | dma_addr_t dma_addr = | ||
314 | pci_map_single(pdev, va, size, PCI_DMA_BIDIRECTIONAL); | ||
315 | |||
316 | if (!pci_dma_mapping_error(pdev, dma_addr)) { | ||
317 | mic_addr = mic_map(mdev, dma_addr, size); | ||
318 | if (!mic_addr) { | ||
319 | dev_err(mdev->sdev->parent, | ||
320 | "mic_map failed dma_addr 0x%llx size 0x%lx\n", | ||
321 | dma_addr, size); | ||
322 | pci_unmap_single(pdev, dma_addr, | ||
323 | size, PCI_DMA_BIDIRECTIONAL); | ||
324 | } | ||
325 | } | ||
326 | return mic_addr; | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * mic_unmap_single - Unmaps a MIC physical address. | ||
331 | * | ||
332 | * @mdev: pointer to mic_device instance. | ||
333 | * @mic_addr: MIC physical address. | ||
334 | * @size: Size of the region to be unmapped. | ||
335 | * | ||
336 | * This API unmaps the mappings created by mic_map_single(..). | ||
337 | * | ||
338 | * returns None. | ||
339 | */ | ||
340 | void | ||
341 | mic_unmap_single(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) | ||
342 | { | ||
343 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
344 | struct pci_dev, dev); | ||
345 | dma_addr_t dma_addr = mic_to_dma_addr(mdev, mic_addr); | ||
346 | mic_unmap(mdev, mic_addr, size); | ||
347 | pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * mic_smpt_init - Initialize MIC System Memory Page Tables. | ||
352 | * | ||
353 | * @mdev: pointer to mic_device instance. | ||
354 | * | ||
355 | * returns 0 for success and -errno for error. | ||
356 | */ | ||
357 | int mic_smpt_init(struct mic_device *mdev) | ||
358 | { | ||
359 | int i, err = 0; | ||
360 | dma_addr_t dma_addr; | ||
361 | struct mic_smpt_info *smpt_info; | ||
362 | |||
363 | mdev->smpt = kmalloc(sizeof(*mdev->smpt), GFP_KERNEL); | ||
364 | if (!mdev->smpt) | ||
365 | return -ENOMEM; | ||
366 | |||
367 | smpt_info = mdev->smpt; | ||
368 | mdev->smpt_ops->init(mdev); | ||
369 | smpt_info->entry = kmalloc(sizeof(struct mic_smpt) | ||
370 | * smpt_info->info.num_reg, GFP_KERNEL); | ||
371 | if (!smpt_info->entry) { | ||
372 | err = -ENOMEM; | ||
373 | goto free_smpt; | ||
374 | } | ||
375 | spin_lock_init(&smpt_info->smpt_lock); | ||
376 | for (i = 0; i < smpt_info->info.num_reg; i++) { | ||
377 | dma_addr = i * smpt_info->info.page_size; | ||
378 | smpt_info->entry[i].dma_addr = dma_addr; | ||
379 | smpt_info->entry[i].ref_count = 0; | ||
380 | mdev->smpt_ops->set(mdev, dma_addr, i); | ||
381 | } | ||
382 | smpt_info->ref_count = 0; | ||
383 | smpt_info->map_count = 0; | ||
384 | smpt_info->unmap_count = 0; | ||
385 | return 0; | ||
386 | free_smpt: | ||
387 | kfree(smpt_info); | ||
388 | return err; | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * mic_smpt_uninit - UnInitialize MIC System Memory Page Tables. | ||
393 | * | ||
394 | * @mdev: pointer to mic_device instance. | ||
395 | * | ||
396 | * returns None. | ||
397 | */ | ||
398 | void mic_smpt_uninit(struct mic_device *mdev) | ||
399 | { | ||
400 | struct mic_smpt_info *smpt_info = mdev->smpt; | ||
401 | int i; | ||
402 | |||
403 | dev_dbg(mdev->sdev->parent, | ||
404 | "nodeid %d SMPT ref count %lld map %lld unmap %lld\n", | ||
405 | mdev->id, smpt_info->ref_count, | ||
406 | smpt_info->map_count, smpt_info->unmap_count); | ||
407 | |||
408 | for (i = 0; i < smpt_info->info.num_reg; i++) { | ||
409 | dev_dbg(mdev->sdev->parent, | ||
410 | "SMPT entry[%d] dma_addr = 0x%llx ref_count = %lld\n", | ||
411 | i, smpt_info->entry[i].dma_addr, | ||
412 | smpt_info->entry[i].ref_count); | ||
413 | if (smpt_info->entry[i].ref_count) | ||
414 | dev_warn(mdev->sdev->parent, | ||
415 | "ref count for entry %d is not zero\n", i); | ||
416 | } | ||
417 | kfree(smpt_info->entry); | ||
418 | kfree(smpt_info); | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * mic_smpt_restore - Restore MIC System Memory Page Tables. | ||
423 | * | ||
424 | * @mdev: pointer to mic_device instance. | ||
425 | * | ||
426 | * Restore the SMPT registers to values previously stored in the | ||
427 | * SW data structures. Some MIC steppings lose register state | ||
428 | * across resets and this API should be called for performing | ||
429 | * a restore operation if required. | ||
430 | * | ||
431 | * returns None. | ||
432 | */ | ||
433 | void mic_smpt_restore(struct mic_device *mdev) | ||
434 | { | ||
435 | int i; | ||
436 | dma_addr_t dma_addr; | ||
437 | |||
438 | for (i = 0; i < mdev->smpt->info.num_reg; i++) { | ||
439 | dma_addr = mdev->smpt->entry[i].dma_addr; | ||
440 | mdev->smpt_ops->set(mdev, dma_addr, i); | ||
441 | } | ||
442 | } | ||
diff --git a/drivers/misc/mic/host/mic_smpt.h b/drivers/misc/mic/host/mic_smpt.h new file mode 100644 index 000000000000..51970abfe7df --- /dev/null +++ b/drivers/misc/mic/host/mic_smpt.h | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #ifndef MIC_SMPT_H | ||
22 | #define MIC_SMPT_H | ||
23 | /** | ||
24 | * struct mic_smpt_ops - MIC HW specific SMPT operations. | ||
25 | * @init: Initialize hardware specific SMPT information in mic_smpt_hw_info. | ||
26 | * @set: Set the value for a particular SMPT entry. | ||
27 | */ | ||
28 | struct mic_smpt_ops { | ||
29 | void (*init)(struct mic_device *mdev); | ||
30 | void (*set)(struct mic_device *mdev, dma_addr_t dma_addr, u8 index); | ||
31 | }; | ||
32 | |||
33 | /** | ||
34 | * struct mic_smpt - MIC SMPT entry information. | ||
35 | * @dma_addr: Base DMA address for this SMPT entry. | ||
36 | * @ref_count: Number of active mappings for this SMPT entry in bytes. | ||
37 | */ | ||
38 | struct mic_smpt { | ||
39 | dma_addr_t dma_addr; | ||
40 | s64 ref_count; | ||
41 | }; | ||
42 | |||
43 | /** | ||
44 | * struct mic_smpt_hw_info - MIC SMPT hardware specific information. | ||
45 | * @num_reg: Number of SMPT registers. | ||
46 | * @page_shift: System memory page shift. | ||
47 | * @page_size: System memory page size. | ||
48 | * @base: System address base. | ||
49 | */ | ||
50 | struct mic_smpt_hw_info { | ||
51 | u8 num_reg; | ||
52 | u8 page_shift; | ||
53 | u64 page_size; | ||
54 | u64 base; | ||
55 | }; | ||
56 | |||
57 | /** | ||
58 | * struct mic_smpt_info - MIC SMPT information. | ||
59 | * @entry: Array of SMPT entries. | ||
60 | * @smpt_lock: Spin lock protecting access to SMPT data structures. | ||
61 | * @info: Hardware specific SMPT information. | ||
62 | * @ref_count: Number of active SMPT mappings (for debug). | ||
63 | * @map_count: Number of SMPT mappings created (for debug). | ||
64 | * @unmap_count: Number of SMPT mappings destroyed (for debug). | ||
65 | */ | ||
66 | struct mic_smpt_info { | ||
67 | struct mic_smpt *entry; | ||
68 | spinlock_t smpt_lock; | ||
69 | struct mic_smpt_hw_info info; | ||
70 | s64 ref_count; | ||
71 | s64 map_count; | ||
72 | s64 unmap_count; | ||
73 | }; | ||
74 | |||
75 | dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size); | ||
76 | void mic_unmap_single(struct mic_device *mdev, | ||
77 | dma_addr_t mic_addr, size_t size); | ||
78 | dma_addr_t mic_map(struct mic_device *mdev, | ||
79 | dma_addr_t dma_addr, size_t size); | ||
80 | void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size); | ||
81 | |||
82 | /** | ||
83 | * mic_map_error - Check a MIC address for errors. | ||
84 | * | ||
85 | * @mdev: pointer to mic_device instance. | ||
86 | * | ||
87 | * returns Whether there was an error during mic_map..(..) APIs. | ||
88 | */ | ||
89 | static inline bool mic_map_error(dma_addr_t mic_addr) | ||
90 | { | ||
91 | return !mic_addr; | ||
92 | } | ||
93 | |||
94 | int mic_smpt_init(struct mic_device *mdev); | ||
95 | void mic_smpt_uninit(struct mic_device *mdev); | ||
96 | void mic_smpt_restore(struct mic_device *mdev); | ||
97 | |||
98 | #endif | ||
diff --git a/drivers/misc/mic/host/mic_sysfs.c b/drivers/misc/mic/host/mic_sysfs.c new file mode 100644 index 000000000000..aaf849945111 --- /dev/null +++ b/drivers/misc/mic/host/mic_sysfs.c | |||
@@ -0,0 +1,466 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/pci.h> | ||
22 | |||
23 | #include <linux/mic_common.h> | ||
24 | #include "../common/mic_device.h" | ||
25 | #include "mic_device.h" | ||
26 | |||
27 | /* | ||
28 | * A state-to-string lookup table, for exposing a human readable state | ||
29 | * via sysfs. Always keep in sync with enum mic_states | ||
30 | */ | ||
31 | static const char * const mic_state_string[] = { | ||
32 | [MIC_OFFLINE] = "offline", | ||
33 | [MIC_ONLINE] = "online", | ||
34 | [MIC_SHUTTING_DOWN] = "shutting_down", | ||
35 | [MIC_RESET_FAILED] = "reset_failed", | ||
36 | }; | ||
37 | |||
38 | /* | ||
39 | * A shutdown-status-to-string lookup table, for exposing a human | ||
40 | * readable state via sysfs. Always keep in sync with enum mic_shutdown_status | ||
41 | */ | ||
42 | static const char * const mic_shutdown_status_string[] = { | ||
43 | [MIC_NOP] = "nop", | ||
44 | [MIC_CRASHED] = "crashed", | ||
45 | [MIC_HALTED] = "halted", | ||
46 | [MIC_POWER_OFF] = "poweroff", | ||
47 | [MIC_RESTART] = "restart", | ||
48 | }; | ||
49 | |||
50 | void mic_set_shutdown_status(struct mic_device *mdev, u8 shutdown_status) | ||
51 | { | ||
52 | dev_dbg(mdev->sdev->parent, "Shutdown Status %s -> %s\n", | ||
53 | mic_shutdown_status_string[mdev->shutdown_status], | ||
54 | mic_shutdown_status_string[shutdown_status]); | ||
55 | mdev->shutdown_status = shutdown_status; | ||
56 | } | ||
57 | |||
58 | void mic_set_state(struct mic_device *mdev, u8 state) | ||
59 | { | ||
60 | dev_dbg(mdev->sdev->parent, "State %s -> %s\n", | ||
61 | mic_state_string[mdev->state], | ||
62 | mic_state_string[state]); | ||
63 | mdev->state = state; | ||
64 | sysfs_notify_dirent(mdev->state_sysfs); | ||
65 | } | ||
66 | |||
67 | static ssize_t | ||
68 | mic_show_family(struct device *dev, struct device_attribute *attr, char *buf) | ||
69 | { | ||
70 | static const char x100[] = "x100"; | ||
71 | static const char unknown[] = "Unknown"; | ||
72 | const char *card = NULL; | ||
73 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
74 | |||
75 | if (!mdev) | ||
76 | return -EINVAL; | ||
77 | |||
78 | switch (mdev->family) { | ||
79 | case MIC_FAMILY_X100: | ||
80 | card = x100; | ||
81 | break; | ||
82 | default: | ||
83 | card = unknown; | ||
84 | break; | ||
85 | } | ||
86 | return scnprintf(buf, PAGE_SIZE, "%s\n", card); | ||
87 | } | ||
88 | static DEVICE_ATTR(family, S_IRUGO, mic_show_family, NULL); | ||
89 | |||
90 | static ssize_t | ||
91 | mic_show_stepping(struct device *dev, struct device_attribute *attr, char *buf) | ||
92 | { | ||
93 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
94 | char *string = "??"; | ||
95 | |||
96 | if (!mdev) | ||
97 | return -EINVAL; | ||
98 | |||
99 | switch (mdev->stepping) { | ||
100 | case MIC_A0_STEP: | ||
101 | string = "A0"; | ||
102 | break; | ||
103 | case MIC_B0_STEP: | ||
104 | string = "B0"; | ||
105 | break; | ||
106 | case MIC_B1_STEP: | ||
107 | string = "B1"; | ||
108 | break; | ||
109 | case MIC_C0_STEP: | ||
110 | string = "C0"; | ||
111 | break; | ||
112 | default: | ||
113 | break; | ||
114 | } | ||
115 | return scnprintf(buf, PAGE_SIZE, "%s\n", string); | ||
116 | } | ||
117 | static DEVICE_ATTR(stepping, S_IRUGO, mic_show_stepping, NULL); | ||
118 | |||
119 | static ssize_t | ||
120 | mic_show_state(struct device *dev, struct device_attribute *attr, char *buf) | ||
121 | { | ||
122 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
123 | |||
124 | if (!mdev || mdev->state >= MIC_LAST) | ||
125 | return -EINVAL; | ||
126 | |||
127 | return scnprintf(buf, PAGE_SIZE, "%s\n", | ||
128 | mic_state_string[mdev->state]); | ||
129 | } | ||
130 | |||
131 | static ssize_t | ||
132 | mic_store_state(struct device *dev, struct device_attribute *attr, | ||
133 | const char *buf, size_t count) | ||
134 | { | ||
135 | int rc = 0; | ||
136 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
137 | if (!mdev) | ||
138 | return -EINVAL; | ||
139 | if (sysfs_streq(buf, "boot")) { | ||
140 | rc = mic_start(mdev, buf); | ||
141 | if (rc) { | ||
142 | dev_err(mdev->sdev->parent, | ||
143 | "mic_boot failed rc %d\n", rc); | ||
144 | count = rc; | ||
145 | } | ||
146 | goto done; | ||
147 | } | ||
148 | |||
149 | if (sysfs_streq(buf, "reset")) { | ||
150 | schedule_work(&mdev->reset_trigger_work); | ||
151 | goto done; | ||
152 | } | ||
153 | |||
154 | if (sysfs_streq(buf, "shutdown")) { | ||
155 | mic_shutdown(mdev); | ||
156 | goto done; | ||
157 | } | ||
158 | |||
159 | count = -EINVAL; | ||
160 | done: | ||
161 | return count; | ||
162 | } | ||
163 | static DEVICE_ATTR(state, S_IRUGO|S_IWUSR, mic_show_state, mic_store_state); | ||
164 | |||
165 | static ssize_t mic_show_shutdown_status(struct device *dev, | ||
166 | struct device_attribute *attr, char *buf) | ||
167 | { | ||
168 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
169 | |||
170 | if (!mdev || mdev->shutdown_status >= MIC_STATUS_LAST) | ||
171 | return -EINVAL; | ||
172 | |||
173 | return scnprintf(buf, PAGE_SIZE, "%s\n", | ||
174 | mic_shutdown_status_string[mdev->shutdown_status]); | ||
175 | } | ||
176 | static DEVICE_ATTR(shutdown_status, S_IRUGO|S_IWUSR, | ||
177 | mic_show_shutdown_status, NULL); | ||
178 | |||
179 | static ssize_t | ||
180 | mic_show_cmdline(struct device *dev, struct device_attribute *attr, char *buf) | ||
181 | { | ||
182 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
183 | char *cmdline; | ||
184 | |||
185 | if (!mdev) | ||
186 | return -EINVAL; | ||
187 | |||
188 | cmdline = mdev->cmdline; | ||
189 | |||
190 | if (cmdline) | ||
191 | return scnprintf(buf, PAGE_SIZE, "%s\n", cmdline); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static ssize_t | ||
196 | mic_store_cmdline(struct device *dev, struct device_attribute *attr, | ||
197 | const char *buf, size_t count) | ||
198 | { | ||
199 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
200 | |||
201 | if (!mdev) | ||
202 | return -EINVAL; | ||
203 | |||
204 | mutex_lock(&mdev->mic_mutex); | ||
205 | kfree(mdev->cmdline); | ||
206 | |||
207 | mdev->cmdline = kmalloc(count + 1, GFP_KERNEL); | ||
208 | if (!mdev->cmdline) { | ||
209 | count = -ENOMEM; | ||
210 | goto unlock; | ||
211 | } | ||
212 | |||
213 | strncpy(mdev->cmdline, buf, count); | ||
214 | |||
215 | if (mdev->cmdline[count - 1] == '\n') | ||
216 | mdev->cmdline[count - 1] = '\0'; | ||
217 | else | ||
218 | mdev->cmdline[count] = '\0'; | ||
219 | unlock: | ||
220 | mutex_unlock(&mdev->mic_mutex); | ||
221 | return count; | ||
222 | } | ||
223 | static DEVICE_ATTR(cmdline, S_IRUGO | S_IWUSR, | ||
224 | mic_show_cmdline, mic_store_cmdline); | ||
225 | |||
226 | static ssize_t | ||
227 | mic_show_firmware(struct device *dev, struct device_attribute *attr, char *buf) | ||
228 | { | ||
229 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
230 | char *firmware; | ||
231 | |||
232 | if (!mdev) | ||
233 | return -EINVAL; | ||
234 | |||
235 | firmware = mdev->firmware; | ||
236 | |||
237 | if (firmware) | ||
238 | return scnprintf(buf, PAGE_SIZE, "%s\n", firmware); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static ssize_t | ||
243 | mic_store_firmware(struct device *dev, struct device_attribute *attr, | ||
244 | const char *buf, size_t count) | ||
245 | { | ||
246 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
247 | |||
248 | if (!mdev) | ||
249 | return -EINVAL; | ||
250 | |||
251 | mutex_lock(&mdev->mic_mutex); | ||
252 | kfree(mdev->firmware); | ||
253 | |||
254 | mdev->firmware = kmalloc(count + 1, GFP_KERNEL); | ||
255 | if (!mdev->firmware) { | ||
256 | count = -ENOMEM; | ||
257 | goto unlock; | ||
258 | } | ||
259 | strncpy(mdev->firmware, buf, count); | ||
260 | |||
261 | if (mdev->firmware[count - 1] == '\n') | ||
262 | mdev->firmware[count - 1] = '\0'; | ||
263 | else | ||
264 | mdev->firmware[count] = '\0'; | ||
265 | unlock: | ||
266 | mutex_unlock(&mdev->mic_mutex); | ||
267 | return count; | ||
268 | } | ||
269 | static DEVICE_ATTR(firmware, S_IRUGO | S_IWUSR, | ||
270 | mic_show_firmware, mic_store_firmware); | ||
271 | |||
272 | static ssize_t | ||
273 | mic_show_ramdisk(struct device *dev, struct device_attribute *attr, char *buf) | ||
274 | { | ||
275 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
276 | char *ramdisk; | ||
277 | |||
278 | if (!mdev) | ||
279 | return -EINVAL; | ||
280 | |||
281 | ramdisk = mdev->ramdisk; | ||
282 | |||
283 | if (ramdisk) | ||
284 | return scnprintf(buf, PAGE_SIZE, "%s\n", ramdisk); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static ssize_t | ||
289 | mic_store_ramdisk(struct device *dev, struct device_attribute *attr, | ||
290 | const char *buf, size_t count) | ||
291 | { | ||
292 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
293 | |||
294 | if (!mdev) | ||
295 | return -EINVAL; | ||
296 | |||
297 | mutex_lock(&mdev->mic_mutex); | ||
298 | kfree(mdev->ramdisk); | ||
299 | |||
300 | mdev->ramdisk = kmalloc(count + 1, GFP_KERNEL); | ||
301 | if (!mdev->ramdisk) { | ||
302 | count = -ENOMEM; | ||
303 | goto unlock; | ||
304 | } | ||
305 | |||
306 | strncpy(mdev->ramdisk, buf, count); | ||
307 | |||
308 | if (mdev->ramdisk[count - 1] == '\n') | ||
309 | mdev->ramdisk[count - 1] = '\0'; | ||
310 | else | ||
311 | mdev->ramdisk[count] = '\0'; | ||
312 | unlock: | ||
313 | mutex_unlock(&mdev->mic_mutex); | ||
314 | return count; | ||
315 | } | ||
316 | static DEVICE_ATTR(ramdisk, S_IRUGO | S_IWUSR, | ||
317 | mic_show_ramdisk, mic_store_ramdisk); | ||
318 | |||
319 | static ssize_t | ||
320 | mic_show_bootmode(struct device *dev, struct device_attribute *attr, char *buf) | ||
321 | { | ||
322 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
323 | char *bootmode; | ||
324 | |||
325 | if (!mdev) | ||
326 | return -EINVAL; | ||
327 | |||
328 | bootmode = mdev->bootmode; | ||
329 | |||
330 | if (bootmode) | ||
331 | return scnprintf(buf, PAGE_SIZE, "%s\n", bootmode); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static ssize_t | ||
336 | mic_store_bootmode(struct device *dev, struct device_attribute *attr, | ||
337 | const char *buf, size_t count) | ||
338 | { | ||
339 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
340 | |||
341 | if (!mdev) | ||
342 | return -EINVAL; | ||
343 | |||
344 | if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "elf")) | ||
345 | return -EINVAL; | ||
346 | |||
347 | mutex_lock(&mdev->mic_mutex); | ||
348 | kfree(mdev->bootmode); | ||
349 | |||
350 | mdev->bootmode = kmalloc(count + 1, GFP_KERNEL); | ||
351 | if (!mdev->bootmode) { | ||
352 | count = -ENOMEM; | ||
353 | goto unlock; | ||
354 | } | ||
355 | |||
356 | strncpy(mdev->bootmode, buf, count); | ||
357 | |||
358 | if (mdev->bootmode[count - 1] == '\n') | ||
359 | mdev->bootmode[count - 1] = '\0'; | ||
360 | else | ||
361 | mdev->bootmode[count] = '\0'; | ||
362 | unlock: | ||
363 | mutex_unlock(&mdev->mic_mutex); | ||
364 | return count; | ||
365 | } | ||
366 | static DEVICE_ATTR(bootmode, S_IRUGO | S_IWUSR, | ||
367 | mic_show_bootmode, mic_store_bootmode); | ||
368 | |||
369 | static ssize_t | ||
370 | mic_show_log_buf_addr(struct device *dev, struct device_attribute *attr, | ||
371 | char *buf) | ||
372 | { | ||
373 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
374 | |||
375 | if (!mdev) | ||
376 | return -EINVAL; | ||
377 | |||
378 | return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_addr); | ||
379 | } | ||
380 | |||
381 | static ssize_t | ||
382 | mic_store_log_buf_addr(struct device *dev, struct device_attribute *attr, | ||
383 | const char *buf, size_t count) | ||
384 | { | ||
385 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
386 | int ret; | ||
387 | unsigned long addr; | ||
388 | |||
389 | if (!mdev) | ||
390 | return -EINVAL; | ||
391 | |||
392 | ret = kstrtoul(buf, 16, &addr); | ||
393 | if (ret) | ||
394 | goto exit; | ||
395 | |||
396 | mdev->log_buf_addr = (void *)addr; | ||
397 | ret = count; | ||
398 | exit: | ||
399 | return ret; | ||
400 | } | ||
401 | static DEVICE_ATTR(log_buf_addr, S_IRUGO | S_IWUSR, | ||
402 | mic_show_log_buf_addr, mic_store_log_buf_addr); | ||
403 | |||
404 | static ssize_t | ||
405 | mic_show_log_buf_len(struct device *dev, struct device_attribute *attr, | ||
406 | char *buf) | ||
407 | { | ||
408 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
409 | |||
410 | if (!mdev) | ||
411 | return -EINVAL; | ||
412 | |||
413 | return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_len); | ||
414 | } | ||
415 | |||
416 | static ssize_t | ||
417 | mic_store_log_buf_len(struct device *dev, struct device_attribute *attr, | ||
418 | const char *buf, size_t count) | ||
419 | { | ||
420 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
421 | int ret; | ||
422 | unsigned long addr; | ||
423 | |||
424 | if (!mdev) | ||
425 | return -EINVAL; | ||
426 | |||
427 | ret = kstrtoul(buf, 16, &addr); | ||
428 | if (ret) | ||
429 | goto exit; | ||
430 | |||
431 | mdev->log_buf_len = (int *)addr; | ||
432 | ret = count; | ||
433 | exit: | ||
434 | return ret; | ||
435 | } | ||
436 | static DEVICE_ATTR(log_buf_len, S_IRUGO | S_IWUSR, | ||
437 | mic_show_log_buf_len, mic_store_log_buf_len); | ||
438 | |||
439 | static struct attribute *mic_default_attrs[] = { | ||
440 | &dev_attr_family.attr, | ||
441 | &dev_attr_stepping.attr, | ||
442 | &dev_attr_state.attr, | ||
443 | &dev_attr_shutdown_status.attr, | ||
444 | &dev_attr_cmdline.attr, | ||
445 | &dev_attr_firmware.attr, | ||
446 | &dev_attr_ramdisk.attr, | ||
447 | &dev_attr_bootmode.attr, | ||
448 | &dev_attr_log_buf_addr.attr, | ||
449 | &dev_attr_log_buf_len.attr, | ||
450 | |||
451 | NULL | ||
452 | }; | ||
453 | |||
454 | static struct attribute_group mic_attr_group = { | ||
455 | .attrs = mic_default_attrs, | ||
456 | }; | ||
457 | |||
458 | static const struct attribute_group *__mic_attr_group[] = { | ||
459 | &mic_attr_group, | ||
460 | NULL | ||
461 | }; | ||
462 | |||
463 | void mic_sysfs_init(struct mic_device *mdev) | ||
464 | { | ||
465 | mdev->attr_group = __mic_attr_group; | ||
466 | } | ||
diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c new file mode 100644 index 000000000000..be2a1f06c4ca --- /dev/null +++ b/drivers/misc/mic/host/mic_virtio.c | |||
@@ -0,0 +1,703 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | |||
25 | #include <linux/mic_common.h> | ||
26 | #include "../common/mic_device.h" | ||
27 | #include "mic_device.h" | ||
28 | #include "mic_smpt.h" | ||
29 | #include "mic_virtio.h" | ||
30 | |||
31 | /* | ||
32 | * Initiates the copies across the PCIe bus from card memory to | ||
33 | * a user space buffer. | ||
34 | */ | ||
35 | static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, | ||
36 | void __user *ubuf, size_t len, u64 addr) | ||
37 | { | ||
38 | int err; | ||
39 | void __iomem *dbuf = mvdev->mdev->aper.va + addr; | ||
40 | /* | ||
41 | * We are copying from IO below an should ideally use something | ||
42 | * like copy_to_user_fromio(..) if it existed. | ||
43 | */ | ||
44 | if (copy_to_user(ubuf, dbuf, len)) { | ||
45 | err = -EFAULT; | ||
46 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
47 | __func__, __LINE__, err); | ||
48 | goto err; | ||
49 | } | ||
50 | mvdev->in_bytes += len; | ||
51 | err = 0; | ||
52 | err: | ||
53 | return err; | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Initiates copies across the PCIe bus from a user space | ||
58 | * buffer to card memory. | ||
59 | */ | ||
60 | static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, | ||
61 | void __user *ubuf, size_t len, u64 addr) | ||
62 | { | ||
63 | int err; | ||
64 | void __iomem *dbuf = mvdev->mdev->aper.va + addr; | ||
65 | /* | ||
66 | * We are copying to IO below and should ideally use something | ||
67 | * like copy_from_user_toio(..) if it existed. | ||
68 | */ | ||
69 | if (copy_from_user(dbuf, ubuf, len)) { | ||
70 | err = -EFAULT; | ||
71 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
72 | __func__, __LINE__, err); | ||
73 | goto err; | ||
74 | } | ||
75 | mvdev->out_bytes += len; | ||
76 | err = 0; | ||
77 | err: | ||
78 | return err; | ||
79 | } | ||
80 | |||
81 | #define MIC_VRINGH_READ true | ||
82 | |||
83 | /* The function to call to notify the card about added buffers */ | ||
84 | static void mic_notify(struct vringh *vrh) | ||
85 | { | ||
86 | struct mic_vringh *mvrh = container_of(vrh, struct mic_vringh, vrh); | ||
87 | struct mic_vdev *mvdev = mvrh->mvdev; | ||
88 | s8 db = mvdev->dc->h2c_vdev_db; | ||
89 | |||
90 | if (db != -1) | ||
91 | mvdev->mdev->ops->send_intr(mvdev->mdev, db); | ||
92 | } | ||
93 | |||
94 | /* Determine the total number of bytes consumed in a VRINGH KIOV */ | ||
95 | static inline u32 mic_vringh_iov_consumed(struct vringh_kiov *iov) | ||
96 | { | ||
97 | int i; | ||
98 | u32 total = iov->consumed; | ||
99 | |||
100 | for (i = 0; i < iov->i; i++) | ||
101 | total += iov->iov[i].iov_len; | ||
102 | return total; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Traverse the VRINGH KIOV and issue the APIs to trigger the copies. | ||
107 | * This API is heavily based on the vringh_iov_xfer(..) implementation | ||
108 | * in vringh.c. The reason we cannot reuse vringh_iov_pull_kern(..) | ||
109 | * and vringh_iov_push_kern(..) directly is because there is no | ||
110 | * way to override the VRINGH xfer(..) routines as of v3.10. | ||
111 | */ | ||
112 | static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, | ||
113 | void __user *ubuf, size_t len, bool read, size_t *out_len) | ||
114 | { | ||
115 | int ret = 0; | ||
116 | size_t partlen, tot_len = 0; | ||
117 | |||
118 | while (len && iov->i < iov->used) { | ||
119 | partlen = min(iov->iov[iov->i].iov_len, len); | ||
120 | if (read) | ||
121 | ret = mic_virtio_copy_to_user(mvdev, | ||
122 | ubuf, partlen, | ||
123 | (u64)iov->iov[iov->i].iov_base); | ||
124 | else | ||
125 | ret = mic_virtio_copy_from_user(mvdev, | ||
126 | ubuf, partlen, | ||
127 | (u64)iov->iov[iov->i].iov_base); | ||
128 | if (ret) { | ||
129 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
130 | __func__, __LINE__, ret); | ||
131 | break; | ||
132 | } | ||
133 | len -= partlen; | ||
134 | ubuf += partlen; | ||
135 | tot_len += partlen; | ||
136 | iov->consumed += partlen; | ||
137 | iov->iov[iov->i].iov_len -= partlen; | ||
138 | iov->iov[iov->i].iov_base += partlen; | ||
139 | if (!iov->iov[iov->i].iov_len) { | ||
140 | /* Fix up old iov element then increment. */ | ||
141 | iov->iov[iov->i].iov_len = iov->consumed; | ||
142 | iov->iov[iov->i].iov_base -= iov->consumed; | ||
143 | |||
144 | iov->consumed = 0; | ||
145 | iov->i++; | ||
146 | } | ||
147 | } | ||
148 | *out_len = tot_len; | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Use the standard VRINGH infrastructure in the kernel to fetch new | ||
154 | * descriptors, initiate the copies and update the used ring. | ||
155 | */ | ||
156 | static int _mic_virtio_copy(struct mic_vdev *mvdev, | ||
157 | struct mic_copy_desc *copy) | ||
158 | { | ||
159 | int ret = 0, iovcnt = copy->iovcnt; | ||
160 | struct iovec iov; | ||
161 | struct iovec __user *u_iov = copy->iov; | ||
162 | void __user *ubuf = NULL; | ||
163 | struct mic_vringh *mvr = &mvdev->mvr[copy->vr_idx]; | ||
164 | struct vringh_kiov *riov = &mvr->riov; | ||
165 | struct vringh_kiov *wiov = &mvr->wiov; | ||
166 | struct vringh *vrh = &mvr->vrh; | ||
167 | u16 *head = &mvr->head; | ||
168 | struct mic_vring *vr = &mvr->vring; | ||
169 | size_t len = 0, out_len; | ||
170 | |||
171 | copy->out_len = 0; | ||
172 | /* Fetch a new IOVEC if all previous elements have been processed */ | ||
173 | if (riov->i == riov->used && wiov->i == wiov->used) { | ||
174 | ret = vringh_getdesc_kern(vrh, riov, wiov, | ||
175 | head, GFP_KERNEL); | ||
176 | /* Check if there are available descriptors */ | ||
177 | if (ret <= 0) | ||
178 | return ret; | ||
179 | } | ||
180 | while (iovcnt) { | ||
181 | if (!len) { | ||
182 | /* Copy over a new iovec from user space. */ | ||
183 | ret = copy_from_user(&iov, u_iov, sizeof(*u_iov)); | ||
184 | if (ret) { | ||
185 | ret = -EINVAL; | ||
186 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
187 | __func__, __LINE__, ret); | ||
188 | break; | ||
189 | } | ||
190 | len = iov.iov_len; | ||
191 | ubuf = iov.iov_base; | ||
192 | } | ||
193 | /* Issue all the read descriptors first */ | ||
194 | ret = mic_vringh_copy(mvdev, riov, ubuf, len, | ||
195 | MIC_VRINGH_READ, &out_len); | ||
196 | if (ret) { | ||
197 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
198 | __func__, __LINE__, ret); | ||
199 | break; | ||
200 | } | ||
201 | len -= out_len; | ||
202 | ubuf += out_len; | ||
203 | copy->out_len += out_len; | ||
204 | /* Issue the write descriptors next */ | ||
205 | ret = mic_vringh_copy(mvdev, wiov, ubuf, len, | ||
206 | !MIC_VRINGH_READ, &out_len); | ||
207 | if (ret) { | ||
208 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
209 | __func__, __LINE__, ret); | ||
210 | break; | ||
211 | } | ||
212 | len -= out_len; | ||
213 | ubuf += out_len; | ||
214 | copy->out_len += out_len; | ||
215 | if (!len) { | ||
216 | /* One user space iovec is now completed */ | ||
217 | iovcnt--; | ||
218 | u_iov++; | ||
219 | } | ||
220 | /* Exit loop if all elements in KIOVs have been processed. */ | ||
221 | if (riov->i == riov->used && wiov->i == wiov->used) | ||
222 | break; | ||
223 | } | ||
224 | /* | ||
225 | * Update the used ring if a descriptor was available and some data was | ||
226 | * copied in/out and the user asked for a used ring update. | ||
227 | */ | ||
228 | if (*head != USHRT_MAX && copy->out_len && | ||
229 | copy->update_used) { | ||
230 | u32 total = 0; | ||
231 | |||
232 | /* Determine the total data consumed */ | ||
233 | total += mic_vringh_iov_consumed(riov); | ||
234 | total += mic_vringh_iov_consumed(wiov); | ||
235 | vringh_complete_kern(vrh, *head, total); | ||
236 | *head = USHRT_MAX; | ||
237 | if (vringh_need_notify_kern(vrh) > 0) | ||
238 | vringh_notify(vrh); | ||
239 | vringh_kiov_cleanup(riov); | ||
240 | vringh_kiov_cleanup(wiov); | ||
241 | /* Update avail idx for user space */ | ||
242 | vr->info->avail_idx = vrh->last_avail_idx; | ||
243 | } | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | static inline int mic_verify_copy_args(struct mic_vdev *mvdev, | ||
248 | struct mic_copy_desc *copy) | ||
249 | { | ||
250 | if (copy->vr_idx >= mvdev->dd->num_vq) { | ||
251 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
252 | __func__, __LINE__, -EINVAL); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* Copy a specified number of virtio descriptors in a chain */ | ||
259 | int mic_virtio_copy_desc(struct mic_vdev *mvdev, | ||
260 | struct mic_copy_desc *copy) | ||
261 | { | ||
262 | int err; | ||
263 | struct mic_vringh *mvr = &mvdev->mvr[copy->vr_idx]; | ||
264 | |||
265 | err = mic_verify_copy_args(mvdev, copy); | ||
266 | if (err) | ||
267 | return err; | ||
268 | |||
269 | mutex_lock(&mvr->vr_mutex); | ||
270 | if (!mic_vdevup(mvdev)) { | ||
271 | err = -ENODEV; | ||
272 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
273 | __func__, __LINE__, err); | ||
274 | goto err; | ||
275 | } | ||
276 | err = _mic_virtio_copy(mvdev, copy); | ||
277 | if (err) { | ||
278 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
279 | __func__, __LINE__, err); | ||
280 | } | ||
281 | err: | ||
282 | mutex_unlock(&mvr->vr_mutex); | ||
283 | return err; | ||
284 | } | ||
285 | |||
286 | static void mic_virtio_init_post(struct mic_vdev *mvdev) | ||
287 | { | ||
288 | struct mic_vqconfig *vqconfig = mic_vq_config(mvdev->dd); | ||
289 | int i; | ||
290 | |||
291 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
292 | if (!le64_to_cpu(vqconfig[i].used_address)) { | ||
293 | dev_warn(mic_dev(mvdev), "used_address zero??\n"); | ||
294 | continue; | ||
295 | } | ||
296 | mvdev->mvr[i].vrh.vring.used = | ||
297 | mvdev->mdev->aper.va + | ||
298 | le64_to_cpu(vqconfig[i].used_address); | ||
299 | } | ||
300 | |||
301 | mvdev->dc->used_address_updated = 0; | ||
302 | |||
303 | dev_dbg(mic_dev(mvdev), "%s: device type %d LINKUP\n", | ||
304 | __func__, mvdev->virtio_id); | ||
305 | } | ||
306 | |||
307 | static inline void mic_virtio_device_reset(struct mic_vdev *mvdev) | ||
308 | { | ||
309 | int i; | ||
310 | |||
311 | dev_dbg(mic_dev(mvdev), "%s: status %d device type %d RESET\n", | ||
312 | __func__, mvdev->dd->status, mvdev->virtio_id); | ||
313 | |||
314 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
315 | /* | ||
316 | * Avoid lockdep false positive. The + 1 is for the mic | ||
317 | * mutex which is held in the reset devices code path. | ||
318 | */ | ||
319 | mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1); | ||
320 | |||
321 | /* 0 status means "reset" */ | ||
322 | mvdev->dd->status = 0; | ||
323 | mvdev->dc->vdev_reset = 0; | ||
324 | mvdev->dc->host_ack = 1; | ||
325 | |||
326 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
327 | struct vringh *vrh = &mvdev->mvr[i].vrh; | ||
328 | mvdev->mvr[i].vring.info->avail_idx = 0; | ||
329 | vrh->completed = 0; | ||
330 | vrh->last_avail_idx = 0; | ||
331 | vrh->last_used_idx = 0; | ||
332 | } | ||
333 | |||
334 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
335 | mutex_unlock(&mvdev->mvr[i].vr_mutex); | ||
336 | } | ||
337 | |||
338 | void mic_virtio_reset_devices(struct mic_device *mdev) | ||
339 | { | ||
340 | struct list_head *pos, *tmp; | ||
341 | struct mic_vdev *mvdev; | ||
342 | |||
343 | dev_dbg(mdev->sdev->parent, "%s\n", __func__); | ||
344 | |||
345 | list_for_each_safe(pos, tmp, &mdev->vdev_list) { | ||
346 | mvdev = list_entry(pos, struct mic_vdev, list); | ||
347 | mic_virtio_device_reset(mvdev); | ||
348 | mvdev->poll_wake = 1; | ||
349 | wake_up(&mvdev->waitq); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | void mic_bh_handler(struct work_struct *work) | ||
354 | { | ||
355 | struct mic_vdev *mvdev = container_of(work, struct mic_vdev, | ||
356 | virtio_bh_work); | ||
357 | |||
358 | if (mvdev->dc->used_address_updated) | ||
359 | mic_virtio_init_post(mvdev); | ||
360 | |||
361 | if (mvdev->dc->vdev_reset) | ||
362 | mic_virtio_device_reset(mvdev); | ||
363 | |||
364 | mvdev->poll_wake = 1; | ||
365 | wake_up(&mvdev->waitq); | ||
366 | } | ||
367 | |||
368 | static irqreturn_t mic_virtio_intr_handler(int irq, void *data) | ||
369 | { | ||
370 | |||
371 | struct mic_vdev *mvdev = data; | ||
372 | struct mic_device *mdev = mvdev->mdev; | ||
373 | |||
374 | mdev->ops->ack_interrupt(mdev); | ||
375 | schedule_work(&mvdev->virtio_bh_work); | ||
376 | return IRQ_HANDLED; | ||
377 | } | ||
378 | |||
379 | int mic_virtio_config_change(struct mic_vdev *mvdev, | ||
380 | void __user *argp) | ||
381 | { | ||
382 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); | ||
383 | int ret = 0, retry = 100, i; | ||
384 | struct mic_bootparam *bootparam = mvdev->mdev->dp; | ||
385 | s8 db = bootparam->h2c_config_db; | ||
386 | |||
387 | mutex_lock(&mvdev->mdev->mic_mutex); | ||
388 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
389 | mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1); | ||
390 | |||
391 | if (db == -1 || mvdev->dd->type == -1) { | ||
392 | ret = -EIO; | ||
393 | goto exit; | ||
394 | } | ||
395 | |||
396 | if (copy_from_user(mic_vq_configspace(mvdev->dd), | ||
397 | argp, mvdev->dd->config_len)) { | ||
398 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
399 | __func__, __LINE__, -EFAULT); | ||
400 | ret = -EFAULT; | ||
401 | goto exit; | ||
402 | } | ||
403 | mvdev->dc->config_change = MIC_VIRTIO_PARAM_CONFIG_CHANGED; | ||
404 | mvdev->mdev->ops->send_intr(mvdev->mdev, db); | ||
405 | |||
406 | for (i = retry; i--;) { | ||
407 | ret = wait_event_timeout(wake, | ||
408 | mvdev->dc->guest_ack, msecs_to_jiffies(100)); | ||
409 | if (ret) | ||
410 | break; | ||
411 | } | ||
412 | |||
413 | dev_dbg(mic_dev(mvdev), | ||
414 | "%s %d retry: %d\n", __func__, __LINE__, retry); | ||
415 | mvdev->dc->config_change = 0; | ||
416 | mvdev->dc->guest_ack = 0; | ||
417 | exit: | ||
418 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
419 | mutex_unlock(&mvdev->mvr[i].vr_mutex); | ||
420 | mutex_unlock(&mvdev->mdev->mic_mutex); | ||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | static int mic_copy_dp_entry(struct mic_vdev *mvdev, | ||
425 | void __user *argp, | ||
426 | __u8 *type, | ||
427 | struct mic_device_desc **devpage) | ||
428 | { | ||
429 | struct mic_device *mdev = mvdev->mdev; | ||
430 | struct mic_device_desc dd, *dd_config, *devp; | ||
431 | struct mic_vqconfig *vqconfig; | ||
432 | int ret = 0, i; | ||
433 | bool slot_found = false; | ||
434 | |||
435 | if (copy_from_user(&dd, argp, sizeof(dd))) { | ||
436 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
437 | __func__, __LINE__, -EFAULT); | ||
438 | return -EFAULT; | ||
439 | } | ||
440 | |||
441 | if (mic_aligned_desc_size(&dd) > MIC_MAX_DESC_BLK_SIZE | ||
442 | || dd.num_vq > MIC_MAX_VRINGS) { | ||
443 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
444 | __func__, __LINE__, -EINVAL); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
448 | dd_config = kmalloc(mic_desc_size(&dd), GFP_KERNEL); | ||
449 | if (dd_config == NULL) { | ||
450 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
451 | __func__, __LINE__, -ENOMEM); | ||
452 | return -ENOMEM; | ||
453 | } | ||
454 | if (copy_from_user(dd_config, argp, mic_desc_size(&dd))) { | ||
455 | ret = -EFAULT; | ||
456 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
457 | __func__, __LINE__, ret); | ||
458 | goto exit; | ||
459 | } | ||
460 | |||
461 | vqconfig = mic_vq_config(dd_config); | ||
462 | for (i = 0; i < dd.num_vq; i++) { | ||
463 | if (le16_to_cpu(vqconfig[i].num) > MIC_MAX_VRING_ENTRIES) { | ||
464 | ret = -EINVAL; | ||
465 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
466 | __func__, __LINE__, ret); | ||
467 | goto exit; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | /* Find the first free device page entry */ | ||
472 | for (i = mic_aligned_size(struct mic_bootparam); | ||
473 | i < MIC_DP_SIZE - mic_total_desc_size(dd_config); | ||
474 | i += mic_total_desc_size(devp)) { | ||
475 | devp = mdev->dp + i; | ||
476 | if (devp->type == 0 || devp->type == -1) { | ||
477 | slot_found = true; | ||
478 | break; | ||
479 | } | ||
480 | } | ||
481 | if (!slot_found) { | ||
482 | ret = -EINVAL; | ||
483 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
484 | __func__, __LINE__, ret); | ||
485 | goto exit; | ||
486 | } | ||
487 | /* | ||
488 | * Save off the type before doing the memcpy. Type will be set in the | ||
489 | * end after completing all initialization for the new device. | ||
490 | */ | ||
491 | *type = dd_config->type; | ||
492 | dd_config->type = 0; | ||
493 | memcpy(devp, dd_config, mic_desc_size(dd_config)); | ||
494 | |||
495 | *devpage = devp; | ||
496 | exit: | ||
497 | kfree(dd_config); | ||
498 | return ret; | ||
499 | } | ||
500 | |||
501 | static void mic_init_device_ctrl(struct mic_vdev *mvdev, | ||
502 | struct mic_device_desc *devpage) | ||
503 | { | ||
504 | struct mic_device_ctrl *dc; | ||
505 | |||
506 | dc = mvdev->dc = (void *)devpage + mic_aligned_desc_size(devpage); | ||
507 | |||
508 | dc->config_change = 0; | ||
509 | dc->guest_ack = 0; | ||
510 | dc->vdev_reset = 0; | ||
511 | dc->host_ack = 0; | ||
512 | dc->used_address_updated = 0; | ||
513 | dc->c2h_vdev_db = -1; | ||
514 | dc->h2c_vdev_db = -1; | ||
515 | } | ||
516 | |||
517 | int mic_virtio_add_device(struct mic_vdev *mvdev, | ||
518 | void __user *argp) | ||
519 | { | ||
520 | struct mic_device *mdev = mvdev->mdev; | ||
521 | struct mic_device_desc *dd; | ||
522 | struct mic_vqconfig *vqconfig; | ||
523 | int vr_size, i, j, ret; | ||
524 | u8 type; | ||
525 | s8 db; | ||
526 | char irqname[10]; | ||
527 | struct mic_bootparam *bootparam = mdev->dp; | ||
528 | u16 num; | ||
529 | |||
530 | mutex_lock(&mdev->mic_mutex); | ||
531 | |||
532 | ret = mic_copy_dp_entry(mvdev, argp, &type, &dd); | ||
533 | if (ret) { | ||
534 | mutex_unlock(&mdev->mic_mutex); | ||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | mic_init_device_ctrl(mvdev, dd); | ||
539 | |||
540 | mvdev->dd = dd; | ||
541 | mvdev->virtio_id = type; | ||
542 | vqconfig = mic_vq_config(dd); | ||
543 | INIT_WORK(&mvdev->virtio_bh_work, mic_bh_handler); | ||
544 | |||
545 | for (i = 0; i < dd->num_vq; i++) { | ||
546 | struct mic_vringh *mvr = &mvdev->mvr[i]; | ||
547 | struct mic_vring *vr = &mvdev->mvr[i].vring; | ||
548 | num = le16_to_cpu(vqconfig[i].num); | ||
549 | mutex_init(&mvr->vr_mutex); | ||
550 | vr_size = PAGE_ALIGN(vring_size(num, MIC_VIRTIO_RING_ALIGN) + | ||
551 | sizeof(struct _mic_vring_info)); | ||
552 | vr->va = (void *) | ||
553 | __get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
554 | get_order(vr_size)); | ||
555 | if (!vr->va) { | ||
556 | ret = -ENOMEM; | ||
557 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
558 | __func__, __LINE__, ret); | ||
559 | goto err; | ||
560 | } | ||
561 | vr->len = vr_size; | ||
562 | vr->info = vr->va + vring_size(num, MIC_VIRTIO_RING_ALIGN); | ||
563 | vr->info->magic = MIC_MAGIC + mvdev->virtio_id + i; | ||
564 | vqconfig[i].address = mic_map_single(mdev, | ||
565 | vr->va, vr_size); | ||
566 | if (mic_map_error(vqconfig[i].address)) { | ||
567 | free_pages((unsigned long)vr->va, | ||
568 | get_order(vr_size)); | ||
569 | ret = -ENOMEM; | ||
570 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
571 | __func__, __LINE__, ret); | ||
572 | goto err; | ||
573 | } | ||
574 | vqconfig[i].address = cpu_to_le64(vqconfig[i].address); | ||
575 | |||
576 | vring_init(&vr->vr, num, | ||
577 | vr->va, MIC_VIRTIO_RING_ALIGN); | ||
578 | ret = vringh_init_kern(&mvr->vrh, | ||
579 | *(u32 *)mic_vq_features(mvdev->dd), num, false, | ||
580 | vr->vr.desc, vr->vr.avail, vr->vr.used); | ||
581 | if (ret) { | ||
582 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
583 | __func__, __LINE__, ret); | ||
584 | goto err; | ||
585 | } | ||
586 | vringh_kiov_init(&mvr->riov, NULL, 0); | ||
587 | vringh_kiov_init(&mvr->wiov, NULL, 0); | ||
588 | mvr->head = USHRT_MAX; | ||
589 | mvr->mvdev = mvdev; | ||
590 | mvr->vrh.notify = mic_notify; | ||
591 | dev_dbg(mdev->sdev->parent, | ||
592 | "%s %d index %d va %p info %p vr_size 0x%x\n", | ||
593 | __func__, __LINE__, i, vr->va, vr->info, vr_size); | ||
594 | } | ||
595 | |||
596 | snprintf(irqname, sizeof(irqname), | ||
597 | "mic%dvirtio%d", mdev->id, mvdev->virtio_id); | ||
598 | mvdev->virtio_db = mic_next_db(mdev); | ||
599 | mvdev->virtio_cookie = mic_request_irq(mdev, mic_virtio_intr_handler, | ||
600 | irqname, mvdev, mvdev->virtio_db, MIC_INTR_DB); | ||
601 | if (IS_ERR(mvdev->virtio_cookie)) { | ||
602 | ret = PTR_ERR(mvdev->virtio_cookie); | ||
603 | dev_dbg(mdev->sdev->parent, "request irq failed\n"); | ||
604 | goto err; | ||
605 | } | ||
606 | |||
607 | mvdev->dc->c2h_vdev_db = mvdev->virtio_db; | ||
608 | |||
609 | list_add_tail(&mvdev->list, &mdev->vdev_list); | ||
610 | /* | ||
611 | * Order the type update with previous stores. This write barrier | ||
612 | * is paired with the corresponding read barrier before the uncached | ||
613 | * system memory read of the type, on the card while scanning the | ||
614 | * device page. | ||
615 | */ | ||
616 | smp_wmb(); | ||
617 | dd->type = type; | ||
618 | |||
619 | dev_dbg(mdev->sdev->parent, "Added virtio device id %d\n", dd->type); | ||
620 | |||
621 | db = bootparam->h2c_config_db; | ||
622 | if (db != -1) | ||
623 | mdev->ops->send_intr(mdev, db); | ||
624 | mutex_unlock(&mdev->mic_mutex); | ||
625 | return 0; | ||
626 | err: | ||
627 | vqconfig = mic_vq_config(dd); | ||
628 | for (j = 0; j < i; j++) { | ||
629 | struct mic_vringh *mvr = &mvdev->mvr[j]; | ||
630 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[j].address), | ||
631 | mvr->vring.len); | ||
632 | free_pages((unsigned long)mvr->vring.va, | ||
633 | get_order(mvr->vring.len)); | ||
634 | } | ||
635 | mutex_unlock(&mdev->mic_mutex); | ||
636 | return ret; | ||
637 | } | ||
638 | |||
639 | void mic_virtio_del_device(struct mic_vdev *mvdev) | ||
640 | { | ||
641 | struct list_head *pos, *tmp; | ||
642 | struct mic_vdev *tmp_mvdev; | ||
643 | struct mic_device *mdev = mvdev->mdev; | ||
644 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); | ||
645 | int i, ret, retry = 100; | ||
646 | struct mic_vqconfig *vqconfig; | ||
647 | struct mic_bootparam *bootparam = mdev->dp; | ||
648 | s8 db; | ||
649 | |||
650 | mutex_lock(&mdev->mic_mutex); | ||
651 | db = bootparam->h2c_config_db; | ||
652 | if (db == -1) | ||
653 | goto skip_hot_remove; | ||
654 | dev_dbg(mdev->sdev->parent, | ||
655 | "Requesting hot remove id %d\n", mvdev->virtio_id); | ||
656 | mvdev->dc->config_change = MIC_VIRTIO_PARAM_DEV_REMOVE; | ||
657 | mdev->ops->send_intr(mdev, db); | ||
658 | for (i = retry; i--;) { | ||
659 | ret = wait_event_timeout(wake, | ||
660 | mvdev->dc->guest_ack, msecs_to_jiffies(100)); | ||
661 | if (ret) | ||
662 | break; | ||
663 | } | ||
664 | dev_dbg(mdev->sdev->parent, | ||
665 | "Device id %d config_change %d guest_ack %d\n", | ||
666 | mvdev->virtio_id, mvdev->dc->config_change, | ||
667 | mvdev->dc->guest_ack); | ||
668 | mvdev->dc->config_change = 0; | ||
669 | mvdev->dc->guest_ack = 0; | ||
670 | skip_hot_remove: | ||
671 | mic_free_irq(mdev, mvdev->virtio_cookie, mvdev); | ||
672 | flush_work(&mvdev->virtio_bh_work); | ||
673 | vqconfig = mic_vq_config(mvdev->dd); | ||
674 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
675 | struct mic_vringh *mvr = &mvdev->mvr[i]; | ||
676 | vringh_kiov_cleanup(&mvr->riov); | ||
677 | vringh_kiov_cleanup(&mvr->wiov); | ||
678 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), | ||
679 | mvr->vring.len); | ||
680 | free_pages((unsigned long)mvr->vring.va, | ||
681 | get_order(mvr->vring.len)); | ||
682 | } | ||
683 | |||
684 | list_for_each_safe(pos, tmp, &mdev->vdev_list) { | ||
685 | tmp_mvdev = list_entry(pos, struct mic_vdev, list); | ||
686 | if (tmp_mvdev == mvdev) { | ||
687 | list_del(pos); | ||
688 | dev_dbg(mdev->sdev->parent, | ||
689 | "Removing virtio device id %d\n", | ||
690 | mvdev->virtio_id); | ||
691 | break; | ||
692 | } | ||
693 | } | ||
694 | /* | ||
695 | * Order the type update with previous stores. This write barrier | ||
696 | * is paired with the corresponding read barrier before the uncached | ||
697 | * system memory read of the type, on the card while scanning the | ||
698 | * device page. | ||
699 | */ | ||
700 | smp_wmb(); | ||
701 | mvdev->dd->type = -1; | ||
702 | mutex_unlock(&mdev->mic_mutex); | ||
703 | } | ||
diff --git a/drivers/misc/mic/host/mic_virtio.h b/drivers/misc/mic/host/mic_virtio.h new file mode 100644 index 000000000000..184f3c84805b --- /dev/null +++ b/drivers/misc/mic/host/mic_virtio.h | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #ifndef MIC_VIRTIO_H | ||
22 | #define MIC_VIRTIO_H | ||
23 | |||
24 | #include <linux/virtio_config.h> | ||
25 | #include <linux/mic_ioctl.h> | ||
26 | |||
27 | /* | ||
28 | * Note on endianness. | ||
29 | * 1. Host can be both BE or LE | ||
30 | * 2. Guest/card is LE. Host uses le_to_cpu to access desc/avail | ||
31 | * rings and ioreadXX/iowriteXX to access used ring. | ||
32 | * 3. Device page exposed by host to guest contains LE values. Guest | ||
33 | * accesses these using ioreadXX/iowriteXX etc. This way in general we | ||
34 | * obey the virtio spec according to which guest works with native | ||
35 | * endianness and host is aware of guest endianness and does all | ||
36 | * required endianness conversion. | ||
37 | * 4. Data provided from user space to guest (in ADD_DEVICE and | ||
38 | * CONFIG_CHANGE ioctl's) is not interpreted by the driver and should be | ||
39 | * in guest endianness. | ||
40 | */ | ||
41 | |||
42 | /** | ||
43 | * struct mic_vringh - Virtio ring host information. | ||
44 | * | ||
45 | * @vring: The MIC vring used for setting up user space mappings. | ||
46 | * @vrh: The host VRINGH used for accessing the card vrings. | ||
47 | * @riov: The VRINGH read kernel IOV. | ||
48 | * @wiov: The VRINGH write kernel IOV. | ||
49 | * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). | ||
50 | * @vr_mutex: Mutex for synchronizing access to the VRING. | ||
51 | * @mvdev: Back pointer to MIC virtio device for vringh_notify(..). | ||
52 | */ | ||
53 | struct mic_vringh { | ||
54 | struct mic_vring vring; | ||
55 | struct vringh vrh; | ||
56 | struct vringh_kiov riov; | ||
57 | struct vringh_kiov wiov; | ||
58 | u16 head; | ||
59 | struct mutex vr_mutex; | ||
60 | struct mic_vdev *mvdev; | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * struct mic_vdev - Host information for a card Virtio device. | ||
65 | * | ||
66 | * @virtio_id - Virtio device id. | ||
67 | * @waitq - Waitqueue to allow ring3 apps to poll. | ||
68 | * @mdev - Back pointer to host MIC device. | ||
69 | * @poll_wake - Used for waking up threads blocked in poll. | ||
70 | * @out_bytes - Debug stats for number of bytes copied from host to card. | ||
71 | * @in_bytes - Debug stats for number of bytes copied from card to host. | ||
72 | * @mvr - Store per VRING data structures. | ||
73 | * @virtio_bh_work - Work struct used to schedule virtio bottom half handling. | ||
74 | * @dd - Virtio device descriptor. | ||
75 | * @dc - Virtio device control fields. | ||
76 | * @list - List of Virtio devices. | ||
77 | * @virtio_db - The doorbell used by the card to interrupt the host. | ||
78 | * @virtio_cookie - The cookie returned while requesting interrupts. | ||
79 | */ | ||
80 | struct mic_vdev { | ||
81 | int virtio_id; | ||
82 | wait_queue_head_t waitq; | ||
83 | struct mic_device *mdev; | ||
84 | int poll_wake; | ||
85 | unsigned long out_bytes; | ||
86 | unsigned long in_bytes; | ||
87 | struct mic_vringh mvr[MIC_MAX_VRINGS]; | ||
88 | struct work_struct virtio_bh_work; | ||
89 | struct mic_device_desc *dd; | ||
90 | struct mic_device_ctrl *dc; | ||
91 | struct list_head list; | ||
92 | int virtio_db; | ||
93 | struct mic_irq *virtio_cookie; | ||
94 | }; | ||
95 | |||
96 | void mic_virtio_uninit(struct mic_device *mdev); | ||
97 | int mic_virtio_add_device(struct mic_vdev *mvdev, | ||
98 | void __user *argp); | ||
99 | void mic_virtio_del_device(struct mic_vdev *mvdev); | ||
100 | int mic_virtio_config_change(struct mic_vdev *mvdev, | ||
101 | void __user *argp); | ||
102 | int mic_virtio_copy_desc(struct mic_vdev *mvdev, | ||
103 | struct mic_copy_desc *request); | ||
104 | void mic_virtio_reset_devices(struct mic_device *mdev); | ||
105 | void mic_bh_handler(struct work_struct *work); | ||
106 | |||
107 | /* Helper API to obtain the MIC PCIe device */ | ||
108 | static inline struct device *mic_dev(struct mic_vdev *mvdev) | ||
109 | { | ||
110 | return mvdev->mdev->sdev->parent; | ||
111 | } | ||
112 | |||
113 | /* Helper API to check if a virtio device is initialized */ | ||
114 | static inline int mic_vdev_inited(struct mic_vdev *mvdev) | ||
115 | { | ||
116 | /* Device has not been created yet */ | ||
117 | if (!mvdev->dd || !mvdev->dd->type) { | ||
118 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
119 | __func__, __LINE__, -EINVAL); | ||
120 | return -EINVAL; | ||
121 | } | ||
122 | |||
123 | /* Device has been removed/deleted */ | ||
124 | if (mvdev->dd->type == -1) { | ||
125 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
126 | __func__, __LINE__, -ENODEV); | ||
127 | return -ENODEV; | ||
128 | } | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /* Helper API to check if a virtio device is running */ | ||
134 | static inline bool mic_vdevup(struct mic_vdev *mvdev) | ||
135 | { | ||
136 | return !!mvdev->dd->status; | ||
137 | } | ||
138 | #endif | ||
diff --git a/drivers/misc/mic/host/mic_x100.c b/drivers/misc/mic/host/mic_x100.c new file mode 100644 index 000000000000..a12ae5c8844d --- /dev/null +++ b/drivers/misc/mic/host/mic_x100.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/firmware.h> | ||
25 | #include <linux/delay.h> | ||
26 | |||
27 | #include "../common/mic_device.h" | ||
28 | #include "mic_device.h" | ||
29 | #include "mic_x100.h" | ||
30 | #include "mic_smpt.h" | ||
31 | |||
32 | /** | ||
33 | * mic_x100_write_spad - write to the scratchpad register | ||
34 | * @mdev: pointer to mic_device instance | ||
35 | * @idx: index to the scratchpad register, 0 based | ||
36 | * @val: the data value to put into the register | ||
37 | * | ||
38 | * This function allows writing of a 32bit value to the indexed scratchpad | ||
39 | * register. | ||
40 | * | ||
41 | * RETURNS: none. | ||
42 | */ | ||
43 | static void | ||
44 | mic_x100_write_spad(struct mic_device *mdev, unsigned int idx, u32 val) | ||
45 | { | ||
46 | dev_dbg(mdev->sdev->parent, "Writing 0x%x to scratch pad index %d\n", | ||
47 | val, idx); | ||
48 | mic_mmio_write(&mdev->mmio, val, | ||
49 | MIC_X100_SBOX_BASE_ADDRESS + | ||
50 | MIC_X100_SBOX_SPAD0 + idx * 4); | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * mic_x100_read_spad - read from the scratchpad register | ||
55 | * @mdev: pointer to mic_device instance | ||
56 | * @idx: index to scratchpad register, 0 based | ||
57 | * | ||
58 | * This function allows reading of the 32bit scratchpad register. | ||
59 | * | ||
60 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
61 | */ | ||
62 | static u32 | ||
63 | mic_x100_read_spad(struct mic_device *mdev, unsigned int idx) | ||
64 | { | ||
65 | u32 val = mic_mmio_read(&mdev->mmio, | ||
66 | MIC_X100_SBOX_BASE_ADDRESS + | ||
67 | MIC_X100_SBOX_SPAD0 + idx * 4); | ||
68 | |||
69 | dev_dbg(mdev->sdev->parent, | ||
70 | "Reading 0x%x from scratch pad index %d\n", val, idx); | ||
71 | return val; | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * mic_x100_enable_interrupts - Enable interrupts. | ||
76 | * @mdev: pointer to mic_device instance | ||
77 | */ | ||
78 | static void mic_x100_enable_interrupts(struct mic_device *mdev) | ||
79 | { | ||
80 | u32 reg; | ||
81 | struct mic_mw *mw = &mdev->mmio; | ||
82 | u32 sice0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICE0; | ||
83 | u32 siac0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SIAC0; | ||
84 | |||
85 | reg = mic_mmio_read(mw, sice0); | ||
86 | reg |= MIC_X100_SBOX_DBR_BITS(0xf) | MIC_X100_SBOX_DMA_BITS(0xff); | ||
87 | mic_mmio_write(mw, reg, sice0); | ||
88 | |||
89 | /* | ||
90 | * Enable auto-clear when enabling interrupts. Applicable only for | ||
91 | * MSI-x. Legacy and MSI mode cannot have auto-clear enabled. | ||
92 | */ | ||
93 | if (mdev->irq_info.num_vectors > 1) { | ||
94 | reg = mic_mmio_read(mw, siac0); | ||
95 | reg |= MIC_X100_SBOX_DBR_BITS(0xf) | | ||
96 | MIC_X100_SBOX_DMA_BITS(0xff); | ||
97 | mic_mmio_write(mw, reg, siac0); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * mic_x100_disable_interrupts - Disable interrupts. | ||
103 | * @mdev: pointer to mic_device instance | ||
104 | */ | ||
105 | static void mic_x100_disable_interrupts(struct mic_device *mdev) | ||
106 | { | ||
107 | u32 reg; | ||
108 | struct mic_mw *mw = &mdev->mmio; | ||
109 | u32 sice0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICE0; | ||
110 | u32 siac0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SIAC0; | ||
111 | u32 sicc0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICC0; | ||
112 | |||
113 | reg = mic_mmio_read(mw, sice0); | ||
114 | mic_mmio_write(mw, reg, sicc0); | ||
115 | |||
116 | if (mdev->irq_info.num_vectors > 1) { | ||
117 | reg = mic_mmio_read(mw, siac0); | ||
118 | reg &= ~(MIC_X100_SBOX_DBR_BITS(0xf) | | ||
119 | MIC_X100_SBOX_DMA_BITS(0xff)); | ||
120 | mic_mmio_write(mw, reg, siac0); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * mic_x100_send_sbox_intr - Send an MIC_X100_SBOX interrupt to MIC. | ||
126 | * @mdev: pointer to mic_device instance | ||
127 | */ | ||
128 | static void mic_x100_send_sbox_intr(struct mic_device *mdev, | ||
129 | int doorbell) | ||
130 | { | ||
131 | struct mic_mw *mw = &mdev->mmio; | ||
132 | u64 apic_icr_offset = MIC_X100_SBOX_APICICR0 + doorbell * 8; | ||
133 | u32 apicicr_low = mic_mmio_read(mw, | ||
134 | MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); | ||
135 | |||
136 | /* for MIC we need to make sure we "hit" the send_icr bit (13) */ | ||
137 | apicicr_low = (apicicr_low | (1 << 13)); | ||
138 | |||
139 | /* Ensure that the interrupt is ordered w.r.t. previous stores. */ | ||
140 | wmb(); | ||
141 | mic_mmio_write(mw, apicicr_low, | ||
142 | MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); | ||
143 | } | ||
144 | |||
145 | /** | ||
146 | * mic_x100_send_rdmasr_intr - Send an RDMASR interrupt to MIC. | ||
147 | * @mdev: pointer to mic_device instance | ||
148 | */ | ||
149 | static void mic_x100_send_rdmasr_intr(struct mic_device *mdev, | ||
150 | int doorbell) | ||
151 | { | ||
152 | int rdmasr_offset = MIC_X100_SBOX_RDMASR0 + (doorbell << 2); | ||
153 | /* Ensure that the interrupt is ordered w.r.t. previous stores. */ | ||
154 | wmb(); | ||
155 | mic_mmio_write(&mdev->mmio, 0, | ||
156 | MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * __mic_x100_send_intr - Send interrupt to MIC. | ||
161 | * @mdev: pointer to mic_device instance | ||
162 | * @doorbell: doorbell number. | ||
163 | */ | ||
164 | static void mic_x100_send_intr(struct mic_device *mdev, int doorbell) | ||
165 | { | ||
166 | int rdmasr_db; | ||
167 | if (doorbell < MIC_X100_NUM_SBOX_IRQ) { | ||
168 | mic_x100_send_sbox_intr(mdev, doorbell); | ||
169 | } else { | ||
170 | rdmasr_db = doorbell - MIC_X100_NUM_SBOX_IRQ + | ||
171 | MIC_X100_RDMASR_IRQ_BASE; | ||
172 | mic_x100_send_rdmasr_intr(mdev, rdmasr_db); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * mic_ack_interrupt - Device specific interrupt handling. | ||
178 | * @mdev: pointer to mic_device instance | ||
179 | * | ||
180 | * Returns: bitmask of doorbell events triggered. | ||
181 | */ | ||
182 | static u32 mic_x100_ack_interrupt(struct mic_device *mdev) | ||
183 | { | ||
184 | u32 reg = 0; | ||
185 | struct mic_mw *mw = &mdev->mmio; | ||
186 | u32 sicr0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICR0; | ||
187 | |||
188 | /* Clear pending bit array. */ | ||
189 | if (MIC_A0_STEP == mdev->stepping) | ||
190 | mic_mmio_write(mw, 1, MIC_X100_SBOX_BASE_ADDRESS + | ||
191 | MIC_X100_SBOX_MSIXPBACR); | ||
192 | |||
193 | if (mdev->irq_info.num_vectors <= 1) { | ||
194 | reg = mic_mmio_read(mw, sicr0); | ||
195 | |||
196 | if (unlikely(!reg)) | ||
197 | goto done; | ||
198 | |||
199 | mic_mmio_write(mw, reg, sicr0); | ||
200 | } | ||
201 | |||
202 | if (mdev->stepping >= MIC_B0_STEP) | ||
203 | mdev->intr_ops->enable_interrupts(mdev); | ||
204 | done: | ||
205 | return reg; | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * mic_x100_hw_intr_init - Initialize h/w specific interrupt | ||
210 | * information. | ||
211 | * @mdev: pointer to mic_device instance | ||
212 | */ | ||
213 | static void mic_x100_hw_intr_init(struct mic_device *mdev) | ||
214 | { | ||
215 | mdev->intr_info = (struct mic_intr_info *) mic_x100_intr_init; | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * mic_x100_read_msi_to_src_map - read from the MSI mapping registers | ||
220 | * @mdev: pointer to mic_device instance | ||
221 | * @idx: index to the mapping register, 0 based | ||
222 | * | ||
223 | * This function allows reading of the 32bit MSI mapping register. | ||
224 | * | ||
225 | * RETURNS: The value in the register. | ||
226 | */ | ||
227 | static u32 | ||
228 | mic_x100_read_msi_to_src_map(struct mic_device *mdev, int idx) | ||
229 | { | ||
230 | return mic_mmio_read(&mdev->mmio, | ||
231 | MIC_X100_SBOX_BASE_ADDRESS + | ||
232 | MIC_X100_SBOX_MXAR0 + idx * 4); | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * mic_x100_program_msi_to_src_map - program the MSI mapping registers | ||
237 | * @mdev: pointer to mic_device instance | ||
238 | * @idx: index to the mapping register, 0 based | ||
239 | * @offset: The bit offset in the register that needs to be updated. | ||
240 | * @set: boolean specifying if the bit in the specified offset needs | ||
241 | * to be set or cleared. | ||
242 | * | ||
243 | * RETURNS: None. | ||
244 | */ | ||
245 | static void | ||
246 | mic_x100_program_msi_to_src_map(struct mic_device *mdev, | ||
247 | int idx, int offset, bool set) | ||
248 | { | ||
249 | unsigned long reg; | ||
250 | struct mic_mw *mw = &mdev->mmio; | ||
251 | u32 mxar = MIC_X100_SBOX_BASE_ADDRESS + | ||
252 | MIC_X100_SBOX_MXAR0 + idx * 4; | ||
253 | |||
254 | reg = mic_mmio_read(mw, mxar); | ||
255 | if (set) | ||
256 | __set_bit(offset, ®); | ||
257 | else | ||
258 | __clear_bit(offset, ®); | ||
259 | mic_mmio_write(mw, reg, mxar); | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * mic_x100_reset_fw_ready - Reset Firmware ready status field. | ||
264 | * @mdev: pointer to mic_device instance | ||
265 | */ | ||
266 | static void mic_x100_reset_fw_ready(struct mic_device *mdev) | ||
267 | { | ||
268 | mdev->ops->write_spad(mdev, MIC_X100_DOWNLOAD_INFO, 0); | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * mic_x100_is_fw_ready - Check if firmware is ready. | ||
273 | * @mdev: pointer to mic_device instance | ||
274 | */ | ||
275 | static bool mic_x100_is_fw_ready(struct mic_device *mdev) | ||
276 | { | ||
277 | u32 scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO); | ||
278 | return MIC_X100_SPAD2_DOWNLOAD_STATUS(scratch2) ? true : false; | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * mic_x100_get_apic_id - Get bootstrap APIC ID. | ||
283 | * @mdev: pointer to mic_device instance | ||
284 | */ | ||
285 | static u32 mic_x100_get_apic_id(struct mic_device *mdev) | ||
286 | { | ||
287 | u32 scratch2 = 0; | ||
288 | |||
289 | scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO); | ||
290 | return MIC_X100_SPAD2_APIC_ID(scratch2); | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * mic_x100_send_firmware_intr - Send an interrupt to the firmware on MIC. | ||
295 | * @mdev: pointer to mic_device instance | ||
296 | */ | ||
297 | static void mic_x100_send_firmware_intr(struct mic_device *mdev) | ||
298 | { | ||
299 | u32 apicicr_low; | ||
300 | u64 apic_icr_offset = MIC_X100_SBOX_APICICR7; | ||
301 | int vector = MIC_X100_BSP_INTERRUPT_VECTOR; | ||
302 | struct mic_mw *mw = &mdev->mmio; | ||
303 | |||
304 | /* | ||
305 | * For MIC we need to make sure we "hit" | ||
306 | * the send_icr bit (13). | ||
307 | */ | ||
308 | apicicr_low = (vector | (1 << 13)); | ||
309 | |||
310 | mic_mmio_write(mw, mic_x100_get_apic_id(mdev), | ||
311 | MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset + 4); | ||
312 | |||
313 | /* Ensure that the interrupt is ordered w.r.t. previous stores. */ | ||
314 | wmb(); | ||
315 | mic_mmio_write(mw, apicicr_low, | ||
316 | MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * mic_x100_hw_reset - Reset the MIC device. | ||
321 | * @mdev: pointer to mic_device instance | ||
322 | */ | ||
323 | static void mic_x100_hw_reset(struct mic_device *mdev) | ||
324 | { | ||
325 | u32 reset_reg; | ||
326 | u32 rgcr = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_RGCR; | ||
327 | struct mic_mw *mw = &mdev->mmio; | ||
328 | |||
329 | /* Ensure that the reset is ordered w.r.t. previous loads and stores */ | ||
330 | mb(); | ||
331 | /* Trigger reset */ | ||
332 | reset_reg = mic_mmio_read(mw, rgcr); | ||
333 | reset_reg |= 0x1; | ||
334 | mic_mmio_write(mw, reset_reg, rgcr); | ||
335 | /* | ||
336 | * It seems we really want to delay at least 1 second | ||
337 | * after touching reset to prevent a lot of problems. | ||
338 | */ | ||
339 | msleep(1000); | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * mic_x100_load_command_line - Load command line to MIC. | ||
344 | * @mdev: pointer to mic_device instance | ||
345 | * @fw: the firmware image | ||
346 | * | ||
347 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
348 | */ | ||
349 | static int | ||
350 | mic_x100_load_command_line(struct mic_device *mdev, const struct firmware *fw) | ||
351 | { | ||
352 | u32 len = 0; | ||
353 | u32 boot_mem; | ||
354 | char *buf; | ||
355 | void __iomem *cmd_line_va = mdev->aper.va + mdev->bootaddr + fw->size; | ||
356 | #define CMDLINE_SIZE 2048 | ||
357 | |||
358 | boot_mem = mdev->aper.len >> 20; | ||
359 | buf = kzalloc(CMDLINE_SIZE, GFP_KERNEL); | ||
360 | if (!buf) { | ||
361 | dev_err(mdev->sdev->parent, | ||
362 | "%s %d allocation failed\n", __func__, __LINE__); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | len += snprintf(buf, CMDLINE_SIZE - len, | ||
366 | " mem=%dM", boot_mem); | ||
367 | if (mdev->cmdline) | ||
368 | snprintf(buf + len, CMDLINE_SIZE - len, | ||
369 | " %s", mdev->cmdline); | ||
370 | memcpy_toio(cmd_line_va, buf, strlen(buf) + 1); | ||
371 | kfree(buf); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | /** | ||
376 | * mic_x100_load_ramdisk - Load ramdisk to MIC. | ||
377 | * @mdev: pointer to mic_device instance | ||
378 | * | ||
379 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
380 | */ | ||
381 | static int | ||
382 | mic_x100_load_ramdisk(struct mic_device *mdev) | ||
383 | { | ||
384 | const struct firmware *fw; | ||
385 | int rc; | ||
386 | struct boot_params __iomem *bp = mdev->aper.va + mdev->bootaddr; | ||
387 | |||
388 | rc = request_firmware(&fw, | ||
389 | mdev->ramdisk, mdev->sdev->parent); | ||
390 | if (rc < 0) { | ||
391 | dev_err(mdev->sdev->parent, | ||
392 | "ramdisk request_firmware failed: %d %s\n", | ||
393 | rc, mdev->ramdisk); | ||
394 | goto error; | ||
395 | } | ||
396 | /* | ||
397 | * Typically the bootaddr for card OS is 64M | ||
398 | * so copy over the ramdisk @ 128M. | ||
399 | */ | ||
400 | memcpy_toio(mdev->aper.va + (mdev->bootaddr << 1), | ||
401 | fw->data, fw->size); | ||
402 | iowrite32(cpu_to_le32(mdev->bootaddr << 1), &bp->hdr.ramdisk_image); | ||
403 | iowrite32(cpu_to_le32(fw->size), &bp->hdr.ramdisk_size); | ||
404 | release_firmware(fw); | ||
405 | error: | ||
406 | return rc; | ||
407 | } | ||
408 | |||
409 | /** | ||
410 | * mic_x100_get_boot_addr - Get MIC boot address. | ||
411 | * @mdev: pointer to mic_device instance | ||
412 | * | ||
413 | * This function is called during firmware load to determine | ||
414 | * the address at which the OS should be downloaded in card | ||
415 | * memory i.e. GDDR. | ||
416 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
417 | */ | ||
418 | static int | ||
419 | mic_x100_get_boot_addr(struct mic_device *mdev) | ||
420 | { | ||
421 | u32 scratch2, boot_addr; | ||
422 | int rc = 0; | ||
423 | |||
424 | scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO); | ||
425 | boot_addr = MIC_X100_SPAD2_DOWNLOAD_ADDR(scratch2); | ||
426 | dev_dbg(mdev->sdev->parent, "%s %d boot_addr 0x%x\n", | ||
427 | __func__, __LINE__, boot_addr); | ||
428 | if (boot_addr > (1 << 31)) { | ||
429 | dev_err(mdev->sdev->parent, | ||
430 | "incorrect bootaddr 0x%x\n", | ||
431 | boot_addr); | ||
432 | rc = -EINVAL; | ||
433 | goto error; | ||
434 | } | ||
435 | mdev->bootaddr = boot_addr; | ||
436 | error: | ||
437 | return rc; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * mic_x100_load_firmware - Load firmware to MIC. | ||
442 | * @mdev: pointer to mic_device instance | ||
443 | * @buf: buffer containing boot string including firmware/ramdisk path. | ||
444 | * | ||
445 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
446 | */ | ||
447 | static int | ||
448 | mic_x100_load_firmware(struct mic_device *mdev, const char *buf) | ||
449 | { | ||
450 | int rc; | ||
451 | const struct firmware *fw; | ||
452 | |||
453 | rc = mic_x100_get_boot_addr(mdev); | ||
454 | if (rc) | ||
455 | goto error; | ||
456 | /* load OS */ | ||
457 | rc = request_firmware(&fw, mdev->firmware, mdev->sdev->parent); | ||
458 | if (rc < 0) { | ||
459 | dev_err(mdev->sdev->parent, | ||
460 | "ramdisk request_firmware failed: %d %s\n", | ||
461 | rc, mdev->firmware); | ||
462 | goto error; | ||
463 | } | ||
464 | if (mdev->bootaddr > mdev->aper.len - fw->size) { | ||
465 | rc = -EINVAL; | ||
466 | dev_err(mdev->sdev->parent, "%s %d rc %d bootaddr 0x%x\n", | ||
467 | __func__, __LINE__, rc, mdev->bootaddr); | ||
468 | release_firmware(fw); | ||
469 | goto error; | ||
470 | } | ||
471 | memcpy_toio(mdev->aper.va + mdev->bootaddr, fw->data, fw->size); | ||
472 | mdev->ops->write_spad(mdev, MIC_X100_FW_SIZE, fw->size); | ||
473 | if (!strcmp(mdev->bootmode, "elf")) | ||
474 | goto done; | ||
475 | /* load command line */ | ||
476 | rc = mic_x100_load_command_line(mdev, fw); | ||
477 | if (rc) { | ||
478 | dev_err(mdev->sdev->parent, "%s %d rc %d\n", | ||
479 | __func__, __LINE__, rc); | ||
480 | goto error; | ||
481 | } | ||
482 | release_firmware(fw); | ||
483 | /* load ramdisk */ | ||
484 | if (mdev->ramdisk) | ||
485 | rc = mic_x100_load_ramdisk(mdev); | ||
486 | error: | ||
487 | dev_dbg(mdev->sdev->parent, "%s %d rc %d\n", | ||
488 | __func__, __LINE__, rc); | ||
489 | done: | ||
490 | return rc; | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * mic_x100_get_postcode - Get postcode status from firmware. | ||
495 | * @mdev: pointer to mic_device instance | ||
496 | * | ||
497 | * RETURNS: postcode. | ||
498 | */ | ||
499 | static u32 mic_x100_get_postcode(struct mic_device *mdev) | ||
500 | { | ||
501 | return mic_mmio_read(&mdev->mmio, MIC_X100_POSTCODE); | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * mic_x100_smpt_set - Update an SMPT entry with a DMA address. | ||
506 | * @mdev: pointer to mic_device instance | ||
507 | * | ||
508 | * RETURNS: none. | ||
509 | */ | ||
510 | static void | ||
511 | mic_x100_smpt_set(struct mic_device *mdev, dma_addr_t dma_addr, u8 index) | ||
512 | { | ||
513 | #define SNOOP_ON (0 << 0) | ||
514 | #define SNOOP_OFF (1 << 0) | ||
515 | /* | ||
516 | * Sbox Smpt Reg Bits: | ||
517 | * Bits 31:2 Host address | ||
518 | * Bits 1 RSVD | ||
519 | * Bits 0 No snoop | ||
520 | */ | ||
521 | #define BUILD_SMPT(NO_SNOOP, HOST_ADDR) \ | ||
522 | (u32)(((HOST_ADDR) << 2) | ((NO_SNOOP) & 0x01)) | ||
523 | |||
524 | uint32_t smpt_reg_val = BUILD_SMPT(SNOOP_ON, | ||
525 | dma_addr >> mdev->smpt->info.page_shift); | ||
526 | mic_mmio_write(&mdev->mmio, smpt_reg_val, | ||
527 | MIC_X100_SBOX_BASE_ADDRESS + | ||
528 | MIC_X100_SBOX_SMPT00 + (4 * index)); | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * mic_x100_smpt_hw_init - Initialize SMPT X100 specific fields. | ||
533 | * @mdev: pointer to mic_device instance | ||
534 | * | ||
535 | * RETURNS: none. | ||
536 | */ | ||
537 | static void mic_x100_smpt_hw_init(struct mic_device *mdev) | ||
538 | { | ||
539 | struct mic_smpt_hw_info *info = &mdev->smpt->info; | ||
540 | |||
541 | info->num_reg = 32; | ||
542 | info->page_shift = 34; | ||
543 | info->page_size = (1ULL << info->page_shift); | ||
544 | info->base = 0x8000000000ULL; | ||
545 | } | ||
546 | |||
547 | struct mic_smpt_ops mic_x100_smpt_ops = { | ||
548 | .init = mic_x100_smpt_hw_init, | ||
549 | .set = mic_x100_smpt_set, | ||
550 | }; | ||
551 | |||
552 | struct mic_hw_ops mic_x100_ops = { | ||
553 | .aper_bar = MIC_X100_APER_BAR, | ||
554 | .mmio_bar = MIC_X100_MMIO_BAR, | ||
555 | .read_spad = mic_x100_read_spad, | ||
556 | .write_spad = mic_x100_write_spad, | ||
557 | .send_intr = mic_x100_send_intr, | ||
558 | .ack_interrupt = mic_x100_ack_interrupt, | ||
559 | .reset = mic_x100_hw_reset, | ||
560 | .reset_fw_ready = mic_x100_reset_fw_ready, | ||
561 | .is_fw_ready = mic_x100_is_fw_ready, | ||
562 | .send_firmware_intr = mic_x100_send_firmware_intr, | ||
563 | .load_mic_fw = mic_x100_load_firmware, | ||
564 | .get_postcode = mic_x100_get_postcode, | ||
565 | }; | ||
566 | |||
567 | struct mic_hw_intr_ops mic_x100_intr_ops = { | ||
568 | .intr_init = mic_x100_hw_intr_init, | ||
569 | .enable_interrupts = mic_x100_enable_interrupts, | ||
570 | .disable_interrupts = mic_x100_disable_interrupts, | ||
571 | .program_msi_to_src_map = mic_x100_program_msi_to_src_map, | ||
572 | .read_msi_to_src_map = mic_x100_read_msi_to_src_map, | ||
573 | }; | ||
diff --git a/drivers/misc/mic/host/mic_x100.h b/drivers/misc/mic/host/mic_x100.h new file mode 100644 index 000000000000..8b7daa182e54 --- /dev/null +++ b/drivers/misc/mic/host/mic_x100.h | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Intel MIC Platform Software Stack (MPSS) | ||
3 | * | ||
4 | * Copyright(c) 2013 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License, version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * The full GNU General Public License is included in this distribution in | ||
16 | * the file called "COPYING". | ||
17 | * | ||
18 | * Intel MIC Host driver. | ||
19 | * | ||
20 | */ | ||
21 | #ifndef _MIC_X100_HW_H_ | ||
22 | #define _MIC_X100_HW_H_ | ||
23 | |||
24 | #define MIC_X100_PCI_DEVICE_2250 0x2250 | ||
25 | #define MIC_X100_PCI_DEVICE_2251 0x2251 | ||
26 | #define MIC_X100_PCI_DEVICE_2252 0x2252 | ||
27 | #define MIC_X100_PCI_DEVICE_2253 0x2253 | ||
28 | #define MIC_X100_PCI_DEVICE_2254 0x2254 | ||
29 | #define MIC_X100_PCI_DEVICE_2255 0x2255 | ||
30 | #define MIC_X100_PCI_DEVICE_2256 0x2256 | ||
31 | #define MIC_X100_PCI_DEVICE_2257 0x2257 | ||
32 | #define MIC_X100_PCI_DEVICE_2258 0x2258 | ||
33 | #define MIC_X100_PCI_DEVICE_2259 0x2259 | ||
34 | #define MIC_X100_PCI_DEVICE_225a 0x225a | ||
35 | #define MIC_X100_PCI_DEVICE_225b 0x225b | ||
36 | #define MIC_X100_PCI_DEVICE_225c 0x225c | ||
37 | #define MIC_X100_PCI_DEVICE_225d 0x225d | ||
38 | #define MIC_X100_PCI_DEVICE_225e 0x225e | ||
39 | |||
40 | #define MIC_X100_APER_BAR 0 | ||
41 | #define MIC_X100_MMIO_BAR 4 | ||
42 | |||
43 | #define MIC_X100_SBOX_BASE_ADDRESS 0x00010000 | ||
44 | #define MIC_X100_SBOX_SPAD0 0x0000AB20 | ||
45 | #define MIC_X100_SBOX_SICR0_DBR(x) ((x) & 0xf) | ||
46 | #define MIC_X100_SBOX_SICR0_DMA(x) (((x) >> 8) & 0xff) | ||
47 | #define MIC_X100_SBOX_SICE0_DBR(x) ((x) & 0xf) | ||
48 | #define MIC_X100_SBOX_DBR_BITS(x) ((x) & 0xf) | ||
49 | #define MIC_X100_SBOX_SICE0_DMA(x) (((x) >> 8) & 0xff) | ||
50 | #define MIC_X100_SBOX_DMA_BITS(x) (((x) & 0xff) << 8) | ||
51 | |||
52 | #define MIC_X100_SBOX_APICICR0 0x0000A9D0 | ||
53 | #define MIC_X100_SBOX_SICR0 0x00009004 | ||
54 | #define MIC_X100_SBOX_SICE0 0x0000900C | ||
55 | #define MIC_X100_SBOX_SICC0 0x00009010 | ||
56 | #define MIC_X100_SBOX_SIAC0 0x00009014 | ||
57 | #define MIC_X100_SBOX_MSIXPBACR 0x00009084 | ||
58 | #define MIC_X100_SBOX_MXAR0 0x00009044 | ||
59 | #define MIC_X100_SBOX_SMPT00 0x00003100 | ||
60 | #define MIC_X100_SBOX_RDMASR0 0x0000B180 | ||
61 | |||
62 | #define MIC_X100_DOORBELL_IDX_START 0 | ||
63 | #define MIC_X100_NUM_DOORBELL 4 | ||
64 | #define MIC_X100_DMA_IDX_START 8 | ||
65 | #define MIC_X100_NUM_DMA 8 | ||
66 | #define MIC_X100_ERR_IDX_START 30 | ||
67 | #define MIC_X100_NUM_ERR 1 | ||
68 | |||
69 | #define MIC_X100_NUM_SBOX_IRQ 8 | ||
70 | #define MIC_X100_NUM_RDMASR_IRQ 8 | ||
71 | #define MIC_X100_RDMASR_IRQ_BASE 17 | ||
72 | #define MIC_X100_SPAD2_DOWNLOAD_STATUS(x) ((x) & 0x1) | ||
73 | #define MIC_X100_SPAD2_APIC_ID(x) (((x) >> 1) & 0x1ff) | ||
74 | #define MIC_X100_SPAD2_DOWNLOAD_ADDR(x) ((x) & 0xfffff000) | ||
75 | #define MIC_X100_SBOX_APICICR7 0x0000AA08 | ||
76 | #define MIC_X100_SBOX_RGCR 0x00004010 | ||
77 | #define MIC_X100_SBOX_SDBIC0 0x0000CC90 | ||
78 | #define MIC_X100_DOWNLOAD_INFO 2 | ||
79 | #define MIC_X100_FW_SIZE 5 | ||
80 | #define MIC_X100_POSTCODE 0x242c | ||
81 | |||
82 | static const u16 mic_x100_intr_init[] = { | ||
83 | MIC_X100_DOORBELL_IDX_START, | ||
84 | MIC_X100_DMA_IDX_START, | ||
85 | MIC_X100_ERR_IDX_START, | ||
86 | MIC_X100_NUM_DOORBELL, | ||
87 | MIC_X100_NUM_DMA, | ||
88 | MIC_X100_NUM_ERR, | ||
89 | }; | ||
90 | |||
91 | /* Host->Card(bootstrap) Interrupt Vector */ | ||
92 | #define MIC_X100_BSP_INTERRUPT_VECTOR 229 | ||
93 | |||
94 | extern struct mic_hw_ops mic_x100_ops; | ||
95 | extern struct mic_smpt_ops mic_x100_smpt_ops; | ||
96 | extern struct mic_hw_intr_ops mic_x100_intr_ops; | ||
97 | |||
98 | #endif | ||
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index f84ff0c06035..eda38cbe8530 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c | |||
@@ -892,7 +892,6 @@ static void pti_pci_remove(struct pci_dev *pdev) | |||
892 | } | 892 | } |
893 | 893 | ||
894 | iounmap(drv_data->pti_ioaddr); | 894 | iounmap(drv_data->pti_ioaddr); |
895 | pci_set_drvdata(pdev, NULL); | ||
896 | kfree(drv_data); | 895 | kfree(drv_data); |
897 | pci_release_region(pdev, 1); | 896 | pci_release_region(pdev, 1); |
898 | pci_disable_device(pdev); | 897 | pci_disable_device(pdev); |
diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c index 9b237221bc4e..83da711ce9f1 100644 --- a/drivers/misc/ti_dac7512.c +++ b/drivers/misc/ti_dac7512.c | |||
@@ -22,9 +22,7 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/spi/spi.h> | 24 | #include <linux/spi/spi.h> |
25 | 25 | #include <linux/of.h> | |
26 | #define DAC7512_DRV_NAME "dac7512" | ||
27 | #define DRIVER_VERSION "1.0" | ||
28 | 26 | ||
29 | static ssize_t dac7512_store_val(struct device *dev, | 27 | static ssize_t dac7512_store_val(struct device *dev, |
30 | struct device_attribute *attr, | 28 | struct device_attribute *attr, |
@@ -75,13 +73,29 @@ static int dac7512_remove(struct spi_device *spi) | |||
75 | return 0; | 73 | return 0; |
76 | } | 74 | } |
77 | 75 | ||
76 | static const struct spi_device_id dac7512_id_table[] = { | ||
77 | { "dac7512", 0 }, | ||
78 | { } | ||
79 | }; | ||
80 | MODULE_DEVICE_TABLE(spi, dac7512_id_table); | ||
81 | |||
82 | #ifdef CONFIG_OF | ||
83 | static const struct of_device_id dac7512_of_match[] = { | ||
84 | { .compatible = "ti,dac7512", }, | ||
85 | { } | ||
86 | }; | ||
87 | MODULE_DEVICE_TABLE(of, dac7512_of_match); | ||
88 | #endif | ||
89 | |||
78 | static struct spi_driver dac7512_driver = { | 90 | static struct spi_driver dac7512_driver = { |
79 | .driver = { | 91 | .driver = { |
80 | .name = DAC7512_DRV_NAME, | 92 | .name = "dac7512", |
81 | .owner = THIS_MODULE, | 93 | .owner = THIS_MODULE, |
94 | .of_match_table = of_match_ptr(dac7512_of_match), | ||
82 | }, | 95 | }, |
83 | .probe = dac7512_probe, | 96 | .probe = dac7512_probe, |
84 | .remove = dac7512_remove, | 97 | .remove = dac7512_remove, |
98 | .id_table = dac7512_id_table, | ||
85 | }; | 99 | }; |
86 | 100 | ||
87 | module_spi_driver(dac7512_driver); | 101 | module_spi_driver(dac7512_driver); |
@@ -89,4 +103,3 @@ module_spi_driver(dac7512_driver); | |||
89 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 103 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); |
90 | MODULE_DESCRIPTION("DAC7512 16-bit DAC"); | 104 | MODULE_DESCRIPTION("DAC7512 16-bit DAC"); |
91 | MODULE_LICENSE("GPL v2"); | 105 | MODULE_LICENSE("GPL v2"); |
92 | MODULE_VERSION(DRIVER_VERSION); | ||
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index f8d6654391e5..ae282a100429 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c | |||
@@ -378,7 +378,6 @@ err_out_irq: | |||
378 | err_out_unmap: | 378 | err_out_unmap: |
379 | iounmap(fm->addr); | 379 | iounmap(fm->addr); |
380 | err_out_free: | 380 | err_out_free: |
381 | pci_set_drvdata(dev, NULL); | ||
382 | tifm_free_adapter(fm); | 381 | tifm_free_adapter(fm); |
383 | err_out_int: | 382 | err_out_int: |
384 | pci_intx(dev, 0); | 383 | pci_intx(dev, 0); |
@@ -405,8 +404,6 @@ static void tifm_7xx1_remove(struct pci_dev *dev) | |||
405 | for (cnt = 0; cnt < fm->num_sockets; cnt++) | 404 | for (cnt = 0; cnt < fm->num_sockets; cnt++) |
406 | tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt)); | 405 | tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt)); |
407 | 406 | ||
408 | pci_set_drvdata(dev, NULL); | ||
409 | |||
410 | iounmap(fm->addr); | 407 | iounmap(fm->addr); |
411 | pci_intx(dev, 0); | 408 | pci_intx(dev, 0); |
412 | pci_release_regions(dev); | 409 | pci_release_regions(dev); |
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index b3a2b763ecf2..c98b03b99353 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c | |||
@@ -649,7 +649,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, | |||
649 | return 0; | 649 | return 0; |
650 | 650 | ||
651 | err_free_irq: | 651 | err_free_irq: |
652 | free_irq(vmci_dev->irq, &vmci_dev); | 652 | free_irq(vmci_dev->irq, vmci_dev); |
653 | tasklet_kill(&vmci_dev->datagram_tasklet); | 653 | tasklet_kill(&vmci_dev->datagram_tasklet); |
654 | tasklet_kill(&vmci_dev->bm_tasklet); | 654 | tasklet_kill(&vmci_dev->bm_tasklet); |
655 | 655 | ||
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index a4c16ee5c718..622dd6fe7347 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c | |||
@@ -777,15 +777,4 @@ static struct pci_driver pd6729_pci_driver = { | |||
777 | .remove = pd6729_pci_remove, | 777 | .remove = pd6729_pci_remove, |
778 | }; | 778 | }; |
779 | 779 | ||
780 | static int pd6729_module_init(void) | 780 | module_pci_driver(pd6729_pci_driver); |
781 | { | ||
782 | return pci_register_driver(&pd6729_pci_driver); | ||
783 | } | ||
784 | |||
785 | static void pd6729_module_exit(void) | ||
786 | { | ||
787 | pci_unregister_driver(&pd6729_pci_driver); | ||
788 | } | ||
789 | |||
790 | module_init(pd6729_module_init); | ||
791 | module_exit(pd6729_module_exit); | ||
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 6b4ff099fb13..dc18a3a5e010 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c | |||
@@ -1439,20 +1439,6 @@ static struct pci_driver yenta_cardbus_driver = { | |||
1439 | .driver.pm = YENTA_PM_OPS, | 1439 | .driver.pm = YENTA_PM_OPS, |
1440 | }; | 1440 | }; |
1441 | 1441 | ||
1442 | 1442 | module_pci_driver(yenta_cardbus_driver); | |
1443 | static int __init yenta_socket_init(void) | ||
1444 | { | ||
1445 | return pci_register_driver(¥ta_cardbus_driver); | ||
1446 | } | ||
1447 | |||
1448 | |||
1449 | static void __exit yenta_socket_exit(void) | ||
1450 | { | ||
1451 | pci_unregister_driver(¥ta_cardbus_driver); | ||
1452 | } | ||
1453 | |||
1454 | |||
1455 | module_init(yenta_socket_init); | ||
1456 | module_exit(yenta_socket_exit); | ||
1457 | 1443 | ||
1458 | MODULE_LICENSE("GPL"); | 1444 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index ba475632c5fa..11d4e0a52579 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -796,10 +796,9 @@ int __uio_register_device(struct module *owner, | |||
796 | 796 | ||
797 | info->uio_dev = NULL; | 797 | info->uio_dev = NULL; |
798 | 798 | ||
799 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); | 799 | idev = devm_kzalloc(parent, sizeof(*idev), GFP_KERNEL); |
800 | if (!idev) { | 800 | if (!idev) { |
801 | ret = -ENOMEM; | 801 | return -ENOMEM; |
802 | goto err_kzalloc; | ||
803 | } | 802 | } |
804 | 803 | ||
805 | idev->owner = owner; | 804 | idev->owner = owner; |
@@ -809,7 +808,7 @@ int __uio_register_device(struct module *owner, | |||
809 | 808 | ||
810 | ret = uio_get_minor(idev); | 809 | ret = uio_get_minor(idev); |
811 | if (ret) | 810 | if (ret) |
812 | goto err_get_minor; | 811 | return ret; |
813 | 812 | ||
814 | idev->dev = device_create(&uio_class, parent, | 813 | idev->dev = device_create(&uio_class, parent, |
815 | MKDEV(uio_major, idev->minor), idev, | 814 | MKDEV(uio_major, idev->minor), idev, |
@@ -827,7 +826,7 @@ int __uio_register_device(struct module *owner, | |||
827 | info->uio_dev = idev; | 826 | info->uio_dev = idev; |
828 | 827 | ||
829 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { | 828 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { |
830 | ret = request_irq(info->irq, uio_interrupt, | 829 | ret = devm_request_irq(parent, info->irq, uio_interrupt, |
831 | info->irq_flags, info->name, idev); | 830 | info->irq_flags, info->name, idev); |
832 | if (ret) | 831 | if (ret) |
833 | goto err_request_irq; | 832 | goto err_request_irq; |
@@ -841,9 +840,6 @@ err_uio_dev_add_attributes: | |||
841 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); | 840 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
842 | err_device_create: | 841 | err_device_create: |
843 | uio_free_minor(idev); | 842 | uio_free_minor(idev); |
844 | err_get_minor: | ||
845 | kfree(idev); | ||
846 | err_kzalloc: | ||
847 | return ret; | 843 | return ret; |
848 | } | 844 | } |
849 | EXPORT_SYMBOL_GPL(__uio_register_device); | 845 | EXPORT_SYMBOL_GPL(__uio_register_device); |
@@ -864,13 +860,9 @@ void uio_unregister_device(struct uio_info *info) | |||
864 | 860 | ||
865 | uio_free_minor(idev); | 861 | uio_free_minor(idev); |
866 | 862 | ||
867 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) | ||
868 | free_irq(info->irq, idev); | ||
869 | |||
870 | uio_dev_del_attributes(idev); | 863 | uio_dev_del_attributes(idev); |
871 | 864 | ||
872 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); | 865 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
873 | kfree(idev); | ||
874 | 866 | ||
875 | return; | 867 | return; |
876 | } | 868 | } |
diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c index f3611c2d83b6..1549fab633c6 100644 --- a/drivers/uio/uio_aec.c +++ b/drivers/uio/uio_aec.c | |||
@@ -147,7 +147,6 @@ static void remove(struct pci_dev *pdev) | |||
147 | uio_unregister_device(info); | 147 | uio_unregister_device(info); |
148 | pci_release_regions(pdev); | 148 | pci_release_regions(pdev); |
149 | pci_disable_device(pdev); | 149 | pci_disable_device(pdev); |
150 | pci_set_drvdata(pdev, NULL); | ||
151 | iounmap(info->priv); | 150 | iounmap(info->priv); |
152 | 151 | ||
153 | kfree(info); | 152 | kfree(info); |
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index 22cdf385ab33..30f533ce3758 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c | |||
@@ -106,7 +106,6 @@ static void hilscher_pci_remove(struct pci_dev *dev) | |||
106 | uio_unregister_device(info); | 106 | uio_unregister_device(info); |
107 | pci_release_regions(dev); | 107 | pci_release_regions(dev); |
108 | pci_disable_device(dev); | 108 | pci_disable_device(dev); |
109 | pci_set_drvdata(dev, NULL); | ||
110 | iounmap(info->mem[0].internal_addr); | 109 | iounmap(info->mem[0].internal_addr); |
111 | 110 | ||
112 | kfree (info); | 111 | kfree (info); |
diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c index a1768b2f4493..f764adbfe036 100644 --- a/drivers/uio/uio_mf624.c +++ b/drivers/uio/uio_mf624.c | |||
@@ -42,7 +42,7 @@ | |||
42 | 42 | ||
43 | enum mf624_interrupt_source {ADC, CTR4, ALL}; | 43 | enum mf624_interrupt_source {ADC, CTR4, ALL}; |
44 | 44 | ||
45 | void mf624_disable_interrupt(enum mf624_interrupt_source source, | 45 | static void mf624_disable_interrupt(enum mf624_interrupt_source source, |
46 | struct uio_info *info) | 46 | struct uio_info *info) |
47 | { | 47 | { |
48 | void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR; | 48 | void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR; |
@@ -70,7 +70,7 @@ void mf624_disable_interrupt(enum mf624_interrupt_source source, | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | void mf624_enable_interrupt(enum mf624_interrupt_source source, | 73 | static void mf624_enable_interrupt(enum mf624_interrupt_source source, |
74 | struct uio_info *info) | 74 | struct uio_info *info) |
75 | { | 75 | { |
76 | void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR; | 76 | void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR; |
@@ -220,7 +220,6 @@ static void mf624_pci_remove(struct pci_dev *dev) | |||
220 | uio_unregister_device(info); | 220 | uio_unregister_device(info); |
221 | pci_release_regions(dev); | 221 | pci_release_regions(dev); |
222 | pci_disable_device(dev); | 222 | pci_disable_device(dev); |
223 | pci_set_drvdata(dev, NULL); | ||
224 | 223 | ||
225 | iounmap(info->mem[0].internal_addr); | 224 | iounmap(info->mem[0].internal_addr); |
226 | iounmap(info->mem[1].internal_addr); | 225 | iounmap(info->mem[1].internal_addr); |
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index 28a766b9e198..4c345db8b016 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c | |||
@@ -127,7 +127,6 @@ static void netx_pci_remove(struct pci_dev *dev) | |||
127 | uio_unregister_device(info); | 127 | uio_unregister_device(info); |
128 | pci_release_regions(dev); | 128 | pci_release_regions(dev); |
129 | pci_disable_device(dev); | 129 | pci_disable_device(dev); |
130 | pci_set_drvdata(dev, NULL); | ||
131 | iounmap(info->mem[0].internal_addr); | 130 | iounmap(info->mem[0].internal_addr); |
132 | 131 | ||
133 | kfree(info); | 132 | kfree(info); |
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 90ff17a0202f..76669313e9a7 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c | |||
@@ -112,11 +112,11 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) | |||
112 | 112 | ||
113 | if (pdev->dev.of_node) { | 113 | if (pdev->dev.of_node) { |
114 | /* alloc uioinfo for one device */ | 114 | /* alloc uioinfo for one device */ |
115 | uioinfo = kzalloc(sizeof(*uioinfo), GFP_KERNEL); | 115 | uioinfo = devm_kzalloc(&pdev->dev, sizeof(*uioinfo), |
116 | GFP_KERNEL); | ||
116 | if (!uioinfo) { | 117 | if (!uioinfo) { |
117 | ret = -ENOMEM; | ||
118 | dev_err(&pdev->dev, "unable to kmalloc\n"); | 118 | dev_err(&pdev->dev, "unable to kmalloc\n"); |
119 | return ret; | 119 | return -ENOMEM; |
120 | } | 120 | } |
121 | uioinfo->name = pdev->dev.of_node->name; | 121 | uioinfo->name = pdev->dev.of_node->name; |
122 | uioinfo->version = "devicetree"; | 122 | uioinfo->version = "devicetree"; |
@@ -125,20 +125,19 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) | |||
125 | 125 | ||
126 | if (!uioinfo || !uioinfo->name || !uioinfo->version) { | 126 | if (!uioinfo || !uioinfo->name || !uioinfo->version) { |
127 | dev_err(&pdev->dev, "missing platform_data\n"); | 127 | dev_err(&pdev->dev, "missing platform_data\n"); |
128 | goto bad0; | 128 | return ret; |
129 | } | 129 | } |
130 | 130 | ||
131 | if (uioinfo->handler || uioinfo->irqcontrol || | 131 | if (uioinfo->handler || uioinfo->irqcontrol || |
132 | uioinfo->irq_flags & IRQF_SHARED) { | 132 | uioinfo->irq_flags & IRQF_SHARED) { |
133 | dev_err(&pdev->dev, "interrupt configuration error\n"); | 133 | dev_err(&pdev->dev, "interrupt configuration error\n"); |
134 | goto bad0; | 134 | return ret; |
135 | } | 135 | } |
136 | 136 | ||
137 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 137 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
138 | if (!priv) { | 138 | if (!priv) { |
139 | ret = -ENOMEM; | ||
140 | dev_err(&pdev->dev, "unable to kmalloc\n"); | 139 | dev_err(&pdev->dev, "unable to kmalloc\n"); |
141 | goto bad0; | 140 | return -ENOMEM; |
142 | } | 141 | } |
143 | 142 | ||
144 | priv->uioinfo = uioinfo; | 143 | priv->uioinfo = uioinfo; |
@@ -153,7 +152,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) | |||
153 | uioinfo->irq = UIO_IRQ_NONE; | 152 | uioinfo->irq = UIO_IRQ_NONE; |
154 | else if (ret < 0) { | 153 | else if (ret < 0) { |
155 | dev_err(&pdev->dev, "failed to get IRQ\n"); | 154 | dev_err(&pdev->dev, "failed to get IRQ\n"); |
156 | goto bad1; | 155 | return ret; |
157 | } | 156 | } |
158 | } | 157 | } |
159 | 158 | ||
@@ -209,20 +208,12 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) | |||
209 | ret = uio_register_device(&pdev->dev, priv->uioinfo); | 208 | ret = uio_register_device(&pdev->dev, priv->uioinfo); |
210 | if (ret) { | 209 | if (ret) { |
211 | dev_err(&pdev->dev, "unable to register uio device\n"); | 210 | dev_err(&pdev->dev, "unable to register uio device\n"); |
212 | goto bad2; | 211 | pm_runtime_disable(&pdev->dev); |
212 | return ret; | ||
213 | } | 213 | } |
214 | 214 | ||
215 | platform_set_drvdata(pdev, priv); | 215 | platform_set_drvdata(pdev, priv); |
216 | return 0; | 216 | return 0; |
217 | bad2: | ||
218 | pm_runtime_disable(&pdev->dev); | ||
219 | bad1: | ||
220 | kfree(priv); | ||
221 | bad0: | ||
222 | /* kfree uioinfo for OF */ | ||
223 | if (pdev->dev.of_node) | ||
224 | kfree(uioinfo); | ||
225 | return ret; | ||
226 | } | 217 | } |
227 | 218 | ||
228 | static int uio_pdrv_genirq_remove(struct platform_device *pdev) | 219 | static int uio_pdrv_genirq_remove(struct platform_device *pdev) |
@@ -235,11 +226,6 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev) | |||
235 | priv->uioinfo->handler = NULL; | 226 | priv->uioinfo->handler = NULL; |
236 | priv->uioinfo->irqcontrol = NULL; | 227 | priv->uioinfo->irqcontrol = NULL; |
237 | 228 | ||
238 | /* kfree uioinfo for OF */ | ||
239 | if (pdev->dev.of_node) | ||
240 | kfree(priv->uioinfo); | ||
241 | |||
242 | kfree(priv); | ||
243 | return 0; | 229 | return 0; |
244 | } | 230 | } |
245 | 231 | ||
diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c index 541983217085..9cfdfcafa262 100644 --- a/drivers/uio/uio_sercos3.c +++ b/drivers/uio/uio_sercos3.c | |||
@@ -188,7 +188,6 @@ static void sercos3_pci_remove(struct pci_dev *dev) | |||
188 | uio_unregister_device(info); | 188 | uio_unregister_device(info); |
189 | pci_release_regions(dev); | 189 | pci_release_regions(dev); |
190 | pci_disable_device(dev); | 190 | pci_disable_device(dev); |
191 | pci_set_drvdata(dev, NULL); | ||
192 | for (i = 0; i < 5; i++) { | 191 | for (i = 0; i < 5; i++) { |
193 | if (info->mem[i].internal_addr) | 192 | if (info->mem[i].internal_addr) |
194 | iounmap(info->mem[i].internal_addr); | 193 | iounmap(info->mem[i].internal_addr); |